diff --git a/Content.Client/Cargo/UI/CargoConsoleMenu.xaml.cs b/Content.Client/Cargo/UI/CargoConsoleMenu.xaml.cs index 92039789473..344596f99d9 100644 --- a/Content.Client/Cargo/UI/CargoConsoleMenu.xaml.cs +++ b/Content.Client/Cargo/UI/CargoConsoleMenu.xaml.cs @@ -211,11 +211,11 @@ namespace Content.Client.Cargo.UI foreach (var order in orders) { - if (order.Approved) + if (order.Approved || !_protoManager.Resolve(order.Product, out var productProto)) continue; - var product = _protoManager.Index(order.ProductId); - var productName = product.Name; + var product = _protoManager.Index(productProto.Product); + var productName = productProto.Name; var requester = !string.IsNullOrEmpty(order.Requester) ? order.Requester : Loc.GetString("cargo-console-menu-order-row-alerts-requester-unknown"); var account = _protoManager.Index(order.Account); @@ -230,7 +230,7 @@ namespace Content.Client.Cargo.UI "cargo-console-menu-order-row-title", ("productName", productName), ("orderAmount", order.OrderQuantity), - ("orderPrice", order.Price)), + ("orderPrice", productProto.Cost)), }, Stride = diff --git a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs index 970051432be..a4ed3f2bde8 100644 --- a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs +++ b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs @@ -34,7 +34,10 @@ namespace Content.Client.Cargo.UI foreach (var order in orders) { - var product = protoManager.Index(order.ProductId); + if (!protoManager.Resolve(order.Product, out var productProto)) + continue; + + var product = protoManager.Index(productProto.Product); var productName = product.Name; var account = protoManager.Index(order.Account); diff --git a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs index 7835ccad3e9..7058cfab6a1 100644 --- a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs @@ -121,66 +121,77 @@ namespace Content.IntegrationTests.Tests await server.WaitAssertion(() => { - HashSet restocks = new(); - Dictionary> restockStores = new(); - - // Collect all the prototypes with restock components. + // Collect all entity prototypes which are vending machine restocks. + var restockEntities = new HashSet>(); foreach (var proto in prototypeManager.EnumeratePrototypes()) { if (proto.Abstract || pair.IsTestPrototype(proto) || !proto.HasComponent()) - { continue; - } - restocks.Add(proto.ID); + restockEntities.Add(proto.ID); } - // Collect all the prototypes with EntityTableContainerFills referencing those entities. + // Collect all entity prototypes with `EntityTableContainerFill`s which contain those restock entities. + // Specifically, this is a mapping of entities-with-container-fill to their-contained-entities-which-are-restocks. + Dictionary, + List>> entitiesWhichSpawnRestocks = new(); foreach (var proto in prototypeManager.EnumeratePrototypes()) { - if (!proto.TryGetComponent(out var storage, compFact)) + if (!proto.TryGetComponent(out var fill, compFact)) continue; - var containers = storage.Containers; + var containers = fill.Containers; - if (!containers.TryGetValue(SharedEntityStorageSystem.ContainerName, out var container)) // We only care about this container type. + // We only care about the special known container. + if (!containers.TryGetValue(SharedEntityStorageSystem.ContainerName, out var container)) continue; - List restockStore = new(); - - foreach (var spawnEntry in entityTable.GetSpawns(container)) + var entitiesInProtoContainingRestock = new List>(); + foreach (var (fillSpawnEntry, _) in entityTable.ListSpawns(container)) { - if (restocks.Contains(spawnEntry)) - restockStore.Add(spawnEntry); + if (restockEntities.Contains(fillSpawnEntry.Id)) + entitiesInProtoContainingRestock.Add(fillSpawnEntry.Id); } - if (restockStore.Count > 0) - restockStores.Add(proto.ID, restockStore); + if (entitiesInProtoContainingRestock.Count > 0) + entitiesWhichSpawnRestocks.Add(proto.ID, entitiesInProtoContainingRestock); } - // Iterate through every CargoProduct and make sure each - // prototype with a restock component is referenced in a - // purchaseable entity with an EntityTableContianerFill. + // Remove all restock entities from our set which are either directly purchasable as a CargoProduct, or + // which are spawned by EntityTableContainerFill on a CargoProduct. foreach (var proto in prototypeManager.EnumeratePrototypes()) { - if (restockStores.ContainsKey(proto.Product)) - { - foreach (var entry in restockStores[proto.Product]) - restocks.Remove(entry); + // If the cargo product's product is the restock itself, just remove it. + restockEntities.Remove(proto.Product.Id); - restockStores.Remove(proto.Product); + // Check if the product is an entity which spawns a restock. + if (entitiesWhichSpawnRestocks.TryGetValue(proto.Product.Id, out var restocksSpawnedByProduct)) + { + foreach (var entry in restocksSpawnedByProduct) + { + restockEntities.Remove(entry); + } + + entitiesWhichSpawnRestocks.Remove(proto.Product.Id); } } + // Any entities left in restockEntities are restocks which can't be bought from Cargo. Assert.Multiple(() => { - Assert.That(restockStores, Has.Count.EqualTo(0), - $"Some entities containing entities with VendingMachineRestock components are unavailable for purchase: \n - {string.Join("\n - ", restockStores.Keys)}"); + const string restockCompName = nameof(VendingMachineRestockComponent); - Assert.That(restocks, Has.Count.EqualTo(0), - $"Some entities with VendingMachineRestock components are unavailable for purchase: \n - {string.Join("\n - ", restocks)}"); + Assert.That(entitiesWhichSpawnRestocks, + Has.Count.EqualTo(0), + $"Some entities containing entities with {restockCompName} are unavailable for purchase: \n - {string.Join("\n - ", entitiesWhichSpawnRestocks.Keys)}"); + + + + Assert.That(restockEntities, + Has.Count.EqualTo(0), + $"Some entities with {restockCompName} are unavailable for purchase: \n - {string.Join("\n - ", restockEntities)}"); }); }); diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index 8556a47410c..96a4aaf2e40 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -77,7 +77,7 @@ namespace Content.Server.Cargo.Systems return; var orderId = GenerateOrderId(orderDatabase); - var data = new CargoOrderData(orderId, product.Product, product.Name, product.Cost, slip.OrderQuantity, slip.Requester, slip.Reason, slip.Account); + var data = new CargoOrderData(orderId, product, slip.OrderQuantity, slip.Requester, slip.Reason, slip.Account); if (!TryAddOrder(stationUid.Value, ent.Comp.Account, data, orderDatabase)) { @@ -89,7 +89,7 @@ namespace Content.Server.Cargo.Systems _audio.PlayPvs(ent.Comp.ScanSound, ent); _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.User):user} inserted order slip [orderId:{data.OrderId}, quantity:{data.OrderQuantity}, product:{data.ProductId}, requester:{data.Requester}, reason:{data.Reason}]"); + $"{ToPrettyString(args.User):user} inserted order slip [orderId:{data.OrderId}, quantity:{data.OrderQuantity}, product:{data.Product}, requester:{data.Requester}, reason:{data.Reason}]"); QueueDel(args.Used); args.Handled = true; } @@ -174,7 +174,7 @@ namespace Content.Server.Cargo.Systems } // Invalid order - if (!_protoMan.HasIndex(order.ProductId)) + if (!_protoMan.Resolve(order.Product, out var product)) { ConsolePopup(args.Actor, Loc.GetString("cargo-console-invalid-product")); PlayDenySound(uid, component); @@ -202,7 +202,7 @@ namespace Content.Server.Cargo.Systems PlayDenySound(uid, component); } - var cost = order.Price * order.OrderQuantity; + var cost = product.Cost * order.OrderQuantity; var accountBalance = GetBalanceFromAccount((station.Value, bank), order.Account); // Not enough balance @@ -239,7 +239,7 @@ namespace Content.Server.Cargo.Systems order.SetApproverData(tryGetIdentityShortInfoEvent.Title); var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast", - ("productName", Loc.GetString(order.ProductName)), + ("productName", Loc.GetString(product.Name)), ("orderAmount", order.OrderQuantity), ("approver", order.Approver ?? string.Empty), ("cost", cost)); @@ -253,7 +253,7 @@ namespace Content.Server.Cargo.Systems // Log order approval _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(player):user} approved order [orderId:{order.OrderId}, quantity:{order.OrderQuantity}, product:{order.ProductId}, requester:{order.Requester}, reason:{order.Reason}] on account {order.Account} with balance at {accountBalance}"); + $"{ToPrettyString(player):user} approved order [orderId:{order.OrderId}, quantity:{order.OrderQuantity}, product:{order.Product}, requester:{order.Requester}, reason:{order.Reason}] on account {order.Account} with balance at {accountBalance}"); orderDatabase.Orders[component.Account].Remove(order); UpdateBankAccount((station.Value, bank), -cost, order.Account); @@ -398,7 +398,7 @@ namespace Content.Server.Cargo.Systems // Log order addition _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(player):user} added order [orderId:{data.OrderId}, quantity:{data.OrderQuantity}, product:{data.ProductId}, requester:{data.Requester}, reason:{data.Reason}]"); + $"{ToPrettyString(player):user} added order [orderId:{data.OrderId}, quantity:{data.OrderQuantity}, product:{data.Product}, requester:{data.Requester}, reason:{data.Reason}]"); } @@ -467,7 +467,7 @@ namespace Content.Server.Cargo.Systems private static CargoOrderData GetOrderData(CargoConsoleAddOrderMessage args, CargoProductPrototype cargoProduct, int id, ProtoId account) { - return new CargoOrderData(id, cargoProduct.Product, cargoProduct.Name, cargoProduct.Cost, args.Amount, args.Requester, args.Reason, account); + return new CargoOrderData(id, cargoProduct, args.Amount, args.Requester, args.Reason, account); } public int GetOutstandingOrderCount(Entity station, ProtoId account) @@ -520,9 +520,7 @@ namespace Content.Server.Cargo.Systems public bool AddAndApproveOrder( EntityUid dbUid, - string spawnId, - string name, - int cost, + CargoProductPrototype product, int qty, string sender, string description, @@ -532,10 +530,9 @@ namespace Content.Server.Cargo.Systems Entity stationData ) { - DebugTools.Assert(_protoMan.HasIndex(spawnId)); // Make an order var id = GenerateOrderId(component); - var order = new CargoOrderData(id, spawnId, name, cost, qty, sender, description, account); + var order = new CargoOrderData(id, product, qty, sender, description, account); // Approve it now // DeltaV: the line below does nothing but null order.Approver? @@ -545,7 +542,7 @@ namespace Content.Server.Cargo.Systems // Log order addition _adminLogger.Add(LogType.Action, LogImpact.Low, - $"AddAndApproveOrder {description} added order [orderId:{order.OrderId}, quantity:{order.OrderQuantity}, product:{order.ProductId}, requester:{order.Requester}, reason:{order.Reason}]"); + $"AddAndApproveOrder {description} added order [orderId:{order.OrderId}, quantity:{order.OrderQuantity}, product:{order.Product}, requester:{order.Requester}, reason:{order.Reason}]"); // Add it to the list return TryAddOrder(dbUid, account, order, component) && TryFulfillOrder(stationData, account, order, component).HasValue; @@ -620,11 +617,34 @@ namespace Content.Server.Cargo.Systems /// private bool FulfillOrder(CargoOrderData order, ProtoId account, EntityCoordinates spawn, string? paperProto) { + if (!_protoMan.Resolve(order.Product, out var product)) + return false; + // Create the item itself - var item = Spawn(order.ProductId, spawn); + var item = Spawn(product.Product, spawn); + var itemXForm = Transform(item); // Ensure the item doesn't start anchored - _transformSystem.Unanchor(item, Transform(item)); + _transformSystem.Unanchor(item, itemXForm); + + // Spawn container and insert the item into it if a container is defined. + if (product.Container is { } productContainer) + { + var containerEntity = Spawn(productContainer.Entity, itemXForm.Coordinates); + _transformSystem.SetLocalRotation(containerEntity, itemXForm.LocalRotation); + + if (!_container.TryGetContainer(containerEntity, productContainer.ContainerId, out var container1) || + !_container.Insert(item, container1, force: true)) + { + DebugTools.Assert( + $"Failed to insert cargo product into its specified container. This indicates an error in the cargo product definition's YAML as the product should be insertable into its container. {nameof(CargoProductPrototype)}: {(ProtoId)order.Product.Id}"); + QueueDel(containerEntity); + } + else + { + item = containerEntity; + } + } // Create a sheet of paper to write the order details on var printed = Spawn(paperProto, spawn); @@ -639,7 +659,7 @@ namespace Content.Server.Cargo.Systems Loc.GetString( "cargo-console-paper-print-text", ("orderNumber", order.OrderId), - ("itemName", MetaData(item).EntityName), + ("itemName", product.Name), ("orderQuantity", order.OrderQuantity), ("requester", order.Requester), ("reason", string.IsNullOrWhiteSpace(order.Reason) ? Loc.GetString("cargo-console-paper-reason-default") : order.Reason), diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index d38de1e0d80..b83fdc702bb 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -64,9 +64,7 @@ public sealed class CargoGiftsRule : StationEventSystem if (!_cargoSystem.AddAndApproveOrder( station!.Value, - product.Product, - product.Name, - product.Cost, + product, qty, Loc.GetString(component.Sender), Loc.GetString(component.Description), diff --git a/Content.Shared/Cargo/CargoOrderData.cs b/Content.Shared/Cargo/CargoOrderData.cs index a0b3fbed50a..f7e56e59f56 100644 --- a/Content.Shared/Cargo/CargoOrderData.cs +++ b/Content.Shared/Cargo/CargoOrderData.cs @@ -7,12 +7,6 @@ namespace Content.Shared.Cargo [DataDefinition, NetSerializable, Serializable] public sealed partial class CargoOrderData { - /// - /// Price when the order was added. - /// - [DataField] - public int Price; - /// /// A unique (arbitrary) ID which identifies this order. /// @@ -20,16 +14,10 @@ namespace Content.Shared.Cargo public int OrderId { get; private set; } /// - /// Prototype Id for the item to be created + /// The ID of the cargo product ordered. /// [DataField] - public string ProductId { get; private set; } - - /// - /// Prototype Name - /// - [DataField] - public string ProductName { get; private set; } + public ProtoId Product; /// /// The number of items in the order. Not readonly, as it might change @@ -60,12 +48,10 @@ namespace Content.Shared.Cargo [DataField] public ProtoId Account; - public CargoOrderData(int orderId, string productId, string productName, int price, int amount, string requester, string reason, ProtoId account) + public CargoOrderData(int orderId, ProtoId product, int amount, string requester, string reason, ProtoId account) { OrderId = orderId; - ProductId = productId; - ProductName = productName; - Price = price; + Product = product; OrderQuantity = amount; Requester = requester; Reason = reason; diff --git a/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs b/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs index 46a3a0de137..592b4d8b526 100644 --- a/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs +++ b/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs @@ -1,5 +1,6 @@ +using Robust.Shared.Containers; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; using Robust.Shared.Utility; @@ -17,9 +18,15 @@ namespace Content.Shared.Cargo.Prototypes [AbstractDataField] public bool Abstract { get; private set; } - [DataField("name")] private string _name = string.Empty; + [DataField("name")] + private LocId? _nameLoc; - [DataField("description")] private string _description = string.Empty; + private string _name = string.Empty; + + [DataField("description")] + private LocId? _descLoc; + + private string _description = string.Empty; [ViewVariables] [IdDataField] @@ -36,7 +43,11 @@ namespace Content.Shared.Cargo.Prototypes if (_name.Trim().Length != 0) return _name; - if (IoCManager.Resolve().Resolve(Product, out EntityPrototype? prototype)) + if (_nameLoc is { } nameLoc) + { + _name = Loc.GetString(nameLoc); + } + else if (IoCManager.Resolve().Resolve(Product, out var prototype)) { _name = prototype.Name; } @@ -56,7 +67,11 @@ namespace Content.Shared.Cargo.Prototypes if (_description.Trim().Length != 0) return _description; - if (IoCManager.Resolve().Resolve(Product, out EntityPrototype? prototype)) + if (_descLoc is { } descLoc) + { + _description = Loc.GetString(descLoc); + } + else if (IoCManager.Resolve().Resolve(Product, out var prototype)) { _description = prototype.Description; } @@ -77,6 +92,12 @@ namespace Content.Shared.Cargo.Prototypes [DataField] public EntProtoId Product { get; private set; } = string.Empty; + /// + /// The entity to spawn and insert the product into. If null, just the product is spawned. + /// + [DataField] + public CargoProductContainer? Container; + /// /// The point cost of the product. /// @@ -95,4 +116,21 @@ namespace Content.Shared.Cargo.Prototypes [DataField] public ProtoId Group { get; private set; } = "market"; } + + /// + [DataDefinition, Serializable, NetSerializable] + public sealed partial class CargoProductContainer + { + /// + /// What entity to spawn as the container. + /// + [DataField(required: true)] + public EntProtoId Entity; + + /// + /// What container in the product should be inserted into. + /// + [DataField(required: true)] + public string ContainerId; + } } diff --git a/Content.Shared/ParcelWrap/Components/ParcelWrapComponent.cs b/Content.Shared/ParcelWrap/Components/ParcelWrapComponent.cs index 41375e5c2ac..e7a7f535848 100644 --- a/Content.Shared/ParcelWrap/Components/ParcelWrapComponent.cs +++ b/Content.Shared/ParcelWrap/Components/ParcelWrapComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Item; +using Content.Shared.ParcelWrap.Systems; using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -18,28 +19,7 @@ public sealed partial class ParcelWrapComponent : Component /// The of the parcel created by using this component. /// [DataField(required: true), AutoNetworkedField] - public EntProtoId ParcelPrototype; - - /// - /// If true, parcels created by this will have the same size as the item they - /// contain. If false, parcels created by this will always have the size specified by . - /// - [DataField, AutoNetworkedField] - public bool WrappedItemsMaintainSize = true; - - /// - /// The size of parcels created by this component's entity. This is used if - /// is false, or if the item being wrapped somehow doesn't have a size. - /// - [DataField, AutoNetworkedField] - public ProtoId FallbackItemSize = "Ginormous"; - - /// - /// If true, parcels created by this will have the same shape as the item they contain. If false, parcels created by - /// this will have the default shape for their size. - /// - [DataField, AutoNetworkedField] - public bool WrappedItemsMaintainShape; + public EntProtoId ParcelPrototype; /// /// How long it takes to use this to wrap something. diff --git a/Content.Shared/ParcelWrap/Components/ParcelWrapOverrideComponent.cs b/Content.Shared/ParcelWrap/Components/ParcelWrapOverrideComponent.cs index e401d30a7f7..7a8c12b6b0e 100644 --- a/Content.Shared/ParcelWrap/Components/ParcelWrapOverrideComponent.cs +++ b/Content.Shared/ParcelWrap/Components/ParcelWrapOverrideComponent.cs @@ -14,11 +14,11 @@ public sealed partial class ParcelWrapOverrideComponent : Component /// The of the parcel created by wrapping this entity. /// [DataField(required: true), AutoNetworkedField] - public EntProtoId? ParcelPrototype; + public EntProtoId ParcelPrototype; /// /// How long it takes to use this to wrap something. /// - [DataField(required: true), AutoNetworkedField] + [DataField, AutoNetworkedField] public TimeSpan? WrapDelay; } diff --git a/Content.Shared/ParcelWrap/Components/WrappedParcelComponent.cs b/Content.Shared/ParcelWrap/Components/WrappedParcelComponent.cs index 2ed018e3447..17c6ef46cb2 100644 --- a/Content.Shared/ParcelWrap/Components/WrappedParcelComponent.cs +++ b/Content.Shared/ParcelWrap/Components/WrappedParcelComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Item; using Content.Shared.ParcelWrap.Systems; using Robust.Shared.Audio; using Robust.Shared.Containers; @@ -45,6 +46,21 @@ public sealed partial class WrappedParcelComponent : Component [DataField, ViewVariables(VVAccess.ReadOnly)] public string ContainerId = "contents"; + /// + /// If true, the owner of this entity has its set to the size of any item inserted + /// into . If the contents do not have a size, + /// is used instead. + /// + [DataField, AutoNetworkedField] + public bool GetsSizeFromContent = true; + + /// + /// If true, the owner of this entity has its set to the shape of any item + /// inserted into . + /// + [DataField, AutoNetworkedField] + public bool GetsShapeFromContent; + /// /// If a player trapped inside this parcel can escape from it by unwrapping it. /// This is set by the used to create the parcel. diff --git a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.ParcelWrap.cs b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.ParcelWrap.cs index 38059b8e245..57b969c0cd7 100644 --- a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.ParcelWrap.cs +++ b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.ParcelWrap.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.DoAfter; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; @@ -5,6 +6,8 @@ using Content.Shared.Item; using Content.Shared.ParcelWrap.Components; using Content.Shared.Popups; using Content.Shared.Verbs; +using Robust.Shared.Network; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.ParcelWrap.Systems; @@ -12,11 +15,34 @@ namespace Content.Shared.ParcelWrap.Systems; // This part handles Parcel Wrap. public sealed partial class ParcelWrappingSystem { + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly INetManager _net = default!; + + private static ProtoId _fallbackParcelSize = "Ginormous"; + private void InitializeParcelWrap() { + SubscribeLocalEvent(OnPrototypeReload); + SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent>(OnGetVerbsForParcelWrap); SubscribeLocalEvent(OnWrapItemDoAfter); + + SetFallbackParcelSize(); + } + + private void OnPrototypeReload(PrototypesReloadedEventArgs args) + { + if (args.WasModified()) + SetFallbackParcelSize(); + } + + private void SetFallbackParcelSize() + { + if (_proto.EnumeratePrototypes().Max() is { } size) + { + _fallbackParcelSize = size; + } } private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) @@ -63,8 +89,9 @@ public sealed partial class ParcelWrappingSystem { var duration = wrapper.Comp.WrapDelay; - if (TryComp(target, out var overrideComp) && overrideComp.WrapDelay != null) - duration = overrideComp.WrapDelay.Value; + if (TryComp(target, out var overrideComp) && + overrideComp.WrapDelay is { } wrapDelayOverride) + duration = wrapDelayOverride; // In case the target is a player inform them with a popup. if (target == user) @@ -74,7 +101,10 @@ public sealed partial class ParcelWrappingSystem } else { - var othersMsg = Loc.GetString("parcel-wrap-popup-being-wrapped", ("user", Identity.Entity(user, EntityManager))); + var othersMsg = Loc.GetString( + "parcel-wrap-popup-being-wrapped", + ("user", Identity.Entity(user, EntityManager)) + ); _popup.PopupEntity(othersMsg, target, target, PopupType.MediumCaution); } @@ -111,43 +141,16 @@ public sealed partial class ParcelWrappingSystem if (_net.IsClient) return; // Predicted spawns can't be interacted with yet. - EntityUid spawned; + // Spawn the actual parcel entity. var targetTransform = Transform(target); - // Check if the target has a pre-defined parcel type to be used. - if (TryComp(target, out var overrideComp)) - { - spawned = Spawn(overrideComp.ParcelPrototype, targetTransform.Coordinates); - } - else // Create a parcel with the same size and generic sprites instead. - { - spawned = Spawn(wrapper.Comp.ParcelPrototype, targetTransform.Coordinates); - - // If this wrap maintains the size when wrapping, set the parcel's size to the target's size. Otherwise use the - // wrap's fallback size. - TryComp(target, out ItemComponent? targetItemComp); - var size = wrapper.Comp.FallbackItemSize; - if (wrapper.Comp.WrappedItemsMaintainSize && targetItemComp is not null) - size = targetItemComp.Size; - - // ParcelWrap's spawned entity should always have an `ItemComp`. As of writing, the only use has it hardcoded on - // its prototype. - var item = Comp(spawned); - _item.SetSize(spawned, size, item); - _appearance.SetData(spawned, WrappedParcelVisuals.Size, size.Id); - - // If this wrap maintains the shape when wrapping and the item has a shape override, copy the shape override to - // the parcel. - if (wrapper.Comp.WrappedItemsMaintainShape && targetItemComp is { Shape: { } shape }) - _item.SetShape(spawned, shape, item); - } - + var spawned = Spawn(GetParcelPrototype(wrapper, target), targetTransform.Coordinates); _transform.SetLocalRotation(spawned, targetTransform.LocalRotation); // If the target is in a container, try to put the parcel in its place in the container. - if (_container.TryGetContainingContainer((target, null, null), out var containerOfTarget)) + if (_container.TryGetContainingContainer(target, out var containerOfTarget)) { _container.Remove(target, containerOfTarget); - _container.InsertOrDrop((spawned, null, null), containerOfTarget); + _container.InsertOrDrop(spawned, containerOfTarget); } // Insert the target into the parcel. @@ -162,4 +165,16 @@ public sealed partial class ParcelWrappingSystem PredictedDel(spawned); } } + + private EntProtoId GetParcelPrototype( + Entity wrapper, + Entity target + ) + { + // If an override is defined on the target, use that. + if (Resolve(target, ref target.Comp, logMissing: false)) + return target.Comp.ParcelPrototype; + + return wrapper.Comp.ParcelPrototype; + } } diff --git a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.WrappedParcel.cs b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.WrappedParcel.cs index 460ba7caf5a..96919b0ae22 100644 --- a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.WrappedParcel.cs +++ b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.WrappedParcel.cs @@ -1,20 +1,25 @@ using Content.Shared.Destructible; using Content.Shared.DoAfter; using Content.Shared.Interaction.Events; +using Content.Shared.Item; using Content.Shared.Materials; using Content.Shared.ParcelWrap.Components; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Shared.Containers; +using Robust.Shared.Timing; namespace Content.Shared.ParcelWrap.Systems; // This part handles Wrapped Parcels public sealed partial class ParcelWrappingSystem { + [Dependency] private readonly IGameTiming _timing = default!; + private void InitializeWrappedParcel() { SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnEntInsertedIntoContainer); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent>(OnGetVerbsForWrappedParcel); SubscribeLocalEvent(OnUnwrapParcelDoAfter); @@ -27,6 +32,35 @@ public sealed partial class ParcelWrappingSystem entity.Comp.Contents = _container.EnsureContainer(entity, entity.Comp.ContainerId); } + private void OnEntInsertedIntoContainer(Entity entity, ref EntInsertedIntoContainerMessage args) + { + // If the entity was inserted because of a server state application, assume that the item's state is applied + // correctly as well and that deriving them from the contents is unneeded. + if (_timing.ApplyingState) + return; + + if (args.Container != entity.Comp.Contents || + !TryComp(entity, out var parcelItemComp)) + return; + + // If this wrap maintains the size when wrapping, set the parcel's size to the target's size, or the fallback + // size if the target does not have a size. + var targetItemComp = CompOrNull(args.Entity); + if (entity.Comp.GetsSizeFromContent) + { + var size = targetItemComp?.Size ?? _fallbackParcelSize; + _item.SetSize(entity, size, parcelItemComp); + _appearance.SetData(entity, WrappedParcelVisuals.Size, size.Id); + } + + // If this wrap maintains the shape when wrapping and the item has a shape override, copy the shape override to + // the parcel. + if (entity.Comp.GetsShapeFromContent) + { + _item.SetShape(entity, targetItemComp?.Shape, parcelItemComp); + } + } + private void OnUseInHand(Entity entity, ref UseInHandEvent args) { if (args.Handled) @@ -102,22 +136,19 @@ public sealed partial class ParcelWrappingSystem /// private EntityUid? UnwrapInternal(EntityUid? user, Entity parcel) { - var containedEntity = parcel.Comp.Contents.ContainedEntity; - _audio.PlayPredicted(parcel.Comp.UnwrapSound, parcel, user); - - // If we're on the client, just return the contained entity and don't try to despawn the parcel. - if (!_net.IsServer) - return containedEntity; - var parcelTransform = Transform(parcel); + _audio.PlayPredicted(parcel.Comp.UnwrapSound, parcelTransform.Coordinates, user); + var containedEntity = parcel.Comp.Contents.ContainedEntity; if (containedEntity is { } parcelContents) { - _container.Remove(parcelContents, + _container.Remove( + parcelContents, parcel.Comp.Contents, true, true, - parcelTransform.Coordinates); + parcelTransform.Coordinates + ); // If the parcel is in a container, try to put the unwrapped contents in that container. if (_container.TryGetContainingContainer((parcel, null, null), out var outerContainer)) @@ -131,11 +162,11 @@ public sealed partial class ParcelWrappingSystem // Spawn unwrap trash. if (parcel.Comp.UnwrapTrash is { } trashProto) { - var trash = Spawn(trashProto, parcelTransform.Coordinates); + var trash = PredictedSpawnAtPosition(trashProto, parcelTransform.Coordinates); _transform.DropNextTo((trash, null), (parcel, parcelTransform)); } - QueueDel(parcel); + PredictedQueueDel(parcel); return containedEntity; } diff --git a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.cs b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.cs index 7ea6daeed8f..15d0074f966 100644 --- a/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.cs +++ b/Content.Shared/ParcelWrap/Systems/ParcelWrappingSystem.cs @@ -6,7 +6,6 @@ using Content.Shared.Popups; using Content.Shared.Whitelist; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Network; namespace Content.Shared.ParcelWrap.Systems; @@ -24,7 +23,6 @@ public sealed partial class ParcelWrappingSystem : EntitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly SharedItemSystem _item = default!; - [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; diff --git a/Resources/Locale/en-US/prototypes/catalog/cargo/cargoproduct-descriptions.ftl b/Resources/Locale/en-US/prototypes/catalog/cargo/cargoproduct-descriptions.ftl new file mode 100644 index 00000000000..916390958ee --- /dev/null +++ b/Resources/Locale/en-US/prototypes/catalog/cargo/cargoproduct-descriptions.ftl @@ -0,0 +1,12 @@ +# Emergency +cargoproduct-description-emergencyinflatablewall = Three stacks of inflatable walls for when the stations metal walls don't want to hold atmosphere anymore. + +# Materials +cargoproduct-name-material-gold = gold ingots +cargoproduct-description-material-gold = 30 ingots of gold. + +cargoproduct-name-material-plasteel = plasteel sheets +cargoproduct-description-material-plasteel = 30 sheets of plasteel. + +cargoproduct-name-material-silver = silver ingots +cargoproduct-description-material-silver = 30 ingots of silver. diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index c3375cf5e9c..800be042cc3 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -801,3 +801,26 @@ TowelColorYellow: null TowelColorMaroon: null TowelColorSilver: null TowelColorMime: null + +# 2026-02-18 +# Replace cargo order crates which contain exactly one item with the item, parcel wrapped. +CrateVendingMachineRestockBoozeFilled: VendingMachineRestockBooze +CrateVendingMachineRestockChefvendFilled: VendingMachineRestockChefvend +CrateVendingMachineRestockClothesFilled: VendingMachineRestockClothes +CrateVendingMachineRestockAutoDrobeFilled: VendingMachineRestockCostumes +CrateVendingMachineRestockCondimentStationFilled: VendingMachineRestockCondimentStation +CrateVendingMachineRestockDinnerwareFilled: VendingMachineRestockDinnerware +CrateVendingMachineRestockGamesFilled: VendingMachineRestockGames +CrateVendingMachineRestockPTechFilled: VendingMachineRestockPTech +CrateVendingMachineRestockSalvageEquipmentFilled: VendingMachineRestockSalvageEquipment +CrateVendingMachineRestockVendomatFilled: VendingMachineRestockVendomat +CrateVendingMachineRestockTankDispenserFilled: VendingMachineRestockTankDispenser +# The crates below contained _two_ of the restock items, so these are technically not direct migrations. But eh. +CrateVendingMachineRestockHotDrinksFilled: VendingMachineRestockHotDrinks +CrateVendingMachineRestockRobustSoftdrinksFilled: VendingMachineRestockRobustSoftdrinks +CrateVendingMachineRestockSmokesFilled: VendingMachineRestockSmokes +CrateVendingMachineRestockHappyHonkFilled: VendingMachineRestockHappyHonk +CrateVendingMachineRestockGetmoreChocolateCorpFilled: VendingMachineRestockGetmoreChocolateCorp +CrateVendingMachineRestockChangFilled: VendingMachineRestockChang +CrateVendingMachineRestockDiscountDansFilled: VendingMachineRestockDiscountDans +CrateVendingMachineRestockDonutFilled: VendingMachineRestockDonut diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_emergency.yml b/Resources/Prototypes/Catalog/Cargo/cargo_emergency.yml index 91ffcf772fa..256beb69a36 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_emergency.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_emergency.yml @@ -50,10 +50,14 @@ - type: cargoProduct id: EmergencyInflatablewall + description: cargoproduct-description-emergencyinflatablewall icon: sprite: Objects/Misc/inflatable_wall.rsi state: item_wall - product: CrateEmergencyInflatablewall + product: BoxInflatable + container: + entity: WrappedParcel + containerId: contents cost: 500 category: cargoproduct-category-name-emergency group: market diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_fun.yml b/Resources/Prototypes/Catalog/Cargo/cargo_fun.yml index c52a2af3a7b..a80e50585f8 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_fun.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_fun.yml @@ -73,7 +73,10 @@ icon: sprite: Objects/Fun/crayons.rsi state: box - product: CrateFunArtSupplies + product: CrayonBox + container: + entity: WrappedParcel + containerId: contents cost: 500 category: cargoproduct-category-name-fun group: market diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml b/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml index a3dd0508066..c3210ab5c7d 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_livestock.yml @@ -123,7 +123,10 @@ icon: sprite: Objects/Misc/monkeycube.rsi state: box - product: CrateNPCMonkeyCube + product: MonkeyCubeBox + container: + entity: WrappedParcel + containerId: contents cost: 2000 category: cargoproduct-category-name-livestock group: market @@ -133,7 +136,10 @@ icon: sprite: Objects/Misc/monkeycube.rsi state: box_kobold - product: CrateNPCKoboldCube + product: KoboldCubeBox + container: + entity: WrappedParcel + containerId: contents cost: 2000 category: cargoproduct-category-name-livestock group: market diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_materials.yml b/Resources/Prototypes/Catalog/Cargo/cargo_materials.yml index e84f43f57b8..384531463f0 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_materials.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_materials.yml @@ -40,30 +40,45 @@ - type: cargoProduct id: MaterialPlasteel + name: cargoproduct-name-material-plasteel + description: cargoproduct-description-material-plasteel icon: sprite: Objects/Materials/Sheets/metal.rsi state: plasteel_3 - product: CrateMaterialPlasteel + product: SheetPlasteel + container: + entity: WrappedParcel + containerId: contents cost: 1600 category: cargoproduct-category-name-materials group: market - type: cargoProduct id: MaterialGold + name: cargoproduct-name-material-gold + description: cargoproduct-description-material-gold icon: sprite: Objects/Materials/ingots.rsi state: gold_3 - product: CrateMaterialGold + product: IngotGold + container: + entity: WrappedParcel + containerId: contents cost: 3225 category: cargoproduct-category-name-materials group: market - type: cargoProduct id: MaterialSilver + name: cargoproduct-name-material-silver + description: cargoproduct-description-material-silver icon: sprite: Objects/Materials/ingots.rsi state: silver_3 - product: CrateMaterialSilver + product: IngotSilver + container: + entity: WrappedParcel + containerId: contents cost: 2580 category: cargoproduct-category-name-materials group: market diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_service.yml b/Resources/Prototypes/Catalog/Cargo/cargo_service.yml index 14f484c5ea5..3f2610bad30 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_service.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_service.yml @@ -43,7 +43,10 @@ icon: sprite: Objects/Devices/mousetrap.rsi state: mousetrap - product: CrateMousetrapBoxes + product: BoxMousetrap + container: + entity: WrappedParcel + containerId: contents cost: 500 category: cargoproduct-category-name-service group: market diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index acf1570f788..3ad51c47cff 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -11,7 +11,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockBoozeFilled + product: VendingMachineRestockBooze + container: + entity: WrappedParcel + containerId: contents cost: 3500 category: cargoproduct-category-name-service group: market @@ -21,7 +24,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockChefvendFilled + product: VendingMachineRestockChefvend + container: + entity: WrappedParcel + containerId: contents cost: 680 category: cargoproduct-category-name-service group: market @@ -31,7 +37,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockClothesFilled + product: VendingMachineRestockClothes + container: + entity: WrappedParcel + containerId: contents cost: 4500 # DeltaV category: cargoproduct-category-name-service group: market @@ -41,7 +50,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockAutoDrobeFilled + product: VendingMachineRestockCostumes + container: + entity: WrappedParcel + containerId: contents cost: 3250 # DeltaV category: cargoproduct-category-name-service group: market @@ -51,7 +63,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockDinnerwareFilled + product: VendingMachineRestockDinnerware + container: + entity: WrappedParcel + containerId: contents cost: 2000 category: cargoproduct-category-name-service group: market @@ -61,7 +76,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockCondimentStationFilled + product: VendingMachineRestockCondimentStation + container: + entity: WrappedParcel + containerId: contents cost: 300 category: cargoproduct-category-name-service group: market @@ -81,7 +99,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockGamesFilled + product: VendingMachineRestockGames + container: + entity: WrappedParcel + containerId: contents cost: 750 category: cargoproduct-category-name-service group: market @@ -91,8 +112,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockHotDrinksFilled - cost: 1200 + product: VendingMachineRestockHotDrinks + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -131,7 +155,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockPTechFilled + product: VendingMachineRestockPTech + container: + entity: WrappedParcel + containerId: contents cost: 1200 category: cargoproduct-category-name-service group: market @@ -141,8 +168,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockRobustSoftdrinksFilled - cost: 1200 + product: VendingMachineRestockRobustSoftdrinks + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -151,8 +181,11 @@ # icon: # sprite: Objects/Specific/Service/vending_machine_restock.rsi # state: base -# product: CrateVendingMachineRestockSalvageEquipmentFilled -# cost: 1000 +# product: VendingMachineRestockSalvageEquipment +# container: +# entity: WrappedParcel +# containerId: contents +# cost: 1500 # category: cargoproduct-category-name-engineering # group: market @@ -181,8 +214,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockSmokesFilled - cost: 1200 + product: VendingMachineRestockSmokes + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -191,7 +227,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockVendomatFilled + product: VendingMachineRestockVendomat + container: + entity: WrappedParcel + containerId: contents cost: 1200 category: cargoproduct-category-name-service group: market @@ -211,7 +250,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockTankDispenserFilled + product: VendingMachineRestockTankDispenser + container: + entity: WrappedParcel + containerId: contents cost: 1300 # DeltaV - Was 1000 category: cargoproduct-category-name-atmospherics group: market @@ -221,8 +263,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockHappyHonkFilled - cost: 2100 + product: VendingMachineRestockHappyHonk + container: + entity: WrappedParcel + containerId: contents + cost: 1050 category: cargoproduct-category-name-service group: market @@ -231,8 +276,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockGetmoreChocolateCorpFilled - cost: 1200 + product: VendingMachineRestockGetmoreChocolateCorp + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -241,8 +289,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockChangFilled - cost: 1200 + product: VendingMachineRestockChang + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -251,8 +302,11 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockDiscountDansFilled - cost: 1200 + product: VendingMachineRestockDiscountDans + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market @@ -261,7 +315,10 @@ icon: sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base - product: CrateVendingMachineRestockDonutFilled - cost: 1200 + product: VendingMachineRestockDonut + container: + entity: WrappedParcel + containerId: contents + cost: 600 category: cargoproduct-category-name-service group: market diff --git a/Resources/Prototypes/Catalog/Cargo/salvage_rewards.yml b/Resources/Prototypes/Catalog/Cargo/salvage_rewards.yml index 19fea1f55f1..bfe1e8abd22 100644 --- a/Resources/Prototypes/Catalog/Cargo/salvage_rewards.yml +++ b/Resources/Prototypes/Catalog/Cargo/salvage_rewards.yml @@ -55,7 +55,10 @@ icon: sprite: Objects/Tanks/Jetpacks/void.rsi state: icon - product: CrateVoidJetpack + product: JetpackVoidFilled + container: + entity: WrappedParcel + containerId: contents cost: 4000 category: cargoproduct-category-name-cargo group: SalvageJobReward3 @@ -65,7 +68,10 @@ icon: sprite: Objects/Weapons/Melee/crusher_glaive.rsi state: icon - product: CrateCrusherGlaive + product: WeaponCrusherGlaive + container: + entity: WrappedParcel + containerId: contents cost: 8000 category: cargoproduct-category-name-cargo group: SalvageJobReward3 @@ -77,7 +83,10 @@ icon: sprite: Clothing/Neck/Cloaks/miner.rsi state: icon - product: CrateSupremeSalvagerCloak + product: ClothingNeckCloakSalvagerSupreme + container: + entity: WrappedParcel + containerId: contents cost: 25000 category: cargoproduct-category-name-cargo group: SalvageJobRewardMAX diff --git a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml index 047ae5c36f5..11847a9b391 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml @@ -1,69 +1,3 @@ -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockBoozeFilled - name: Booze-O-Mat restock crate - description: Contains a restock box for the Booze-O-Mat. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockBooze - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockChefvendFilled - name: ChefVend restock crate - description: Contains a restock box for the ChefVend. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockChefvend - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockClothesFilled - name: clothing restock crate - description: Contains a restock box for the clothes vending machines. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockClothes - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockAutoDrobeFilled - name: AutoDrobe restock crate - description: Contains a restock box for the AutoDrobe. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockCostumes - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockCondimentStationFilled - name: condiment station restock crate - description: Contains a restock box for the condiment station. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockCondimentStation - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockDinnerwareFilled - name: Plasteel Chef restock crate - description: Contains a restock box for the Plasteel Chef vending machine. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockDinnerware - - type: entity parent: CrateEngineeringSecure id: CrateVendingMachineRestockEngineeringFilled @@ -75,29 +9,6 @@ entity_storage: id: VendingMachineRestockEngineering -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockGamesFilled - name: Good Clean Fun restock crate - description: Contains a restock box for the Good Clean Fun vending machine. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockGames - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockHotDrinksFilled - name: Solar's Best restock crate - description: Contains two restock boxes for Solar's Best Hot Drinks vending machine. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockHotDrinks - amount: 2 - - type: entity parent: CrateMedicalSecure id: CrateVendingMachineRestockMedicalFilled @@ -131,41 +42,6 @@ entity_storage: id: VendingMachineRestockNutriMax -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockPTechFilled - name: PTech restock crate - description: Contains a restock box for the PTech bureaucracy dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockPTech - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockRobustSoftdrinksFilled - name: beverage vendor restock crate - description: Contains restock boxes for beverage vending machines. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockRobustSoftdrinks - amount: 2 - -#- type: entity # DeltaV: Salvage vendor doesn't have stock anymore -#- type: entity -# parent: CrateGenericSteel -# id: CrateVendingMachineRestockSalvageEquipmentFilled -# name: Salvage restock crate -# description: Contains a restock box for the salvage vendor. -# components: -# - type: EntityTableContainerFill -# containers: -# entity_storage: -# id: VendingMachineRestockSalvageEquipment - - type: entity parent: CrateSecgear id: CrateVendingMachineRestockSecTechFilled @@ -188,29 +64,6 @@ entity_storage: id: VendingMachineRestockSeeds -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockSmokesFilled - name: ShadyCigs restock crate - description: Contains two restock boxes for the ShadyCigs vending machine. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockSmokes - amount: 2 - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockVendomatFilled - name: Vendomat restock crate - description: Contains a restock box for a Vendomat vending machine. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockVendomat - - type: entity parent: CrateScienceSecure id: CrateVendingMachineRestockRoboticsFilled @@ -221,74 +74,3 @@ containers: entity_storage: id: VendingMachineRestockRobotics - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockTankDispenserFilled - name: tank dispenser restock crate - description: Contains a restock box for an Engineering or Atmospherics tank dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockTankDispenser - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockHappyHonkFilled - name: Happy Honk restock crate - description: Contains a restock box for a happy honk dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockHappyHonk - amount: 2 - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockGetmoreChocolateCorpFilled - name: Getmore Chocolate Corp restock crate - description: Contains a restock box for a Getmore Chocolate Corp dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockGetmoreChocolateCorp - amount: 2 - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockChangFilled - name: Chang restock crate - description: Contains a restock box for a Mr. Chang dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockChang - amount: 2 - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockDiscountDansFilled - name: Discount Dans restock crate - description: Contains a restock box for a Discount Dan's dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockDiscountDans - amount: 2 - -- type: entity - parent: CratePlastic - id: CrateVendingMachineRestockDonutFilled - name: Donut restock crate - description: Contains a restock box for a Monkin' Donuts dispenser. - components: - - type: EntityTableContainerFill - containers: - entity_storage: - id: VendingMachineRestockDonut - amount: 2 diff --git a/Resources/Prototypes/Entities/Objects/Misc/parcel_wrap.yml b/Resources/Prototypes/Entities/Objects/Misc/parcel_wrap.yml index c553948891c..0bf7ab9813a 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/parcel_wrap.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/parcel_wrap.yml @@ -45,8 +45,6 @@ abstract: true parent: BasePaperLabelable # We use this instead of BasePaperLabelableVisualized because WrappedParcel needs its own GenericVisualizer component for the parcel itself, and WrappedParcelHumanoid currently doesn't have label sprites at all id: BaseWrappedParcel - name: wrapped parcel - description: Something wrapped up in paper. I wonder what's inside... components: - type: Physics bodyType: Dynamic @@ -99,6 +97,8 @@ - type: entity parent: [ BaseItem, BaseWrappedParcel ] id: WrappedParcel + name: wrapped parcel + description: Something wrapped up in paper. I wonder what's inside... components: - type: Appearance - type: GenericVisualizer @@ -134,6 +134,7 @@ - type: entity parent: BaseWrappedParcel id: WrappedParcelHumanoid + name: wrapped parcel description: Something wrapped up in paper. It's suspiciously human-shaped. components: - type: Physics