Borg hands & hand whitelisting (#38668)

* Borg hands & hand whitelisting

* yaml linted

* yaml linted (x2)

* yaml linted (x3)

* my storage tests so pass

* no need for SetCount

* ok new stuff you can get fixed too

* oops

* staque

* what if we addressed feedback

* my place so holder

* what if we addresesd feedback

* what if i did it correctly

* terminating or deleted
This commit is contained in:
pathetic meowmeow
2025-08-12 18:21:42 -04:00
committed by GitHub
parent 8b76ace136
commit 39cb27fe21
34 changed files with 732 additions and 667 deletions

View File

@@ -28,22 +28,8 @@ namespace Content.Client.Stack
base.SetCount(uid, amount, component);
if (component.Lingering &&
TryComp<SpriteComponent>(uid, out var sprite))
{
// tint the stack gray and make it transparent if it's lingering.
var color = component.Count == 0 && component.Lingering
? Color.DarkGray.WithAlpha(0.65f)
: Color.White;
for (var i = 0; i < sprite.AllLayers.Count(); i++)
{
_sprite.LayerSetColor((uid, sprite), i, color);
}
}
// TODO PREDICT ENTITY DELETION: This should really just be a normal entity deletion call.
if (component.Count <= 0 && !component.Lingering)
if (component.Count <= 0)
{
Xform.DetachEntity(uid, Transform(uid));
return;

View File

@@ -1,9 +1,11 @@
using System.Numerics;
using Content.Client.Cooldown;
using Content.Client.UserInterface.Systems.Inventory.Controls;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.Controls
{
@@ -20,6 +22,7 @@ namespace Content.Client.UserInterface.Controls
public CooldownGraphic CooldownDisplay { get; }
private SpriteView SpriteView { get; }
private EntityPrototypeView ProtoView { get; }
public EntityUid? Entity => SpriteView.Entity;
@@ -141,6 +144,13 @@ namespace Content.Client.UserInterface.Controls
SetSize = new Vector2(DefaultButtonSize, DefaultButtonSize),
OverrideDirection = Direction.South
});
AddChild(ProtoView = new EntityPrototypeView
{
Visible = false,
Scale = new Vector2(2, 2),
SetSize = new Vector2(DefaultButtonSize, DefaultButtonSize),
OverrideDirection = Direction.South
});
AddChild(HoverSpriteView = new SpriteView
{
@@ -209,12 +219,35 @@ namespace Content.Client.UserInterface.Controls
HoverSpriteView.SetEntity(null);
}
/// <summary>
/// Causes the control to display a placeholder prototype, optionally faded
/// </summary>
public void SetEntity(EntityUid? ent)
{
SpriteView.SetEntity(ent);
SpriteView.Visible = true;
ProtoView.Visible = false;
UpdateButtonTexture();
}
/// <summary>
/// Causes the control to display a placeholder prototype, optionally faded
/// </summary>
public void SetPrototype(EntProtoId? proto, bool fade)
{
ProtoView.SetPrototype(proto);
SpriteView.Visible = false;
ProtoView.Visible = true;
UpdateButtonTexture();
if (ProtoView.Entity is not { } ent || !fade)
return;
var sprites = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>();
sprites.SetColor((ent.Owner, ent.Comp1), Color.DarkGray.WithAlpha(0.65f));
}
private void UpdateButtonTexture()
{
var fullTexture = Theme.ResolveTextureOrNull(_fullButtonTexturePath);

View File

@@ -12,6 +12,7 @@ using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
using Robust.Shared.Input;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -73,7 +74,8 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
{
if (entity.Owner != _player.LocalEntity)
return;
AddHand(name, location);
if (_handsSystem.TryGetHand((entity.Owner, entity.Comp), name, out var hand))
AddHand(name, hand.Value);
}
private void OnRemoveHand(Entity<HandsComponent> entity, string name)
@@ -139,7 +141,7 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
_playerHandsComponent = handsComp;
foreach (var (name, hand) in handsComp.Comp.Hands)
{
var handButton = AddHand(name, hand.Location);
var handButton = AddHand(name, hand);
if (_handsSystem.TryGetHeldItem(handsComp.AsNullable(), name, out var held) &&
_entities.TryGetComponent(held, out VirtualItemComponent? virt))
@@ -147,11 +149,25 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
handButton.SetEntity(virt.BlockingEntity);
handButton.Blocked = true;
}
else
else if (held != null)
{
handButton.SetEntity(held);
handButton.Blocked = false;
}
else
{
if (hand.EmptyRepresentative is { } representative)
{
// placeholder, view it
SetRepresentative(handButton, representative);
}
else
{
// otherwise empty
handButton.SetEntity(null);
}
handButton.Blocked = false;
}
}
if (handsComp.Comp.ActiveHandId == null)
@@ -159,6 +175,11 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
SetActiveHand(handsComp.Comp.ActiveHandId);
}
private void SetRepresentative(HandButton handButton, EntProtoId prototype)
{
handButton.SetPrototype(prototype, true);
}
private void HandBlocked(string handName)
{
if (!_handLookup.TryGetValue(handName, out var hand))
@@ -203,7 +224,12 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
hand.Blocked = false;
}
UpdateHandStatus(hand, entity);
if (_playerHandsComponent != null &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand((playerEntity, _playerHandsComponent), name, out var handData))
{
UpdateHandStatus(hand, entity, handData);
}
}
private void OnItemRemoved(string name, EntityUid entity)
@@ -212,8 +238,19 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (hand == null)
return;
if (_playerHandsComponent != null &&
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand((playerEntity, _playerHandsComponent), name, out var handData))
{
UpdateHandStatus(hand, null, handData);
if (handData?.EmptyRepresentative is { } representative)
{
SetRepresentative(hand, representative);
return;
}
}
hand.SetEntity(null);
UpdateHandStatus(hand, null);
}
private HandsContainer GetFirstAvailableContainer()
@@ -276,13 +313,13 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
if (foldedLocation == HandUILocation.Left)
{
_statusHandLeft = handControl;
HandsGui.UpdatePanelEntityLeft(heldEnt);
HandsGui.UpdatePanelEntityLeft(heldEnt, hand.Value);
}
else
{
// Middle or right
_statusHandRight = handControl;
HandsGui.UpdatePanelEntityRight(heldEnt);
HandsGui.UpdatePanelEntityRight(heldEnt, hand.Value);
}
HandsGui.SetHighlightHand(foldedLocation);
@@ -295,9 +332,9 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
return handControl;
}
private HandButton AddHand(string handName, HandLocation location)
private HandButton AddHand(string handName, Hand hand)
{
var button = new HandButton(handName, location);
var button = new HandButton(handName, hand.Location);
button.StoragePressed += StorageActivate;
button.Pressed += HandPressed;
@@ -313,10 +350,16 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
GetFirstAvailableContainer().AddButton(button);
}
if (hand.EmptyRepresentative is { } representative)
{
SetRepresentative(button, representative);
}
UpdateHandStatus(button, null, hand);
// If we don't have a status for this hand type yet, set it.
// This means we have status filled by default in most scenarios,
// otherwise the user'd need to switch hands to "activate" the hands the first time.
if (location.GetUILocation() == HandUILocation.Left)
if (hand.Location.GetUILocation() == HandUILocation.Left)
_statusHandLeft ??= button;
else
_statusHandRight ??= button;
@@ -480,12 +523,12 @@ public sealed class HandsUIController : UIController, IOnStateEntered<GameplaySt
}
}
private void UpdateHandStatus(HandButton hand, EntityUid? entity)
private void UpdateHandStatus(HandButton hand, EntityUid? entity, Hand? handData)
{
if (hand == _statusHandLeft)
HandsGui?.UpdatePanelEntityLeft(entity);
HandsGui?.UpdatePanelEntityLeft(entity, handData);
if (hand == _statusHandRight)
HandsGui?.UpdatePanelEntityRight(entity);
HandsGui?.UpdatePanelEntityRight(entity, handData);
}
}

View File

@@ -19,14 +19,14 @@ public sealed partial class HotbarGui : UIWidget
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Begin);
}
public void UpdatePanelEntityLeft(EntityUid? entity)
public void UpdatePanelEntityLeft(EntityUid? entity, Hand? hand)
{
StatusPanelLeft.Update(entity);
StatusPanelLeft.Update(entity, hand);
}
public void UpdatePanelEntityRight(EntityUid? entity)
public void UpdatePanelEntityRight(EntityUid? entity, Hand? hand)
{
StatusPanelRight.Update(entity);
StatusPanelRight.Update(entity, hand);
}
public void SetHighlightHand(HandUILocation? hand)

View File

@@ -17,6 +17,7 @@ public sealed partial class ItemStatusPanel : Control
[Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables] private EntityUid? _entity;
[ViewVariables] private Hand? _hand;
// Tracked so we can re-run SetSide() if the theme changes.
private HandUILocation _side;
@@ -101,29 +102,45 @@ public sealed partial class ItemStatusPanel : Control
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateItemName();
UpdateItemName(_hand);
}
public void Update(EntityUid? entity)
public void Update(EntityUid? entity, Hand? hand)
{
ItemNameLabel.Visible = entity != null;
NoItemLabel.Visible = entity == null;
if (entity == _entity && hand == _hand)
return;
_hand = hand;
if (entity == null)
{
ItemNameLabel.Text = "";
ClearOldStatus();
_entity = null;
if (hand?.EmptyLabel is { } label)
{
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
ItemNameLabel.Text = Loc.GetString(label);
}
else
{
ItemNameLabel.Visible = false;
NoItemLabel.Visible = true;
ItemNameLabel.Text = "";
}
return;
}
if (entity != _entity)
{
ItemNameLabel.Visible = true;
NoItemLabel.Visible = false;
_entity = entity.Value;
BuildNewEntityStatus();
UpdateItemName();
}
UpdateItemName(hand);
}
public void UpdateHighlight(bool highlight)
@@ -131,14 +148,14 @@ public sealed partial class ItemStatusPanel : Control
HighlightPanel.Visible = highlight;
}
private void UpdateItemName()
private void UpdateItemName(Hand? hand)
{
if (_entity == null)
return;
if (!_entityManager.TryGetComponent<MetaDataComponent>(_entity, out var meta) || meta.Deleted)
{
Update(null);
Update(null, hand);
return;
}

View File

@@ -276,8 +276,8 @@ namespace Content.Server.Construction
if(!insertStep.EntityValid(insert, EntityManager, Factory))
return HandleResult.False;
// Unremovable items can't be inserted, unless they are a lingering stack
if(HasComp<UnremoveableComponent>(insert) && (!TryComp<StackComponent>(insert, out var comp) || !comp.Lingering))
// Unremovable items can't be inserted
if(HasComp<UnremoveableComponent>(insert))
return HandleResult.False;
// If we're only testing whether this step would be handled by the given event, then we're done.

View File

@@ -52,7 +52,7 @@ public sealed partial class BorgSystem
private void OnProvideItemStartup(EntityUid uid, ItemBorgModuleComponent component, ComponentStartup args)
{
component.ProvidedContainer = Container.EnsureContainer<Container>(uid, component.ProvidedContainerId);
Container.EnsureContainer<Container>(uid, component.HoldingContainer);
}
private void OnSelectableInstalled(EntityUid uid, SelectableBorgModuleComponent component, ref BorgModuleInstalledEvent args)
@@ -187,43 +187,43 @@ public sealed partial class BorgSystem
if (!TryComp<HandsComponent>(chassis, out var hands))
return;
var xform = Transform(chassis);
foreach (var itemProto in component.Items)
{
EntityUid item;
if (!_container.TryGetContainer(uid, component.HoldingContainer, out var container))
return;
if (!component.ItemsCreated)
var xform = Transform(chassis);
for (var i = 0; i < component.Hands.Count; i++)
{
var hand = component.Hands[i];
var handId = $"{uid}-hand-{i}";
_hands.AddHand((chassis, hands), handId, hand.Hand);
EntityUid? item = null;
if (component.StoredItems is not null)
{
if (component.StoredItems.TryGetValue(handId, out var storedItem))
{
item = storedItem;
_container.Remove(storedItem, container, force: true);
}
}
else if (hand.Item is { } itemProto)
{
item = Spawn(itemProto, xform.Coordinates);
}
else
if (item is { } pickUp)
{
item = component.ProvidedContainer.ContainedEntities
.FirstOrDefault(ent => Prototype(ent)?.ID == itemProto.Id);
if (!item.IsValid())
_hands.DoPickup(chassis, handId, pickUp, hands);
if (!hand.ForceRemovable && hand.Hand.Whitelist == null && hand.Hand.Blacklist == null)
{
Log.Debug($"no items found: {component.ProvidedContainer.ContainedEntities.Count}");
continue;
EnsureComp<UnremoveableComponent>(pickUp);
}
}
}
_container.Remove(item, component.ProvidedContainer, force: true);
}
if (!item.IsValid())
{
Log.Debug("no valid item");
continue;
}
var handId = $"{uid}-item{component.HandCounter}";
component.HandCounter++;
_hands.AddHand((chassis, hands), handId, HandLocation.Middle);
_hands.DoPickup(chassis, handId, item, hands);
EnsureComp<UnremoveableComponent>(item);
component.ProvidedItems.Add(handId, item);
}
component.ItemsCreated = true;
Dirty(uid, component);
}
private void RemoveProvidedItems(EntityUid chassis, EntityUid uid, BorgChassisComponent? chassisComponent = null, ItemBorgModuleComponent? component = null)
@@ -234,27 +234,33 @@ public sealed partial class BorgSystem
if (!TryComp<HandsComponent>(chassis, out var hands))
return;
if (TerminatingOrDeleted(uid))
{
foreach (var (hand, item) in component.ProvidedItems)
{
QueueDel(item);
_hands.RemoveHand(chassis, hand);
}
component.ProvidedItems.Clear();
if (!_container.TryGetContainer(uid, component.HoldingContainer, out var container))
return;
if (TerminatingOrDeleted(uid))
return;
component.StoredItems ??= new();
for (var i = 0; i < component.Hands.Count; i++)
{
var handId = $"{uid}-hand-{i}";
if (_hands.TryGetHeldItem(chassis, handId, out var held))
{
RemComp<UnremoveableComponent>(held.Value);
_container.Insert(held.Value, container);
component.StoredItems[handId] = held.Value;
}
else
{
component.StoredItems.Remove(handId);
}
foreach (var (handId, item) in component.ProvidedItems)
{
if (LifeStage(item) <= EntityLifeStage.MapInitialized)
{
RemComp<UnremoveableComponent>(item);
_container.Insert(item, component.ProvidedContainer);
}
_hands.RemoveHand(chassis, handId);
}
component.ProvidedItems.Clear();
Dirty(uid, component);
}
/// <summary>
@@ -286,8 +292,8 @@ public sealed partial class BorgSystem
if (!TryComp<ItemBorgModuleComponent>(containedModuleUid, out var containedItemModuleComp))
continue;
if (containedItemModuleComp.Items.Count == itemModuleComp.Items.Count &&
containedItemModuleComp.Items.All(itemModuleComp.Items.Contains))
if (containedItemModuleComp.Hands.Count == itemModuleComp.Hands.Count &&
containedItemModuleComp.Hands.All(itemModuleComp.Hands.Contains))
{
if (user != null)
Popup.PopupEntity(Loc.GetString("borg-module-duplicate"), uid, user.Value);

View File

@@ -33,7 +33,7 @@ namespace Content.Server.Stack
base.SetCount(uid, amount, component);
// Queue delete stack if count reaches zero.
if (component.Count <= 0 && !component.Lingering)
if (component.Count <= 0)
QueueDel(uid);
}

View File

@@ -33,6 +33,12 @@ public sealed partial class MachineBoardComponent : Component
public EntProtoId Prototype;
}
/// <summary>
/// Marker component for any item that's machine board-like without necessarily being a MachineBoardComponent
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class CircuitboardComponent : Component;
[DataDefinition, Serializable]
public partial struct GenericPartInfo
{

View File

@@ -1,6 +1,8 @@
using Content.Shared.DisplacementMap;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Whitelist;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Hands.Components;
@@ -106,16 +108,45 @@ public sealed partial class HandsComponent : Component
public partial record struct Hand
{
[DataField]
public HandLocation Location = HandLocation.Right;
public HandLocation Location = HandLocation.Middle;
/// <summary>
/// The label to be displayed for this hand when it does not contain an entity
/// </summary>
[DataField]
public LocId? EmptyLabel;
/// <summary>
/// The prototype ID of a "representative" entity prototype for what this hand could hold, used in the UI.
/// It is not map-initted.
/// </summary>
[DataField]
public EntProtoId? EmptyRepresentative;
/// <summary>
/// What this hand is allowed to hold
/// </summary>
[DataField]
public EntityWhitelist? Whitelist;
/// <summary>
/// What this hand is not allowed to hold
/// </summary>
[DataField]
public EntityWhitelist? Blacklist;
public Hand()
{
}
public Hand(HandLocation location)
public Hand(HandLocation location, LocId? emptyLabel = null, EntProtoId? emptyRepresentative = null, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null)
{
Location = location;
EmptyLabel = emptyLabel;
EmptyRepresentative = emptyRepresentative;
Whitelist = whitelist;
Blacklist = blacklist;
}
}

View File

@@ -185,6 +185,9 @@ public abstract partial class SharedHandsSystem
if (checkActionBlocker && !_actionBlocker.CanPickup(uid, entity))
return false;
if (!CheckWhitelists((uid, handsComp), handId, entity))
return false;
if (ContainerSystem.TryGetContainingContainer((entity, null, null), out var container))
{
if (!ContainerSystem.CanRemove(entity, container))

View File

@@ -0,0 +1,15 @@
using Content.Shared.Hands.Components;
using Content.Shared.Whitelist;
namespace Content.Shared.Hands.EntitySystems;
public abstract partial class SharedHandsSystem
{
private bool CheckWhitelists(Entity<HandsComponent?> ent, string handId, EntityUid toTest)
{
if (!TryGetHand(ent, handId, out var hand))
return false;
return _entityWhitelist.CheckBoth(toTest, hand.Value.Blacklist, hand.Value.Whitelist);
}
}

View File

@@ -7,8 +7,10 @@ using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Inventory.VirtualItem;
using Content.Shared.Storage.EntitySystems;
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared.Hands.EntitySystems;
@@ -23,6 +25,7 @@ public abstract partial class SharedHandsSystem
[Dependency] private readonly SharedStorageSystem _storage = default!;
[Dependency] protected readonly SharedTransformSystem TransformSystem = default!;
[Dependency] private readonly SharedVirtualItemSystem _virtualSystem = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
public event Action<Entity<HandsComponent>, string, HandLocation>? OnPlayerAddHand;
public event Action<Entity<HandsComponent>, string>? OnPlayerRemoveHand;
@@ -66,9 +69,9 @@ public abstract partial class SharedHandsSystem
/// <summary>
/// Adds a hand with the given container id and supplied location to the specified entity.
/// </summary>
public void AddHand(Entity<HandsComponent?> ent, string handName, HandLocation handLocation)
public void AddHand(Entity<HandsComponent?> ent, string handName, HandLocation handLocation, LocId? emptyLabel = null, EntProtoId? emptyRepresentative = null, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null)
{
AddHand(ent, handName, new Hand(handLocation));
AddHand(ent, handName, new Hand(handLocation, emptyLabel, emptyRepresentative, whitelist, blacklist));
}
/// <summary>

View File

@@ -1,6 +1,8 @@
using Robust.Shared.Containers;
using Content.Shared.Hands.Components;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Silicons.Borgs.Components;
@@ -11,40 +13,40 @@ namespace Content.Shared.Silicons.Borgs.Components;
public sealed partial class ItemBorgModuleComponent : Component
{
/// <summary>
/// The items that are provided.
/// The hands that are provided.
/// </summary>
[DataField(required: true)]
public List<EntProtoId> Items = new();
public List<BorgHand> Hands = new();
/// <summary>
/// The entities from <see cref="Items"/> that were spawned.
/// The items stored within the hands. Null until the first time items are stored.
/// </summary>
[DataField("providedItems")]
public SortedDictionary<string, EntityUid> ProvidedItems = new();
[DataField]
public Dictionary<string, EntityUid>? StoredItems;
/// <summary>
/// A counter that ensures a unique
/// An ID for the container where items are stored when not in use.
/// </summary>
[DataField("handCounter")]
public int HandCounter;
/// <summary>
/// Whether or not the items have been created and stored in <see cref="ProvidedContainer"/>
/// </summary>
[DataField("itemsCrated")]
public bool ItemsCreated;
/// <summary>
/// A container where provided items are stored when not being used.
/// This is helpful as it means that items retain state.
/// </summary>
[ViewVariables]
public Container ProvidedContainer = default!;
/// <summary>
/// An ID for the container where provided items are stored when not used.
/// </summary>
[DataField("providedContainerId")]
public string ProvidedContainerId = "provided_container";
[DataField]
public string HoldingContainer = "holding_container";
}
[DataDefinition, Serializable, NetSerializable]
public partial record struct BorgHand
{
[DataField]
public EntProtoId? Item;
[DataField]
public Hand Hand = new();
[DataField]
public bool ForceRemovable = false;
public BorgHand(EntProtoId? item, Hand hand, bool forceRemovable = false)
{
Item = item;
Hand = hand;
ForceRemovable = forceRemovable;
}
}

View File

@@ -352,10 +352,6 @@ namespace Content.Shared.Stacks
private void OnStackStarted(EntityUid uid, StackComponent component, ComponentStartup args)
{
// on client, lingering stacks that start at 0 need to be darkened
// on server this does nothing
SetCount(uid, component.Count, component);
if (!TryComp(uid, out AppearanceComponent? appearance))
return;
@@ -366,7 +362,7 @@ namespace Content.Shared.Stacks
private void OnStackGetState(EntityUid uid, StackComponent component, ref ComponentGetState args)
{
args.State = new StackComponentState(component.Count, component.MaxCountOverride, component.Lingering);
args.State = new StackComponentState(component.Count, component.MaxCountOverride);
}
private void OnStackHandleState(EntityUid uid, StackComponent component, ref ComponentHandleState args)
@@ -375,7 +371,6 @@ namespace Content.Shared.Stacks
return;
component.MaxCountOverride = cast.MaxCount;
component.Lingering = cast.Lingering;
// This will change the count and call events.
SetCount(uid, cast.Count, component);
}
@@ -428,7 +423,7 @@ namespace Content.Shared.Stacks
return;
// We haven't eaten the whole stack yet or are unable to eat it completely.
if (eaten.Comp.Count > 0 || eaten.Comp.Lingering)
if (eaten.Comp.Count > 0)
{
args.Refresh = true;
return;

View File

@@ -34,13 +34,6 @@ namespace Content.Shared.Stacks
[ViewVariables(VVAccess.ReadOnly)]
public bool Unlimited { get; set; }
/// <summary>
/// Lingering stacks will remain present even when there are no items.
/// Instead, they will become transparent.
/// </summary>
[DataField("lingering"), ViewVariables(VVAccess.ReadWrite)]
public bool Lingering;
[DataField("throwIndividually"), ViewVariables(VVAccess.ReadWrite)]
public bool ThrowIndividually { get; set; } = false;
@@ -93,13 +86,10 @@ namespace Content.Shared.Stacks
public int Count { get; }
public int? MaxCount { get; }
public bool Lingering;
public StackComponentState(int count, int? maxCount, bool lingering)
public StackComponentState(int count, int? maxCount)
{
Count = count;
MaxCount = maxCount;
Lingering = lingering;
}
}

View File

@@ -0,0 +1,12 @@
borg-slot-cables-empty = Cables
borg-slot-construction-empty = Construction materials
borg-slot-circuitboards-empty = Circuitboards
borg-slot-flatpacks-empty = Flatpacks
borg-slot-tiles-empty = Floor tiles
borg-slot-topicals-empty = Topicals
borg-slot-small-containers-empty = Small containers
borg-slot-chemical-containers-empty = Chemical containers
borg-slot-documents-empty = Books and papers
borg-slot-soap-empty = Soap
borg-slot-instruments-empty = Instruments
borg-slot-beakers-empty = Beakers

View File

@@ -18,4 +18,5 @@
Glass: 230
chemicalComposition:
Silicon: 20
- type: Circuitboard

View File

@@ -17,6 +17,7 @@
Glass: 230
chemicalComposition:
Silicon: 20
- type: Circuitboard
- type: entity
parent: BaseComputerCircuitboard

View File

@@ -17,3 +17,4 @@
Glass: 200
chemicalComposition:
Silicon: 20
- type: Circuitboard

View File

@@ -15,6 +15,7 @@
- type: Tag
tags:
- Sheet
- ConstructionMaterial
- type: Material
- type: Damageable
damageContainer: Inorganic
@@ -108,15 +109,6 @@
stackType: Glass
count: 1
- type: entity
parent: SheetGlass
id: SheetGlassLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: SheetGlassBase
id: SheetRGlass
@@ -197,15 +189,6 @@
Quantity: 0.5
canReact: false
- type: entity
parent: SheetRGlass
id: SheetRGlassLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: SheetGlassBase
id: SheetPGlass
@@ -336,15 +319,6 @@
stackType: ReinforcedPlasmaGlass
count: 1
- type: entity
parent: SheetRPGlass
id: SheetRPGlassLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: SheetGlassBase
id: SheetUGlass

View File

@@ -15,6 +15,7 @@
tags:
- Sheet
- Metal
- ConstructionMaterial
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic
@@ -94,15 +95,6 @@
stackType: Steel
count: 1
- type: entity
parent: SheetSteel
id: SheetSteelLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: SheetMetalBase
id: SheetBrass
@@ -229,12 +221,3 @@
- type: Stack
stackType: Plasteel
count: 1
- type: entity
parent: SheetPlasteel
id: SheetPlasteelLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0

View File

@@ -12,6 +12,7 @@
- type: Tag
tags:
- Sheet
- ConstructionMaterial
- type: Damageable
damageContainer: Inorganic
- type: Destructible
@@ -110,6 +111,7 @@
- type: Tag
tags:
- Sheet
- ConstructionMaterial
- type: entity
parent: SheetPlasma
@@ -132,16 +134,6 @@
- type: Stack
count: 1
- type: entity
parent: SheetPlasma
id: SheetPlasmaLingering0
name: plasma
suffix: 0, Lingering
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: SheetOtherBase
id: SheetPlastic
@@ -152,6 +144,7 @@
tags:
- Plastic
- Sheet
- ConstructionMaterial
- type: Material
- type: PhysicalComposition
materialComposition:

View File

@@ -14,6 +14,7 @@
- type: Tag
tags:
- Ingot
- ConstructionMaterial
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic

View File

@@ -147,6 +147,7 @@
- ClothMade
- Gauze
- RawMaterial
- ConstructionMaterial
- type: Construction
graph: WebObjects # not sure if I should either keep this here or just make another prototype. Will keep it here just in case.
node: cloth
@@ -212,6 +213,7 @@
tags:
- ClothMade
- RawMaterial
- ConstructionMaterial
- type: Item
heldPrefix: durathread
@@ -261,6 +263,7 @@
tags:
- Wooden
- RawMaterial
- ConstructionMaterial
- type: Extractable
grindableSolutionName: wood
- type: SolutionContainerManager

View File

@@ -19,6 +19,9 @@
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Tag
tags:
- ConstructionMaterial
- type: entity
parent: PartBase
@@ -81,6 +84,7 @@
- type: Tag
tags:
- RodMetal1
- ConstructionMaterial
- type: Sprite
state: rods
- type: Stack
@@ -95,43 +99,8 @@
- type: Tag
tags:
- RodMetal1
- ConstructionMaterial
- type: Sprite
state: rods
- type: Stack
count: 1
- type: entity
parent: PartRodMetal
id: PartRodMetalLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: FloorTileItemSteel
id: FloorTileItemSteelLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: FloorTileItemWhite
id: FloorTileItemWhiteLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0
- type: entity
parent: FloorTileItemDark
id: FloorTileItemDarkLingering0
suffix: Lingering, 0
components:
- type: Stack
lingering: true
count: 0

View File

@@ -11,6 +11,9 @@
size: Tiny
- type: Stack
count: 1
- type: Tag
tags:
- ConstructionMaterial
- type: entity
id: MicroManipulatorStockPart

View File

@@ -239,25 +239,3 @@
- type: Residue
residueAdjective: residue-slippery
residueColor: residue-blue
- type: entity
name: soap
id: SoapBorg # Intended for borg internals, not slippery or food, not a container for soap reagent
parent: BaseItem
description: A Nanotrasen brand bar of soap. Smells of plasma and machines.
components:
- type: Sprite
sprite: Objects/Specific/Janitorial/soap.rsi
layers:
- state: nt-4
- type: Appearance
- type: Item
sprite: Objects/Specific/Janitorial/soap.rsi
storedRotation: -90
- type: CleansForensics
- type: Residue
residueAdjective: residue-slippery
residueColor: residue-grey
- type: Tag
tags:
- Soap

View File

@@ -61,15 +61,6 @@
stackType: Ointment
count: 1
- type: entity
id: Ointment10Lingering
parent: Ointment
suffix: 10, Lingering
components:
- type: Stack
lingering: true
count: 10
- type: entity
name: regenerative mesh
description: Used to treat even the nastiest burns. Also effective against caustic burns.
@@ -118,15 +109,6 @@
stackType: RegenerativeMesh
count: 1
- type: entity
parent: RegenerativeMesh
id: RegenerativeMeshLingering0
suffix: 0, Lingering
components:
- type: Stack
lingering: true
count: 0
- type: entity
name: bruise pack
description: A therapeutic gel pack and bandages designed to treat blunt-force trauma.
@@ -172,15 +154,6 @@
stackType: Brutepack
count: 1
- type: entity
id: Brutepack10Lingering
parent: Brutepack
suffix: 10, Lingering
components:
- type: Stack
lingering: true
count: 10
- type: entity
name: medicated suture
description: A suture soaked in medicine, treats blunt-force trauma effectively and closes wounds.
@@ -228,15 +201,6 @@
stackType: MedicatedSuture
count: 1
- type: entity
parent: MedicatedSuture
id: MedicatedSutureLingering0
suffix: 0, Lingering
components:
- type: Stack
lingering: true
count: 0
- type: entity
name: blood pack
description: Contains a groundbreaking universal blood replacement created by Nanotrasen's advanced medical science.
@@ -283,15 +247,6 @@
stackType: Bloodpack
count: 1
- type: entity
parent: Bloodpack
id: Bloodpack10Lingering
suffix: 10, Lingering
components:
- type: Stack
lingering: true
count: 10
- type: entity
parent: BaseHealingItem
id: Tourniquet
@@ -375,15 +330,6 @@
- type: Stack
count: 1
- type: entity
id: Gauze10Lingering
parent: Gauze
suffix: 10, Lingering
components:
- type: Stack
lingering: true
count: 10
- type: entity
name: aloe cream
description: A topical cream for burns.

View File

@@ -46,7 +46,7 @@
- type: SelectableBorgModule
- type: ContainerContainer
containers:
provided_container: !type:Container { }
holding_container: !type:Container { }
- type: entity
parent: BaseAction
@@ -422,13 +422,31 @@
- state: generic
- state: icon-cables
- type: ItemBorgModule
items:
- CableApcStackLingering10
- CableMVStackLingering10
- CableHVStackLingering10
- Wirecutter
- Crowbar
- trayScanner
hands:
- item: CableApcStack10
hand:
emptyRepresentative: CableApcStack10
emptyLabel: borg-slot-cables-empty
whitelist:
tags:
- CableCoil
- item: CableMVStack10
hand:
emptyRepresentative: CableMVStack10
emptyLabel: borg-slot-cables-empty
whitelist:
tags:
- CableCoil
- item: CableHVStack10
hand:
emptyRepresentative: CableHVStack10
emptyLabel: borg-slot-cables-empty
whitelist:
tags:
- CableCoil
- item: Wirecutter
- item: Crowbar
- item: trayScanner
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: wire-module }
@@ -443,11 +461,11 @@
- state: generic
- state: icon-fire-extinguisher
- type: ItemBorgModule
items:
- BorgFireExtinguisher
- BorgHandheldGPSBasic
- HandheldStationMapUnpowered
- HandHeldMassScannerBorg
hands:
- item: BorgFireExtinguisher
- item: BorgHandheldGPSBasic
- item: HandheldStationMapUnpowered
- item: HandHeldMassScannerBorg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: extinguisher-module }
@@ -461,13 +479,13 @@
- state: generic
- state: icon-tools
- type: ItemBorgModule
items:
- Crowbar
- Wrench
- Screwdriver
- Wirecutter
- WelderIndustrial
- Multitool
hands:
- item: Crowbar
- item: Wrench
- item: Screwdriver
- item: Wirecutter
- item: WelderIndustrial
- item: Multitool
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: tool-module }
@@ -482,13 +500,13 @@
- state: cargo
- state: icon-appraisal
- type: ItemBorgModule
items:
- AppraisalTool
- Pen
- HandLabeler
- RubberStampApproved
- RubberStampDenied
- RadioHandheld
hands:
- item: AppraisalTool
- item: Pen
- item: HandLabeler
- item: RubberStampApproved
- item: RubberStampDenied
- item: RadioHandheld
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: appraisal-module }
@@ -502,11 +520,11 @@
- state: cargo
- state: icon-mining
- type: ItemBorgModule
items:
- MiningDrill
- Shovel
- MineralScannerUnpowered
- BorgOreBag
hands:
- item: MiningDrill
- item: Shovel
- item: MineralScannerUnpowered
- item: BorgOreBag
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: mining-module }
@@ -521,11 +539,11 @@
- state: cargo
- state: icon-mining-adv
- type: ItemBorgModule
items:
- MiningDrillDiamond
- Shovel
- AdvancedMineralScannerUnpowered
- OreBagOfHolding
hands:
- item: MiningDrillDiamond
- item: Shovel
- item: AdvancedMineralScannerUnpowered
- item: OreBagOfHolding
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-mining-module }
@@ -539,11 +557,11 @@
- state: cargo
- state: icon-grappling-gun
- type: ItemBorgModule
items:
- WeaponGrapplingGun
- BorgFireExtinguisher
- BorgHandheldGPSBasic
- HandHeldMassScannerBorg
hands:
- item: WeaponGrapplingGun
- item: BorgFireExtinguisher
- item: BorgHandheldGPSBasic
- item: HandHeldMassScannerBorg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: grappling-module }
@@ -559,15 +577,23 @@
- state: engineering
- state: icon-tools-adv
- type: ItemBorgModule
items:
- JawsOfLife
- PowerDrill
- WelderExperimental
- Multitool
- RemoteSignallerAdvanced
hands:
- item: JawsOfLife
- item: PowerDrill
- item: WelderExperimental
- item: Multitool
- item: RemoteSignallerAdvanced
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-tools-module }
- type: entity
id: BorgModuleConstructionMaterialPlaceholder
parent: BaseItem
components:
- type: Sprite
sprite: Objects/Materials/Sheets/other.rsi
state: generic_materials
- type: entity
id: BorgModuleConstruction
parent: [ BaseBorgModuleEngineering, BaseProviderBorgModule ]
@@ -578,16 +604,61 @@
- state: engineering
- state: icon-construction
- type: ItemBorgModule
items:
- SheetSteelLingering0
- SheetGlassLingering0
- SheetRGlassLingering0
- SheetRPGlassLingering0
- SheetPlasteelLingering0
- PartRodMetalLingering0
- FloorTileItemSteelLingering0
- FloorTileItemWhiteLingering0
- FloorTileItemDarkLingering0
hands:
- hand:
emptyRepresentative: BorgModuleConstructionMaterialPlaceholder
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- hand:
emptyRepresentative: BorgModuleConstructionMaterialPlaceholder
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- hand:
emptyRepresentative: BorgModuleConstructionMaterialPlaceholder
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- hand:
emptyRepresentative: DoorElectronics
emptyLabel: borg-slot-circuitboards-empty
whitelist:
components:
- Circuitboard
- hand:
emptyRepresentative: MicroManipulatorStockPart
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- hand:
emptyRepresentative: SpaceHeaterFlatpack
emptyLabel: borg-slot-flatpacks-empty
whitelist:
components:
- Flatpack
- hand:
emptyRepresentative: FloorTileItemSteel
emptyLabel: borg-slot-tiles-empty
whitelist:
components:
- FloorTile
- hand:
emptyRepresentative: FloorTileItemWhite
emptyLabel: borg-slot-tiles-empty
whitelist:
components:
- FloorTile
- hand:
emptyRepresentative: FloorTileItemDark
emptyLabel: borg-slot-tiles-empty
whitelist:
components:
- FloorTile
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: construction-module }
@@ -601,13 +672,13 @@
- state: engineering
- state: icon-rcd
- type: ItemBorgModule
items:
- RCDRecharging
- BorgFireExtinguisher
- BorgHandheldGPSBasic
- GasAnalyzer
- HolofanProjectorBorg
- GeigerCounter
hands:
- item: RCDRecharging
- item: BorgFireExtinguisher
- item: BorgHandheldGPSBasic
- item: GasAnalyzer
- item: HolofanProjectorBorg
- item: GeigerCounter
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: rcd-module }
@@ -622,11 +693,17 @@
- state: janitor
- state: icon-light-replacer
- type: ItemBorgModule
items:
- LightReplacer
- BorgTrashBag
- Plunger
- SoapBorg
hands:
- item: LightReplacer
- item: BorgTrashBag
- item: Plunger
- item: SoapNT
hand:
emptyLabel: borg-slot-soap-empty
emptyRepresentative: SoapNT
whitelist:
tags:
- Soap
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: light-replacer-module }
@@ -640,11 +717,11 @@
- state: janitor
- state: icon-mop
- type: ItemBorgModule
items:
- MopItem
- BorgBucket
- BorgSprayBottle
- HoloprojectorBorg
hands:
- item: MopItem
- item: BorgBucket
- item: BorgSprayBottle
- item: HoloprojectorBorg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: cleaning-module }
@@ -659,12 +736,18 @@
- state: janitor
- state: icon-mop-adv
- type: ItemBorgModule
items:
- AdvMopItem
- BorgMegaSprayBottle
- HoloprojectorBorg
- BorgDropper
- BorgBeaker
hands:
- item: AdvMopItem
- item: BorgMegaSprayBottle
- item: HoloprojectorBorg
- item: BorgDropper
- item: Beaker
hand:
emptyLabel: borg-slot-beakers-empty
emptyRepresentative: Beaker
whitelist:
tags:
- GlassBeaker
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-cleaning-module }
@@ -679,9 +762,9 @@
- state: medical
- state: icon-diagnosis
- type: ItemBorgModule
items:
- HandheldHealthAnalyzerUnpowered
- ClothingNeckStethoscope
hands:
- item: HandheldHealthAnalyzerUnpowered
- item: ClothingNeckStethoscope
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: diagnosis-module }
@@ -695,14 +778,36 @@
- state: medical
- state: icon-treatment
- type: ItemBorgModule
items:
- HandheldHealthAnalyzerUnpowered
- Gauze10Lingering
- Brutepack10Lingering
- Ointment10Lingering
- Bloodpack10Lingering
- RegenerativeMeshLingering0
- MedicatedSutureLingering0
hands:
- item: HandheldHealthAnalyzerUnpowered
- item: Gauze
hand:
emptyLabel: borg-slot-topicals-empty
emptyRepresentative: Gauze
whitelist:
components:
- Healing
- item: Brutepack
hand:
emptyLabel: borg-slot-topicals-empty
emptyRepresentative: Brutepack
whitelist:
components:
- Healing
- item: Ointment
hand:
emptyLabel: borg-slot-topicals-empty
emptyRepresentative: Ointment
whitelist:
components:
- Healing
- item: Bloodpack
hand:
emptyLabel: borg-slot-topicals-empty
emptyRepresentative: Bloodpack
whitelist:
components:
- Healing
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: treatment-module }
@@ -716,12 +821,12 @@
- state: medical
- state: icon-defib
- type: ItemBorgModule
items:
- HandheldHealthAnalyzerUnpowered
- DefibrillatorOneHandedUnpowered
- BorgFireExtinguisher
- BorgHandheldGPSBasic
- HandLabeler
hands:
- item: HandheldHealthAnalyzerUnpowered
- item: DefibrillatorOneHandedUnpowered
- item: BorgFireExtinguisher
- item: BorgHandheldGPSBasic
- item: HandLabeler
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: defib-module }
@@ -735,13 +840,31 @@
- state: medical
- state: icon-chem
- type: ItemBorgModule
items:
- HandheldHealthAnalyzerUnpowered
- Syringe
- BorgDropper
- BorgVial
- BorgVial
- BorgVial
hands:
- item: HandheldHealthAnalyzerUnpowered
- item: Syringe
- item: BorgDropper
- item: BaseChemistryEmptyVial
hand:
emptyLabel: borg-slot-small-containers-empty
emptyRepresentative: BaseChemistryEmptyVial
whitelist:
components:
- FitsInDispenser
- item: BaseChemistryEmptyVial
hand:
emptyLabel: borg-slot-small-containers-empty
emptyRepresentative: BaseChemistryEmptyVial
whitelist:
components:
- FitsInDispenser
- item: BaseChemistryEmptyVial
hand:
emptyLabel: borg-slot-small-containers-empty
emptyRepresentative: BaseChemistryEmptyVial
whitelist:
components:
- FitsInDispenser
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: chem-module }
@@ -756,13 +879,38 @@
- state: medical
- state: icon-chemist
- type: ItemBorgModule
items:
- HandheldHealthAnalyzerUnpowered
- BorgHypo
- Syringe
- BorgDropper
- BorgBeaker
- BorgBeaker
hands:
- item: HandheldHealthAnalyzerUnpowered
- item: BorgHypo
- item: Syringe
- item: BorgDropper
- item: Beaker
hand:
emptyLabel: borg-slot-chemical-containers-empty
emptyRepresentative: Beaker
whitelist:
components:
- FitsInDispenser
tags:
- ChemDispensable
- item: Beaker
hand:
emptyLabel: borg-slot-chemical-containers-empty
emptyRepresentative: Beaker
whitelist:
components:
- FitsInDispenser
tags:
- ChemDispensable
- item: Beaker
hand:
emptyLabel: borg-slot-chemical-containers-empty
emptyRepresentative: Beaker
whitelist:
components:
- FitsInDispenser
tags:
- ChemDispensable
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-chem-module }
@@ -778,13 +926,19 @@
- state: science
- state: icon-artifacts
- type: ItemBorgModule
items:
- NodeScanner
- SprayBottle
- GasAnalyzer
- BorgDropper
- BorgVial
- GeigerCounter
hands:
- item: NodeScanner
- item: SprayBottle
- item: GasAnalyzer
- item: BorgDropper
- item: BaseChemistryEmptyVial
hand:
emptyLabel: borg-slot-small-containers-empty
emptyRepresentative: BaseChemistryEmptyVial
whitelist:
components:
- FitsInDispenser
- item: GeigerCounter
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: node-scanner-module }
@@ -798,13 +952,23 @@
- state: science
- state: icon-anomalies
- type: ItemBorgModule
items:
- AnomalyScanner
- AnomalyLocatorUnpowered
- AnomalyLocatorWideUnpowered
- HandLabeler
- SheetRGlassLingering0
- SheetRPGlassLingering0
hands:
- item: AnomalyScanner
- item: AnomalyLocatorUnpowered
- item: AnomalyLocatorWideUnpowered
- item: HandLabeler
- hand:
emptyRepresentative: SheetRGlass
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- hand:
emptyRepresentative: SheetRPGlass
emptyLabel: borg-slot-construction-empty
whitelist:
tags:
- ConstructionMaterial
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: anomaly-module }
@@ -819,14 +983,43 @@
- state: service
- state: icon-pen
- type: ItemBorgModule
items:
- Pen
#- BooksBag (Add back when hand whitelisting exists, at the moment they can only use it like an orebag.)
- HandLabeler
- RubberStampApproved
- RubberStampDenied
- BorgDropper
- BorgVial
hands:
- item: Pen
- item: BooksBag
- hand:
emptyLabel: borg-slot-documents-empty
emptyRepresentative: BookBase
whitelist:
tags:
- Book
- Dice
- Document
- Figurine
- TabletopBoard
- Write
- hand:
emptyLabel: borg-slot-documents-empty
emptyRepresentative: Paper
whitelist:
tags:
- Book
- Dice
- Document
- Figurine
- TabletopBoard
- Write
- item: HandLabeler
- item: RubberStampApproved
- item: RubberStampDenied
- item: BorgDropper
- item: DrinkShaker
hand:
emptyLabel: borg-slot-small-containers-empty
emptyRepresentative: DrinkShaker
whitelist:
components:
- FitsInDispenser
- item: BarSpoon
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: service-module }
@@ -840,10 +1033,28 @@
- state: service
- state: icon-musique
- type: ItemBorgModule
items:
- SynthesizerInstrument
- ElectricGuitarInstrument
- SaxophoneInstrument
hands:
- item: SynthesizerInstrument
hand:
emptyLabel: borg-slot-instruments-empty
emptyRepresentative: SynthesizerInstrument
whitelist:
components:
- Instrument
- item: ElectricGuitarInstrument
hand:
emptyLabel: borg-slot-instruments-empty
emptyRepresentative: ElectricGuitarInstrument
whitelist:
components:
- Instrument
- item: SaxophoneInstrument
hand:
emptyLabel: borg-slot-instruments-empty
emptyRepresentative: SaxophoneInstrument
whitelist:
components:
- Instrument
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: musical-module }
@@ -857,11 +1068,11 @@
- state: service
- state: icon-gardening
- type: ItemBorgModule
items:
- HydroponicsToolMiniHoe
- HydroponicsToolSpade
- HydroponicsToolClippers
- Bucket
hands:
- item: HydroponicsToolMiniHoe
- item: HydroponicsToolSpade
- item: HydroponicsToolClippers
- item: Bucket
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: gardening-module }
@@ -875,10 +1086,10 @@
- state: service
- state: icon-harvesting
- type: ItemBorgModule
items:
- HydroponicsToolScythe
- HydroponicsToolHatchet
- PlantBag
hands:
- item: HydroponicsToolScythe
- item: HydroponicsToolHatchet
- item: PlantBag
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: harvesting-module }
@@ -892,10 +1103,10 @@
- state: service
- state: icon-clown
- type: ItemBorgModule
items:
- BikeHorn
- ClownRecorder
- BikeHornInstrument
hands:
- item: BikeHorn
- item: ClownRecorder
- item: BikeHornInstrument
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: clowning-module }
@@ -910,12 +1121,12 @@
- state: service
- state: icon-clown-adv
- type: ItemBorgModule
items:
- HoloprojectorClownBorg
- BorgLauncherCreamPie
- ClownRecorder
- PushHorn
- BikeHornInstrument
hands:
- item: HoloprojectorClownBorg
- item: BorgLauncherCreamPie
- item: ClownRecorder
- item: PushHorn
- item: BikeHornInstrument
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-clowning-module }
@@ -930,9 +1141,9 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- WeaponPistolEchis
- EnergyDaggerLoud
hands:
- item: WeaponPistolEchis
- item: EnergyDaggerLoud
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-weapon-module }
- type: Item
@@ -967,11 +1178,11 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- Crowbar
- Emag
- AccessBreaker
- PinpointerSyndicateNuclear
hands:
- item: Crowbar
- item: Emag
- item: AccessBreaker
- item: PinpointerSyndicateNuclear
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-operative-module }
@@ -986,9 +1197,9 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- CyborgEnergySwordDouble
- PinpointerSyndicateNuclear
hands:
- item: CyborgEnergySwordDouble
- item: PinpointerSyndicateNuclear
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-esword-module }
@@ -1003,9 +1214,9 @@
- state: syndicate
- state: icon-syndicate
- type: ItemBorgModule
items:
- WeaponLightMachineGunL6C
- PinpointerSyndicateNuclear
hands:
- item: WeaponLightMachineGunL6C
- item: PinpointerSyndicateNuclear
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-l6c-module }
@@ -1020,8 +1231,8 @@
- state: syndicateborgbomb
- state: icon-bomb
- type: ItemBorgModule
items:
- SelfDestructSeq
hands:
- item: SelfDestructSeq
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: syndicate-martyr-module }
- type: Item
@@ -1057,10 +1268,10 @@
- state: xenoborg_generic
- state: icon-xenoborg-basic
- type: ItemBorgModule
items:
- MaterialBag
- PinpointerMothership
- HandheldGPSBasic
hands:
- item: MaterialBag
- item: PinpointerMothership
- item: HandheldGPSBasic
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-basic-module }
@@ -1075,13 +1286,13 @@
- state: xenoborg_generic
- state: icon-xenoborg-tools
- type: ItemBorgModule
items:
- Crowbar
- Wrench
- Screwdriver
- Wirecutter
- Multitool
- RefuelingWelder
hands:
- item: Crowbar
- item: Wrench
- item: Screwdriver
- item: Wirecutter
- item: Multitool
- item: RefuelingWelder
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-tool-module }
@@ -1096,8 +1307,8 @@
- state: xenoborg_engi
- state: icon-xenoborg-access-breaker
- type: ItemBorgModule
items:
- AccessBreaker
hands:
- item: AccessBreaker
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-access-breaker-module }
@@ -1112,8 +1323,8 @@
- state: xenoborg_engi
- state: icon-xenoborg-fire-extinguisher
- type: ItemBorgModule
items:
- SelfRechargingFireExtinguisher
hands:
- item: SelfRechargingFireExtinguisher
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-extinguisher-module }
@@ -1128,8 +1339,8 @@
- state: xenoborg_heavy
- state: icon-xenoborg-jammer
- type: ItemBorgModule
items:
- XenoborgRadioJammer
hands:
- item: XenoborgRadioJammer
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-jammer-module }
@@ -1144,8 +1355,8 @@
- state: xenoborg_heavy
- state: icon-xenoborg-laser
- type: ItemBorgModule
items:
- XenoborgLaserGun
hands:
- item: XenoborgLaserGun
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-laser-module }
@@ -1160,8 +1371,8 @@
- state: xenoborg_heavy
- state: icon-xenoborg-laser2
- type: ItemBorgModule
items:
- XenoborgHeavyLaserGun
hands:
- item: XenoborgHeavyLaserGun
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-laser2-module }
@@ -1176,12 +1387,12 @@
- state: xenoborg_scout
- state: icon-xenoborg-space-movement
- type: ItemBorgModule
items:
- HandheldGPSBasic
- HandHeldMassScannerBorg
- HandheldStationMapUnpowered
- WeaponGrapplingGun
- JetpackXenoborg
hands:
- item: HandheldGPSBasic
- item: HandHeldMassScannerBorg
- item: HandheldStationMapUnpowered
- item: WeaponGrapplingGun
- item: JetpackXenoborg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-space-movement-module }
@@ -1196,9 +1407,9 @@
- state: xenoborg_scout
- state: icon-xenoborg-sword
- type: ItemBorgModule
items:
- KukriKnife
- JetpackXenoborg
hands:
- item: KukriKnife
- item: JetpackXenoborg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-sword-module }
@@ -1213,9 +1424,9 @@
- state: xenoborg_scout
- state: icon-xenoborg-sword2
- type: ItemBorgModule
items:
- EnergyDaggerLoudBlue
- JetpackXenoborg
hands:
- item: EnergyDaggerLoudBlue
- item: JetpackXenoborg
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-sword2-module }
@@ -1230,8 +1441,8 @@
- state: xenoborg_stealth
- state: icon-xenoborg-hypo
- type: ItemBorgModule
items:
- NocturineHypo
hands:
- item: NocturineHypo
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-hypo-module }
@@ -1246,8 +1457,8 @@
- state: xenoborg_stealth
- state: icon-xenoborg-projector
- type: ItemBorgModule
items:
- ChameleonProjector
hands:
- item: ChameleonProjector
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-projector-module }
@@ -1262,8 +1473,8 @@
- state: xenoborg_stealth
- state: icon-xenoborg-cloak
- type: ItemBorgModule
items:
- CloakingDevice
hands:
- item: CloakingDevice
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-eye-module }
@@ -1278,7 +1489,7 @@
- state: xenoborg_stealth
- state: icon-xenoborg-cloak2
- type: ItemBorgModule
items:
- SuperCloakingDevice
hands:
- item: SuperCloakingDevice
- type: BorgModuleIcon
icon: { sprite: Interface/Actions/actions_borg.rsi, state: xenoborg-eye2-module }

View File

@@ -104,64 +104,6 @@
solution: beaker
- type: DnaSubstanceTrace
- type: entity
parent: BaseItem
id: BorgVial
name: integrated vial
description: An internal compartment installed into a cyborg. Rated for 30 units of any liquid.
components:
# All this shit is here to avoid inheriting breakable, since borgs can't replace broken vials.
- type: Sprite
sprite: Objects/Specific/Chemistry/vial.rsi
layers:
- state: vial-1
- state: vial-1-1
map: ["enum.SolutionContainerLayers.Fill"]
visible: false
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 6
fillBaseName: vial-1-
inHandsMaxFillLevels: 4
inHandsFillBaseName: -fill-
- type: Drink
solution: beaker
- type: SolutionContainerManager
solutions:
beaker:
maxVol: 30
- type: MixableSolution
solution: beaker
- type: RefillableSolution
solution: beaker
- type: DrainableSolution
solution: beaker
- type: ExaminableSolution
solution: beaker
exactVolume: true
- type: DrawableSolution
solution: beaker
- type: SolutionTransfer
maxTransferAmount: 30
canChangeTransferAmount: true
- type: SolutionItemStatus
solution: beaker
- type: UserInterface
interfaces:
enum.TransferAmountUiKey.Key:
type: TransferAmountBoundUserInterface
- type: Item
size: Tiny
sprite: Objects/Specific/Chemistry/vial.rsi
shape:
- 0,0,0,0
- type: MeleeWeapon
soundNoDamage:
path: "/Audio/Effects/Fluids/splat.ogg"
damage:
types:
Blunt: 0
- type: entity
id: VestineChemistryVial
parent: BaseChemistryEmptyVial

View File

@@ -95,65 +95,6 @@
price: 30
- type: DnaSubstanceTrace
- type: entity
parent: BaseItem
id: BorgBeaker
name: integrated beaker
description: An internal compartment installed into a cyborg. Rated for 50 units of any liquid.
components:
# 3 morbillion components are to avoid inheriting breakable since borgs can't replace beakers.
- type: Tag
tags:
- GlassBeaker
- type: Sprite
sprite: Objects/Specific/Chemistry/beaker.rsi
layers:
- state: beaker
- state: beaker1
map: ["enum.SolutionContainerLayers.Fill"]
visible: false
- type: Item
sprite: Objects/Specific/Chemistry/beaker.rsi
- type: MeleeWeapon
soundNoDamage:
path: "/Audio/Effects/Fluids/splat.ogg"
damage:
types:
Blunt: 0
- type: SolutionContainerManager
solutions:
beaker:
maxVol: 50
- type: MixableSolution
solution: beaker
- type: FitsInDispenser
solution: beaker
- type: RefillableSolution
solution: beaker
- type: DrainableSolution
solution: beaker
- type: ExaminableSolution
solution: beaker
exactVolume: true
- type: DrawableSolution
solution: beaker
- type: InjectableSolution
solution: beaker
- type: SolutionTransfer
canChangeTransferAmount: true
- type: SolutionItemStatus
solution: beaker
- type: UserInterface
interfaces:
enum.TransferAmountUiKey.Key:
type: TransferAmountBoundUserInterface
- type: Drink
solution: beaker
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 6
fillBaseName: beaker
- type: entity
parent: BaseItem
id: BaseBeakerMetallic

View File

@@ -82,15 +82,6 @@
- type: Stack
count: 10
- type: entity
parent: CableHVStack10
id: CableHVStackLingering10
suffix: Lingering, 10
components:
- type: Stack
lingering: true
count: 10
- type: entity
parent: CableHVStack
id: CableHVStack1
@@ -147,15 +138,6 @@
- type: Stack
count: 10
- type: entity
parent: CableMVStack10
id: CableMVStackLingering10
suffix: Lingering, 10
components:
- type: Stack
lingering: true
count: 10
- type: entity
parent: CableMVStack
id: CableMVStack1
@@ -211,15 +193,6 @@
- type: Stack
count: 10
- type: entity
parent: CableApcStack10
id: CableApcStackLingering10
suffix: Lingering, 10
components:
- type: Stack
lingering: true
count: 10
- type: entity
parent: CableApcStack
id: CableApcStack1

View File

@@ -347,6 +347,9 @@
- type: Tag
id: ComputerTelevisionCircuitboard
- type: Tag
id: ConstructionMaterial
- type: Tag
id: ConveyorAssembly