Add supplies to restock vending machines. (#11506)
360
Content.IntegrationTests/Tests/VendingMachineRestockTest.cs
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Server.Storage.Components;
|
||||||
|
using Content.Server.VendingMachines;
|
||||||
|
using Content.Server.VendingMachines.Restock;
|
||||||
|
using Content.Server.Wires;
|
||||||
|
using Content.Shared.Cargo.Prototypes;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
using Content.Shared.VendingMachines;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
[TestOf(typeof(VendingMachineRestockComponent))]
|
||||||
|
[TestOf(typeof(VendingMachineRestockSystem))]
|
||||||
|
public sealed class VendingMachineRestockTest : EntitySystem
|
||||||
|
{
|
||||||
|
private const string Prototypes = @"
|
||||||
|
- type: entity
|
||||||
|
name: HumanDummy
|
||||||
|
id: HumanDummy
|
||||||
|
components:
|
||||||
|
- type: Hands
|
||||||
|
- type: Body
|
||||||
|
prototype: Human
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: FoodSnackBase
|
||||||
|
id: TestRamen
|
||||||
|
name: TestRamen
|
||||||
|
|
||||||
|
- type: vendingMachineInventory
|
||||||
|
id: TestInventory
|
||||||
|
startingInventory:
|
||||||
|
TestRamen: 1
|
||||||
|
|
||||||
|
- type: vendingMachineInventory
|
||||||
|
id: OtherTestInventory
|
||||||
|
startingInventory:
|
||||||
|
TestRamen: 3
|
||||||
|
|
||||||
|
- type: vendingMachineInventory
|
||||||
|
id: BigTestInventory
|
||||||
|
startingInventory:
|
||||||
|
TestRamen: 4
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: TestRestockWrong
|
||||||
|
name: TestRestockWrong
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- OtherTestInventory
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: TestRestockCorrect
|
||||||
|
name: TestRestockCorrect
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- TestInventory
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: TestRestockExplode
|
||||||
|
name: TestRestockExplode
|
||||||
|
components:
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Inorganic
|
||||||
|
damageModifierSet: Metallic
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 20
|
||||||
|
behaviors:
|
||||||
|
- !type:DumpRestockInventory
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ 'Destruction' ]
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- BigTestInventory
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: VendingMachine
|
||||||
|
id: VendingMachineTest
|
||||||
|
name: Test Ramen
|
||||||
|
components:
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: Vending
|
||||||
|
- type: VendingMachine
|
||||||
|
pack: TestInventory
|
||||||
|
- type: Sprite
|
||||||
|
sprite: error.rsi
|
||||||
|
";
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestAllRestocksAreAvailableToBuy()
|
||||||
|
{
|
||||||
|
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true});
|
||||||
|
var server = pairTracker.Pair.Server;
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
HashSet<string> restocks = new();
|
||||||
|
Dictionary<string, List<string>> restockStores = new();
|
||||||
|
|
||||||
|
// Collect all the prototypes with restock components.
|
||||||
|
foreach (var proto in prototypeManager.EnumeratePrototypes<EntityPrototype>())
|
||||||
|
{
|
||||||
|
if (proto.Abstract ||
|
||||||
|
!proto.TryGetComponent<VendingMachineRestockComponent>(out var restock))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
restocks.Add(proto.ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all the prototypes with StorageFills referencing those entities.
|
||||||
|
foreach (var proto in prototypeManager.EnumeratePrototypes<EntityPrototype>())
|
||||||
|
{
|
||||||
|
if (!proto.TryGetComponent<StorageFillComponent>(out var storage))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
List<string> restockStore = new();
|
||||||
|
foreach (var spawnEntry in storage.Contents)
|
||||||
|
{
|
||||||
|
if (spawnEntry.PrototypeId != null && restocks.Contains(spawnEntry.PrototypeId))
|
||||||
|
restockStore.Add(spawnEntry.PrototypeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restockStore.Count > 0)
|
||||||
|
restockStores.Add(proto.ID, restockStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through every CargoProduct and make sure each
|
||||||
|
// prototype with a restock component is referenced in a
|
||||||
|
// purchaseable entity with a StorageFill.
|
||||||
|
foreach (var proto in prototypeManager.EnumeratePrototypes<CargoProductPrototype>())
|
||||||
|
{
|
||||||
|
if (restockStores.ContainsKey(proto.Product))
|
||||||
|
{
|
||||||
|
foreach (var entry in restockStores[proto.Product])
|
||||||
|
restocks.Remove(entry);
|
||||||
|
|
||||||
|
restockStores.Remove(proto.Product);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.That(restockStores.Count, Is.EqualTo(0),
|
||||||
|
$"Some entities containing entities with VendingMachineRestock components are unavailable for purchase: \n - {string.Join("\n - ", restockStores.Keys)}");
|
||||||
|
|
||||||
|
Assert.That(restocks.Count, Is.EqualTo(0),
|
||||||
|
$"Some entities with VendingMachineRestock components are unavailable for purchase: \n - {string.Join("\n - ", restocks)}");
|
||||||
|
});
|
||||||
|
|
||||||
|
await pairTracker.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestCompleteRestockProcess()
|
||||||
|
{
|
||||||
|
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||||
|
var server = pairTracker.Pair.Server;
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
|
||||||
|
EntityUid packageRight;
|
||||||
|
EntityUid packageWrong;
|
||||||
|
EntityUid machine;
|
||||||
|
EntityUid user;
|
||||||
|
VendingMachineComponent machineComponent;
|
||||||
|
VendingMachineRestockComponent restockRightComponent;
|
||||||
|
VendingMachineRestockComponent restockWrongComponent;
|
||||||
|
WiresComponent machineWires;
|
||||||
|
|
||||||
|
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
var coordinates = testMap.GridCoords;
|
||||||
|
|
||||||
|
// Spawn the entities.
|
||||||
|
user = entityManager.SpawnEntity("HumanDummy", coordinates);
|
||||||
|
machine = entityManager.SpawnEntity("VendingMachineTest", coordinates);
|
||||||
|
packageRight = entityManager.SpawnEntity("TestRestockCorrect", coordinates);
|
||||||
|
packageWrong = entityManager.SpawnEntity("TestRestockWrong", coordinates);
|
||||||
|
|
||||||
|
// Sanity test for components existing.
|
||||||
|
Assert.True(entityManager.TryGetComponent(machine, out machineComponent!), $"Machine has no {nameof(VendingMachineComponent)}");
|
||||||
|
Assert.True(entityManager.TryGetComponent(packageRight, out restockRightComponent!), $"Correct package has no {nameof(VendingMachineRestockComponent)}");
|
||||||
|
Assert.True(entityManager.TryGetComponent(packageWrong, out restockWrongComponent!), $"Wrong package has no {nameof(VendingMachineRestockComponent)}");
|
||||||
|
Assert.True(entityManager.TryGetComponent(machine, out machineWires!), $"Machine has no {nameof(WiresComponent)}");
|
||||||
|
|
||||||
|
var systemRestock = entitySystemManager.GetEntitySystem<VendingMachineRestockSystem>();
|
||||||
|
var systemMachine = entitySystemManager.GetEntitySystem<VendingMachineSystem>();
|
||||||
|
|
||||||
|
// Test that the panel needs to be opened first.
|
||||||
|
Assert.That(systemRestock.TryAccessMachine(packageRight, restockRightComponent, machineComponent, user, machine), Is.False, "Right package is able to restock without opened access panel");
|
||||||
|
Assert.That(systemRestock.TryAccessMachine(packageWrong, restockWrongComponent, machineComponent, user, machine), Is.False, "Wrong package is able to restock without opened access panel");
|
||||||
|
|
||||||
|
// Open the panel.
|
||||||
|
machineWires.IsPanelOpen = true;
|
||||||
|
|
||||||
|
// Test that the right package works for the right machine.
|
||||||
|
Assert.That(systemRestock.TryAccessMachine(packageRight, restockRightComponent, machineComponent, user, machine), Is.True, "Correct package is unable to restock with access panel opened");
|
||||||
|
|
||||||
|
// Test that the wrong package does not work.
|
||||||
|
Assert.That(systemRestock.TryMatchPackageToMachine(packageWrong, restockWrongComponent, machineComponent, user, machine), Is.False, "Package with invalid canRestock is able to restock machine");
|
||||||
|
|
||||||
|
// Test that the right package does work.
|
||||||
|
Assert.That(systemRestock.TryMatchPackageToMachine(packageRight, restockRightComponent, machineComponent, user, machine), Is.True, "Package with valid canRestock is unable to restock machine");
|
||||||
|
|
||||||
|
// Make sure there's something in there to begin with.
|
||||||
|
Assert.That(systemMachine.GetAvailableInventory(machine, machineComponent).Count, Is.GreaterThan(0),
|
||||||
|
"Machine inventory is empty before emptying.");
|
||||||
|
|
||||||
|
// Empty the inventory.
|
||||||
|
systemMachine.EjectRandom(machine, false, true, machineComponent);
|
||||||
|
Assert.That(systemMachine.GetAvailableInventory(machine, machineComponent).Count, Is.EqualTo(0),
|
||||||
|
"Machine inventory is not empty after ejecting.");
|
||||||
|
|
||||||
|
// Test that the inventory is actually restocked.
|
||||||
|
systemMachine.TryRestockInventory(machine, machineComponent);
|
||||||
|
Assert.That(systemMachine.GetAvailableInventory(machine, machineComponent).Count, Is.GreaterThan(0),
|
||||||
|
"Machine available inventory count is not greater than zero after restock.");
|
||||||
|
|
||||||
|
mapManager.DeleteMap(testMap.MapId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await pairTracker.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestRestockBreaksOpen()
|
||||||
|
{
|
||||||
|
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||||
|
var server = pairTracker.Pair.Server;
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
|
||||||
|
var damageableSystem = entitySystemManager.GetEntitySystem<DamageableSystem>();
|
||||||
|
|
||||||
|
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||||
|
|
||||||
|
EntityUid restock = default;
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
var coordinates = testMap.GridCoords;
|
||||||
|
|
||||||
|
var totalStartingRamen = 0;
|
||||||
|
|
||||||
|
foreach (var meta in entityManager.EntityQuery<MetaDataComponent>())
|
||||||
|
if (!meta.Deleted && meta.EntityPrototype?.ID == "TestRamen")
|
||||||
|
totalStartingRamen++;
|
||||||
|
|
||||||
|
Assert.That(totalStartingRamen, Is.EqualTo(0),
|
||||||
|
"Did not start with zero ramen.");
|
||||||
|
|
||||||
|
restock = entityManager.SpawnEntity("TestRestockExplode", coordinates);
|
||||||
|
var damageSpec = new DamageSpecifier(prototypeManager.Index<DamageTypePrototype>("Blunt"), 100);
|
||||||
|
var damageResult = damageableSystem.TryChangeDamage(restock, damageSpec);
|
||||||
|
|
||||||
|
Assert.IsNotNull(damageResult,
|
||||||
|
"Received null damageResult when attempting to damage restock box.");
|
||||||
|
|
||||||
|
Assert.That((int) damageResult!.Total, Is.GreaterThan(0),
|
||||||
|
"Box damage result was not greater than 0.");
|
||||||
|
});
|
||||||
|
await server.WaitRunTicks(15);
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
Assert.That(entityManager.Deleted(restock),
|
||||||
|
"Restock box was not deleted after being damaged.");
|
||||||
|
|
||||||
|
var totalRamen = 0;
|
||||||
|
|
||||||
|
foreach (var meta in entityManager.EntityQuery<MetaDataComponent>())
|
||||||
|
if (!meta.Deleted && meta.EntityPrototype?.ID == "TestRamen")
|
||||||
|
totalRamen++;
|
||||||
|
|
||||||
|
Assert.That(totalRamen, Is.EqualTo(2),
|
||||||
|
"Did not find enough ramen after destroying restock box.");
|
||||||
|
|
||||||
|
mapManager.DeleteMap(testMap.MapId);
|
||||||
|
});
|
||||||
|
|
||||||
|
await pairTracker.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestRestockInventoryBounds()
|
||||||
|
{
|
||||||
|
await using var pairTracker = await PoolManager.GetServerClient(new PoolSettings{NoClient = true, ExtraPrototypes = Prototypes});
|
||||||
|
var server = pairTracker.Pair.Server;
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var entitySystemManager = server.ResolveDependency<IEntitySystemManager>();
|
||||||
|
|
||||||
|
var vendingMachineSystem = entitySystemManager.GetEntitySystem<SharedVendingMachineSystem>();
|
||||||
|
|
||||||
|
var testMap = await PoolManager.CreateTestMap(pairTracker);
|
||||||
|
|
||||||
|
await server.WaitAssertion(() =>
|
||||||
|
{
|
||||||
|
var coordinates = testMap.GridCoords;
|
||||||
|
|
||||||
|
EntityUid machine = entityManager.SpawnEntity("VendingMachineTest", coordinates);
|
||||||
|
|
||||||
|
Assert.That(vendingMachineSystem.GetAvailableInventory(machine).Count, Is.EqualTo(1),
|
||||||
|
"Machine's available inventory did not contain one entry.");
|
||||||
|
|
||||||
|
Assert.That(vendingMachineSystem.GetAvailableInventory(machine)[0].Amount, Is.EqualTo(1),
|
||||||
|
"Machine's available inventory is not the expected amount.");
|
||||||
|
|
||||||
|
vendingMachineSystem.RestockInventoryFromPrototype(machine);
|
||||||
|
|
||||||
|
Assert.That(vendingMachineSystem.GetAvailableInventory(machine)[0].Amount, Is.EqualTo(2),
|
||||||
|
"Machine's available inventory is not double its starting amount after a restock.");
|
||||||
|
|
||||||
|
vendingMachineSystem.RestockInventoryFromPrototype(machine);
|
||||||
|
|
||||||
|
Assert.That(vendingMachineSystem.GetAvailableInventory(machine)[0].Amount, Is.EqualTo(3),
|
||||||
|
"Machine's available inventory is not triple its starting amount after two restocks.");
|
||||||
|
|
||||||
|
vendingMachineSystem.RestockInventoryFromPrototype(machine);
|
||||||
|
|
||||||
|
Assert.That(vendingMachineSystem.GetAvailableInventory(machine)[0].Amount, Is.EqualTo(3),
|
||||||
|
"Machine's available inventory did not stay the same after a third restock.");
|
||||||
|
});
|
||||||
|
|
||||||
|
await pairTracker.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using Robust.Shared.Random;
|
||||||
|
using Content.Shared.Stacks;
|
||||||
|
using Content.Server.VendingMachines.Restock;
|
||||||
|
using Content.Shared.Prototypes;
|
||||||
|
using Content.Shared.VendingMachines;
|
||||||
|
|
||||||
|
namespace Content.Server.Destructible.Thresholds.Behaviors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Spawns a portion of the total items from one of the canRestock
|
||||||
|
/// inventory entries on a VendingMachineRestock component.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed class DumpRestockInventory: IThresholdBehavior
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The percent of each inventory entry that will be salvaged
|
||||||
|
/// upon destruction of the package.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("percent", required: true)]
|
||||||
|
public float Percent = 0.5f;
|
||||||
|
|
||||||
|
[DataField("offset")]
|
||||||
|
public float Offset { get; set; } = 0.5f;
|
||||||
|
|
||||||
|
public void Execute(EntityUid owner, DestructibleSystem system)
|
||||||
|
{
|
||||||
|
if (!system.EntityManager.TryGetComponent<VendingMachineRestockComponent>(owner, out var packagecomp) ||
|
||||||
|
!system.EntityManager.TryGetComponent<TransformComponent>(owner, out var xform))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var randomInventory = system.Random.Pick(packagecomp.CanRestock);
|
||||||
|
|
||||||
|
if (!system.PrototypeManager.TryIndex(randomInventory, out VendingMachineInventoryPrototype? packPrototype))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var (entityId, count) in packPrototype.StartingInventory)
|
||||||
|
{
|
||||||
|
var toSpawn = (int) Math.Round(count * Percent);
|
||||||
|
|
||||||
|
if (toSpawn == 0) continue;
|
||||||
|
|
||||||
|
if (EntityPrototypeHelpers.HasComponent<StackComponent>(entityId, system.PrototypeManager, system.ComponentFactory))
|
||||||
|
{
|
||||||
|
var spawned = system.EntityManager.SpawnEntity(entityId, xform.Coordinates.Offset(system.Random.NextVector2(-Offset, Offset)));
|
||||||
|
system.StackSystem.SetCount(spawned, toSpawn);
|
||||||
|
system.EntityManager.GetComponent<TransformComponent>(spawned).LocalRotation = system.Random.NextAngle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < toSpawn; i++)
|
||||||
|
{
|
||||||
|
var spawned = system.EntityManager.SpawnEntity(entityId, xform.Coordinates.Offset(system.Random.NextVector2(-Offset, Offset)));
|
||||||
|
system.EntityManager.GetComponent<TransformComponent>(spawned).LocalRotation = system.Random.NextAngle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
||||||
|
using Content.Shared.VendingMachines;
|
||||||
|
|
||||||
|
namespace Content.Server.VendingMachines.Restock
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed class VendingMachineRestockComponent : Component
|
||||||
|
{
|
||||||
|
public CancellationTokenSource? CancelToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time (in seconds) that it takes to restock a machine.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("restockDelay")]
|
||||||
|
public TimeSpan RestockDelay = TimeSpan.FromSeconds(8.0f);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What sort of machine inventory does this restock?
|
||||||
|
/// This is checked against the VendingMachineComponent's pack value.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("canRestock", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<VendingMachineInventoryPrototype>))]
|
||||||
|
public HashSet<string> CanRestock = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sound that plays when starting to restock a machine.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("soundRestockStart")]
|
||||||
|
public SoundSpecifier SoundRestockStart = new SoundPathSpecifier("/Audio/Machines/vending_restock_start.ogg");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sound that plays when finished restocking a machine.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("soundRestockDone")]
|
||||||
|
public SoundSpecifier SoundRestockDone = new SoundPathSpecifier("/Audio/Machines/vending_restock_done.ogg");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Content.Server.Cargo.Systems;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
|
using Content.Server.Wires;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.VendingMachines;
|
||||||
|
|
||||||
|
namespace Content.Server.VendingMachines.Restock
|
||||||
|
{
|
||||||
|
public sealed class VendingMachineRestockSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||||
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||||
|
[Dependency] private readonly PricingSystem _pricingSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<VendingMachineRestockComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<VendingMachineRestockComponent, PriceCalculationEvent>(OnPriceCalculation);
|
||||||
|
SubscribeLocalEvent<VendingMachineRestockComponent, RestockCancelledEvent>(OnRestockCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAccessMachine(EntityUid uid,
|
||||||
|
VendingMachineRestockComponent component,
|
||||||
|
VendingMachineComponent machineComponent,
|
||||||
|
EntityUid user,
|
||||||
|
EntityUid target)
|
||||||
|
{
|
||||||
|
if (!TryComp<WiresComponent>(target, out var wires) || !wires.IsPanelOpen) {
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("vending-machine-restock-needs-panel-open",
|
||||||
|
("this", uid),
|
||||||
|
("user", user),
|
||||||
|
("target", target)),
|
||||||
|
user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryMatchPackageToMachine(EntityUid uid,
|
||||||
|
VendingMachineRestockComponent component,
|
||||||
|
VendingMachineComponent machineComponent,
|
||||||
|
EntityUid user,
|
||||||
|
EntityUid target)
|
||||||
|
{
|
||||||
|
if (!component.CanRestock.Contains(machineComponent.PackPrototypeId)) {
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("vending-machine-restock-invalid-inventory",
|
||||||
|
("this", uid),
|
||||||
|
("user", user),
|
||||||
|
("target", target)
|
||||||
|
),
|
||||||
|
user);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAfterInteract(EntityUid uid, VendingMachineRestockComponent component, AfterInteractEvent args)
|
||||||
|
{
|
||||||
|
if (component.CancelToken != null || args.Target == null || !args.CanReach)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<VendingMachineComponent>(args.Target, out var machineComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryMatchPackageToMachine(uid, component, machineComponent, args.User, args.Target.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryAccessMachine(uid, component, machineComponent, args.User, args.Target.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.CancelToken = new CancellationTokenSource();
|
||||||
|
|
||||||
|
_doAfterSystem.DoAfter(new DoAfterEventArgs(
|
||||||
|
args.User,
|
||||||
|
(float) component.RestockDelay.TotalSeconds,
|
||||||
|
component.CancelToken.Token,
|
||||||
|
args.Target,
|
||||||
|
args.Used)
|
||||||
|
{
|
||||||
|
TargetFinishedEvent = new VendingMachineRestockEvent(args.User, uid),
|
||||||
|
UsedCancelledEvent = new RestockCancelledEvent(),
|
||||||
|
BreakOnTargetMove = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
BreakOnStun = true,
|
||||||
|
BreakOnDamage = true,
|
||||||
|
NeedHand = true
|
||||||
|
});
|
||||||
|
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("vending-machine-restock-start",
|
||||||
|
("this", uid),
|
||||||
|
("user", args.User),
|
||||||
|
("target", args.Target)
|
||||||
|
),
|
||||||
|
args.User,
|
||||||
|
PopupType.Medium);
|
||||||
|
|
||||||
|
_audioSystem.PlayPvs(component.SoundRestockStart, component.Owner,
|
||||||
|
AudioParams.Default
|
||||||
|
.WithVolume(-2f)
|
||||||
|
.WithVariation(0.2f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPriceCalculation(EntityUid uid, VendingMachineRestockComponent component, ref PriceCalculationEvent args)
|
||||||
|
{
|
||||||
|
List<double> priceSets = new();
|
||||||
|
|
||||||
|
// Find the most expensive inventory and use that as the highest price.
|
||||||
|
foreach (var vendingInventory in component.CanRestock)
|
||||||
|
{
|
||||||
|
double total = 0;
|
||||||
|
|
||||||
|
if (_prototypeManager.TryIndex(vendingInventory, out VendingMachineInventoryPrototype? inventoryPrototype))
|
||||||
|
{
|
||||||
|
foreach (var (item, amount) in inventoryPrototype.StartingInventory)
|
||||||
|
{
|
||||||
|
if (_prototypeManager.TryIndex(item, out EntityPrototype? entity))
|
||||||
|
total += _pricingSystem.GetEstimatedPrice(entity) * amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priceSets.Add(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.Price += priceSets.Max();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRestockCancelled(EntityUid uid, VendingMachineRestockComponent component, RestockCancelledEvent args)
|
||||||
|
{
|
||||||
|
component.CancelToken?.Cancel();
|
||||||
|
component.CancelToken = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct RestockCancelledEvent { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using Content.Server.Popups;
|
|||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Power.EntitySystems;
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
|
using Content.Server.VendingMachines.Restock;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
@@ -10,6 +11,7 @@ using Content.Shared.Actions.ActionTypes;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Destructible;
|
using Content.Shared.Destructible;
|
||||||
using Content.Shared.Emag.Systems;
|
using Content.Shared.Emag.Systems;
|
||||||
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Content.Shared.VendingMachines;
|
using Content.Shared.VendingMachines;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -51,6 +53,8 @@ namespace Content.Server.VendingMachines
|
|||||||
SubscribeLocalEvent<VendingMachineComponent, VendingMachineEjectMessage>(OnInventoryEjectMessage);
|
SubscribeLocalEvent<VendingMachineComponent, VendingMachineEjectMessage>(OnInventoryEjectMessage);
|
||||||
|
|
||||||
SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense);
|
SubscribeLocalEvent<VendingMachineComponent, VendingMachineSelfDispenseEvent>(OnSelfDispense);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<VendingMachineComponent, VendingMachineRestockEvent>(OnRestock);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnVendingPrice(EntityUid uid, VendingMachineComponent component, ref PriceCalculationEvent args)
|
private void OnVendingPrice(EntityUid uid, VendingMachineComponent component, ref PriceCalculationEvent args)
|
||||||
@@ -160,6 +164,31 @@ namespace Content.Server.VendingMachines
|
|||||||
EjectRandom(uid, throwItem: true, forceEject: false, component);
|
EjectRandom(uid, throwItem: true, forceEject: false, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnRestock(EntityUid uid, VendingMachineComponent component, VendingMachineRestockEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<VendingMachineRestockComponent>(args.RestockBox, out var restockComponent))
|
||||||
|
{
|
||||||
|
_sawmill.Error($"{ToPrettyString(args.User)} tried to restock {ToPrettyString(uid)} with {ToPrettyString(args.RestockBox)} which did not have a VendingMachineRestockComponent.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryRestockInventory(uid, component);
|
||||||
|
|
||||||
|
_popupSystem.PopupEntity(Loc.GetString("vending-machine-restock-done",
|
||||||
|
("this", args.RestockBox),
|
||||||
|
("user", args.User),
|
||||||
|
("target", uid)),
|
||||||
|
args.User,
|
||||||
|
PopupType.Medium);
|
||||||
|
|
||||||
|
_audioSystem.PlayPvs(restockComponent.SoundRestockDone, component.Owner,
|
||||||
|
AudioParams.Default
|
||||||
|
.WithVolume(-2f)
|
||||||
|
.WithVariation(0.2f));
|
||||||
|
|
||||||
|
Del(args.RestockBox);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the <see cref="VendingMachineComponent.CanShoot"/> property of the vending machine.
|
/// Sets the <see cref="VendingMachineComponent.CanShoot"/> property of the vending machine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -412,5 +441,29 @@ namespace Content.Server.VendingMachines
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TryRestockInventory(EntityUid uid, VendingMachineComponent? vendComponent = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref vendComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
RestockInventoryFromPrototype(uid, vendComponent);
|
||||||
|
|
||||||
|
UpdateVendingMachineInterfaceState(vendComponent);
|
||||||
|
TryUpdateVisualState(uid, vendComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class VendingMachineRestockEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid User { get; }
|
||||||
|
public EntityUid RestockBox { get; }
|
||||||
|
|
||||||
|
public VendingMachineRestockEvent(EntityUid user, EntityUid restockBox)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
RestockBox = restockBox;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ public abstract class SharedVendingMachineSystem : EntitySystem
|
|||||||
|
|
||||||
protected virtual void OnComponentInit(EntityUid uid, VendingMachineComponent component, ComponentInit args)
|
protected virtual void OnComponentInit(EntityUid uid, VendingMachineComponent component, ComponentInit args)
|
||||||
{
|
{
|
||||||
|
RestockInventoryFromPrototype(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RestockInventoryFromPrototype(EntityUid uid,
|
||||||
|
VendingMachineComponent? component = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref component))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(component.PackPrototypeId, out VendingMachineInventoryPrototype? packPrototype))
|
if (!_prototypeManager.TryIndex(component.PackPrototypeId, out VendingMachineInventoryPrototype? packPrototype))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -64,28 +75,38 @@ public abstract class SharedVendingMachineSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var inventory = new Dictionary<string, VendingMachineInventoryEntry>();
|
Dictionary<string, VendingMachineInventoryEntry> inventory;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case InventoryType.Regular:
|
||||||
|
inventory = component.Inventory;
|
||||||
|
break;
|
||||||
|
case InventoryType.Emagged:
|
||||||
|
inventory = component.EmaggedInventory;
|
||||||
|
break;
|
||||||
|
case InventoryType.Contraband:
|
||||||
|
inventory = component.ContrabandInventory;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (id, amount) in entries)
|
foreach (var (id, amount) in entries)
|
||||||
{
|
{
|
||||||
if (_prototypeManager.HasIndex<EntityPrototype>(id))
|
if (_prototypeManager.HasIndex<EntityPrototype>(id))
|
||||||
{
|
{
|
||||||
|
if (inventory.TryGetValue(id, out VendingMachineInventoryEntry? entry))
|
||||||
|
// Prevent a machine's stock from going over three times
|
||||||
|
// the prototype's normal amount. This is an arbitrary
|
||||||
|
// number and meant to be a convenience for someone
|
||||||
|
// restocking a machine who doesn't want to force vend out
|
||||||
|
// all the items just to restock one empty slot without
|
||||||
|
// losing the rest of the restock.
|
||||||
|
entry.Amount = Math.Min(entry.Amount + amount, 3 * amount);
|
||||||
|
else
|
||||||
inventory.Add(id, new VendingMachineInventoryEntry(type, id, amount));
|
inventory.Add(id, new VendingMachineInventoryEntry(type, id, amount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case InventoryType.Regular:
|
|
||||||
component.Inventory = inventory;
|
|
||||||
break;
|
|
||||||
case InventoryType.Emagged:
|
|
||||||
component.EmaggedInventory = inventory;
|
|
||||||
break;
|
|
||||||
case InventoryType.Contraband:
|
|
||||||
component.ContrabandInventory = inventory;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
- files: ["vending_restock_start.ogg"]
|
||||||
|
license: "CC0-1.0"
|
||||||
|
copyright: "https://freesound.org/people/Defaultv/"
|
||||||
|
source: "https://freesound.org/people/Defaultv/sounds/534362/"
|
||||||
|
|
||||||
|
- files: ["vending_restock_done.ogg"]
|
||||||
|
license: "CC-BY-3.0"
|
||||||
|
copyright: "https://freesound.org/people/felipelnv/"
|
||||||
|
source: "https://freesound.org/people/felipelnv/sounds/153298/"
|
||||||
|
|
||||||
- files: ["short_print_and_rip.ogg"]
|
- files: ["short_print_and_rip.ogg"]
|
||||||
license: "CC0-1.0"
|
license: "CC0-1.0"
|
||||||
copyright: "receipt printing.wav by 13F_Panska_Tlolkova_Matilda. This version is cleaned up, shortened, and converted to OGG."
|
copyright: "receipt printing.wav by 13F_Panska_Tlolkova_Matilda. This version is cleaned up, shortened, and converted to OGG."
|
||||||
|
|||||||
BIN
Resources/Audio/Machines/vending_restock_done.ogg
Normal file
BIN
Resources/Audio/Machines/vending_restock_start.ogg
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
ent-CrateVendingMachineRestockBooze = { ent-CrateVendingMachineRestockBoozeFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockBoozeFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockClothes = { ent-CrateVendingMachineRestockClothesFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockClothesFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockDinnerware = { ent-CrateVendingMachineRestockDinnerwareFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockDinnerwareFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockEngineering = { ent-CrateVendingMachineRestockEngineeringFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockEngineeringFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockGames = { ent-CrateVendingMachineRestockGamesFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockGamesFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockHotDrinks = { ent-CrateVendingMachineRestockHotDrinksFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockHotDrinksFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockMedical = { ent-CrateVendingMachineRestockMedicalFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockMedicalFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockNutriMax = { ent-CrateVendingMachineRestockNutriMaxFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockNutriMaxFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockPTech = { ent-CrateVendingMachineRestockPTechFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockPTechFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockRobustSoftdrinks = { ent-CrateVendingMachineRestockRobustSoftdrinksFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockRobustSoftdrinksFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSalvageEquipment = { ent-CrateVendingMachineRestockSalvageEquipmentFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockSalvageEquipmentFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSecTech = { ent-CrateVendingMachineRestockSecTechFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockSecTechFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSeeds = { ent-CrateVendingMachineRestockSeedsFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockSeedsFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSmokes = { ent-CrateVendingMachineRestockSmokesFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockSmokesFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSnacks = { ent-CrateVendingMachineRestockSnacksFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockSnacksFilled.desc }
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockTankDispenser = { ent-CrateVendingMachineRestockTankDispenserFilled }
|
||||||
|
.desc = { ent-CrateVendingMachineRestockTankDispenserFilled.desc }
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
ent-CrateVendingMachineRestockBoozeFilled = Booze-O-Mat restock crate
|
||||||
|
.desc = Contains a restock box for the Booze-O-Mat.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockClothesFilled = Clothing restock crate
|
||||||
|
.desc = Contains a pair of restock boxes, one for the ClothesMate and one for the AutoDrobe.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockDinnerwareFilled = Plasteel Chef restock crate
|
||||||
|
.desc = Contains a restock box for the Plasteel Chef vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockEngineeringFilled = EngiVend restock crate
|
||||||
|
.desc = Contains a restock box for the EngiVend. Also supports the YouTool.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockGamesFilled = Good Clean Fun restock crate
|
||||||
|
.desc = Contains a restock box for the Good Clean Fun vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockHotDrinksFilled = Solar's Best restock crate
|
||||||
|
.desc = Contains two restock boxes for Solar's Best Hot Drinks vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockMedicalFilled = NanoMed restock crate
|
||||||
|
.desc = Contains a restock box, compatible with the NanoMed and NanoMedPlus.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockNutriMaxFilled = NutriMax restock crate
|
||||||
|
.desc = Contains a restock box for the NutriMax vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockPTechFilled = PTech restock crate
|
||||||
|
.desc = Contains a restock box for the PTech bureaucracy dispenser.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockRobustSoftdrinksFilled = Robust Softdrinks restock crate
|
||||||
|
.desc = Contains two restock boxes for the Robust Softdrinks LLC vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSalvageEquipmentFilled = Salvage restock crate
|
||||||
|
.desc = Contains a restock box for the salvage vendor.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSecTechFilled = SecTech restock crate
|
||||||
|
.desc = Contains a restock box for the SecTech vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSeedsFilled = MegaSeed restock crate
|
||||||
|
.desc = Contains a restock box for the MegaSeed vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSmokesFilled = ShadyCigs restock crate
|
||||||
|
.desc = Contains two restock boxes for the ShadyCigs vending machine.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockSnacksFilled = Snack restock crate
|
||||||
|
.desc = Contains four restock boxes, each covering a different snack vendor. Mr. Chang's, Discount Dans, Robust Donuts, and Getmore Chocolate are featured on the advertisement.
|
||||||
|
|
||||||
|
ent-CrateVendingMachineRestockTankDispenserFilled = Tank dispenser restock crate
|
||||||
|
.desc = Contains a restock box for an Engineering or Atmospherics tank dispenser.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
vending-machine-restock-invalid-inventory = { CAPITALIZE(THE($this)) } isn't the right package to restock { THE($target) }.
|
||||||
|
vending-machine-restock-needs-panel-open = { CAPITALIZE($target) } needs { POSS-ADJ($target) } maintenance panel opened first.
|
||||||
|
vending-machine-restock-start = { $user } starts restocking { $target }.
|
||||||
|
vending-machine-restock-done = { $user } finishes restocking { $target }.
|
||||||
167
Resources/Prototypes/Catalog/Cargo/cargo_vending.yml
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# If you've arrived here after a failed NoCargoOrderArbitrage test, it's likely
|
||||||
|
# because the product in question contains a restock box which links to a
|
||||||
|
# vending machine inventory that has had items added to it recently and caused
|
||||||
|
# its calculated price to exceed the cost below.
|
||||||
|
#
|
||||||
|
# The costs will need to be kept in line with the inventory of the respective
|
||||||
|
# vending machines. An extra hundred or two profit margin should be fine.
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockBooze
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockBoozeFilled
|
||||||
|
cost: 3200
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockClothes
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockClothesFilled
|
||||||
|
cost: 4000
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockDinnerware
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockDinnerwareFilled
|
||||||
|
cost: 2000
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockEngineering
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockEngineeringFilled
|
||||||
|
cost: 3000
|
||||||
|
category: Engineering
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockGames
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockGamesFilled
|
||||||
|
cost: 650
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockHotDrinks
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockHotDrinksFilled
|
||||||
|
cost: 1200
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockMedical
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockMedicalFilled
|
||||||
|
cost: 1500
|
||||||
|
category: Medical
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockNutriMax
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockNutriMaxFilled
|
||||||
|
cost: 2400
|
||||||
|
category: Hydroponics
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockPTech
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockPTechFilled
|
||||||
|
cost: 800
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockRobustSoftdrinks
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockRobustSoftdrinksFilled
|
||||||
|
cost: 1200
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockSalvageEquipment
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockSalvageEquipmentFilled
|
||||||
|
cost: 1000
|
||||||
|
category: Engineering
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockSecTech
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockSecTechFilled
|
||||||
|
cost: 2200
|
||||||
|
category: Security
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockSeeds
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockSeedsFilled
|
||||||
|
cost: 2000
|
||||||
|
category: Hydroponics
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockSmokes
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockSmokesFilled
|
||||||
|
cost: 1200
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockSnacks
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockSnacksFilled
|
||||||
|
cost: 3000
|
||||||
|
category: Service
|
||||||
|
group: market
|
||||||
|
|
||||||
|
- type: cargoProduct
|
||||||
|
id: CrateVendingMachineRestockTankDispenser
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
product: CrateVendingMachineRestockTankDispenserFilled
|
||||||
|
cost: 1000
|
||||||
|
category: Atmospherics
|
||||||
|
group: market
|
||||||
134
Resources/Prototypes/Catalog/Fills/Crates/vending.yml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockBoozeFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockBooze
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockClothesFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockClothes
|
||||||
|
- id: VendingMachineRestockCostumes
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockDinnerwareFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockDinnerware
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockEngineeringFilled
|
||||||
|
parent: CrateEngineeringSecure
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockEngineering
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockGamesFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockGames
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockHotDrinksFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockHotDrinks
|
||||||
|
amount: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockMedicalFilled
|
||||||
|
parent: CrateMedicalSecure
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockMedical
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockNutriMaxFilled
|
||||||
|
parent: CrateHydroSecure
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockNutriMax
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockPTechFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockPTech
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockRobustSoftdrinksFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockRobustSoftdrinks
|
||||||
|
amount: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockSalvageEquipmentFilled
|
||||||
|
parent: CrateGenericSteel
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockSalvageEquipment
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockSecTechFilled
|
||||||
|
parent: CrateSecgear
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockSecTech
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockSeedsFilled
|
||||||
|
parent: CrateHydroSecure
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockSeeds
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockSmokesFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockSmokes
|
||||||
|
amount: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockSnacksFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockChang
|
||||||
|
- id: VendingMachineRestockDiscountDans
|
||||||
|
- id: VendingMachineRestockDonut
|
||||||
|
- id: VendingMachineRestockGetmoreChocolateCorp
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: CrateVendingMachineRestockTankDispenserFilled
|
||||||
|
parent: CratePlastic
|
||||||
|
components:
|
||||||
|
- type: StorageFill
|
||||||
|
contents:
|
||||||
|
- id: VendingMachineRestockTankDispenser
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
- type: entity
|
||||||
|
id: SpawnVendingMachineRestockFoodDrink
|
||||||
|
name: Vending Machine Restock
|
||||||
|
suffix: "food or drink"
|
||||||
|
parent: MarkerBase
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: green
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: refill_discount
|
||||||
|
- type: ConditionalSpawner
|
||||||
|
prototypes:
|
||||||
|
- VendingMachineRestockDiscountDans
|
||||||
|
- VendingMachineRestockChang
|
||||||
|
- VendingMachineRestockDonut
|
||||||
|
- VendingMachineRestockGetmoreChocolateCorp
|
||||||
|
- VendingMachineRestockRobustSoftdrinks
|
||||||
|
- VendingMachineRestockHotDrinks
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpawnVendingMachineRestockFood
|
||||||
|
name: Vending Machine Restock
|
||||||
|
suffix: "food"
|
||||||
|
parent: MarkerBase
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: green
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: refill_donuts
|
||||||
|
- type: ConditionalSpawner
|
||||||
|
prototypes:
|
||||||
|
- VendingMachineRestockDiscountDans
|
||||||
|
- VendingMachineRestockChang
|
||||||
|
- VendingMachineRestockDonut
|
||||||
|
- VendingMachineRestockGetmoreChocolateCorp
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpawnVendingMachineRestockDrink
|
||||||
|
name: Vending Machine Restock
|
||||||
|
suffix: "drink"
|
||||||
|
parent: MarkerBase
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: green
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: base
|
||||||
|
- sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
state: refill_cola
|
||||||
|
- type: ConditionalSpawner
|
||||||
|
prototypes:
|
||||||
|
- VendingMachineRestockRobustSoftdrinks
|
||||||
|
- VendingMachineRestockHotDrinks
|
||||||
@@ -0,0 +1,365 @@
|
|||||||
|
- type: entity
|
||||||
|
parent: BaseItem
|
||||||
|
id: BaseVendingMachineRestock
|
||||||
|
abstract: true
|
||||||
|
name: vending machine restock box
|
||||||
|
description: A box for restocking vending machines with corporate goodies.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Objects/Specific/Service/vending_machine_restock.rsi
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- type: ItemCooldown
|
||||||
|
- type: MeleeWeapon
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5
|
||||||
|
soundHit:
|
||||||
|
path: /Audio/Weapons/genhit2.ogg
|
||||||
|
soundSwing:
|
||||||
|
path: /Audio/Weapons/punchmiss.ogg
|
||||||
|
- type: Item
|
||||||
|
size: 50
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Inorganic
|
||||||
|
damageModifierSet: Metallic
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 20
|
||||||
|
behaviors:
|
||||||
|
- !type:PlaySoundBehavior
|
||||||
|
sound:
|
||||||
|
path: /Audio/Effects/metalbreak.ogg
|
||||||
|
- !type:DumpRestockInventory
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockBooze
|
||||||
|
name: Booze-O-Mat restock box
|
||||||
|
description: Slot into your Booze-O-Mat to start the party! Not for sale to passengers below the legal age.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- BoozeOMatInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_booze
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockChang
|
||||||
|
name: Mr. Chang's restock box
|
||||||
|
description: A box covered in white labels with bold red Chinese characters, ready to be loaded into the nearest Mr. Chang's vending machine.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- ChangInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_chinese
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockClothes
|
||||||
|
name: ClothesMate restock box
|
||||||
|
description: It's time to step up your fashion! Place inside the ClothesMate restock slot to begin.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- ClothesMateInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_clothes
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockCostumes
|
||||||
|
name: AutoDrobe restock box
|
||||||
|
description: A panoply of NanoTrasen employees are prancing about a colorful theater in a tragicomedy. You can join them too! Load this into your nearest AutoDrobe vending machine.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- AutoDrobeInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_costume
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockDinnerware
|
||||||
|
name: Plasteel Chef's restock box
|
||||||
|
description: It's never raw in this kitchen! Drop into the restock slot on the Plasteel Chef to begin.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- DinnerwareInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_dinner
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockDiscountDans
|
||||||
|
name: Discount Dan's restock box
|
||||||
|
description: A box full of salt and starch. Why suffer Quality when you can have Quantity? Discount Dan's!
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- DiscountDansInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_discount
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockDonut
|
||||||
|
name: Robust Donuts box
|
||||||
|
description: A box full of toroidal bundles of fried dough for restocking a vending machine. Use only as directed by Robust Industries, LLC.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- DonutInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_donuts
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockEngineering
|
||||||
|
name: EngiVend resupply box
|
||||||
|
description: Only to be used by certified professionals.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- EngiVendInventory
|
||||||
|
- YouToolInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_engi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockGames
|
||||||
|
name: Good Clean Fun restock box
|
||||||
|
description: It's time to roll for initiative, dice dragons! Load up at the Good Clean Fun vending machine!
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- GoodCleanFunInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_games
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockGetmoreChocolateCorp
|
||||||
|
name: GetMore Chocolate restock box
|
||||||
|
description: A box loaded with the finest ersatz cacao. Only to be used in official Getmore Chocolate vending machines.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- GetmoreChocolateCorpInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_snack
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockHotDrinks
|
||||||
|
name: Solar's Best restock box
|
||||||
|
description: Toasty! For use in Solar's Best Hot Drinks or other affiliate vending machines.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- HotDrinksMachineInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_joe
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockMedical
|
||||||
|
name: NanoMed resupply box
|
||||||
|
description: Slot into your department's NanoMed or NanoMedPlus to dispense. Handle with care.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- NanoMedInventory
|
||||||
|
- NanoMedPlusInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_medical
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockNutriMax
|
||||||
|
name: NutriMax restock box
|
||||||
|
description: We'll make your thumbs green with our tools. Let's get to harvesting! Load into a NutriMax vending machine.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- NutriMaxInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_plant
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockPTech
|
||||||
|
name: PTech resupply box
|
||||||
|
description: All the bureaucracy you can handle, and more! Load into the PTech vending machine to get started.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- PTechInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_ptech
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockRobustSoftdrinks
|
||||||
|
name: Robust Softdrinks box
|
||||||
|
description: A cold, clunky container of colliding chilly cylinders. Use only as directed by Robust Industries, LLC.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- RobustSoftdrinksInventory
|
||||||
|
- BodaInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_cola
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockSecTech
|
||||||
|
name: SecTech resupply box
|
||||||
|
description: "Communists beware: the reinforcements have arrived! A label reads SECURITY PERSONNEL ONLY."
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- SecTechInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_sec
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockSalvageEquipment
|
||||||
|
name: salvage resupply box
|
||||||
|
description: Strike the earth ere the space carp nip your behind! Slam into a salvage vendor to begin.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- SalvageEquipmentInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_salvage
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockSeeds
|
||||||
|
name: MegaSeed restock box
|
||||||
|
description: A label says they're heirloom seeds, passed down from our ancestors. Pack it into the MegaSeed Servitor!
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- MegaSeedServitorInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_plant
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockSmokes
|
||||||
|
name: ShadyCigs restock box
|
||||||
|
description: It's hard to see anything under all the Surgeon General warnings, but it mentions loading it into a vending machine.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- CigaretteMachineInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_smoke
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: BaseVendingMachineRestock
|
||||||
|
id: VendingMachineRestockTankDispenser
|
||||||
|
name: tank dispenser resupply box
|
||||||
|
description: Capable of replacing tanks in a gas tank dispenser. Handle with care.
|
||||||
|
components:
|
||||||
|
- type: VendingMachineRestock
|
||||||
|
canRestock:
|
||||||
|
- TankDispenserEVAInventory
|
||||||
|
- TankDispenserEngineeringInventory
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: base
|
||||||
|
- state: green_bit
|
||||||
|
shader: unshaded
|
||||||
|
- state: refill_tanks
|
||||||
|
After Width: | Height: | Size: 241 B |
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 171 B |
|
After Width: | Height: | Size: 172 B |
@@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "Original source: https://github.com/tgstation/tgstation/blob/master/icons/obj/vending_restock.dmi @ commit 014c44ef6279beb02a5f3e76824439fa57181c22 - Additions and cleanup by @Vordenburg",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "base"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "inhand-left",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "inhand-right",
|
||||||
|
"directions": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "green_bit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_booze"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_chinese"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_clothes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_cola"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_costume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_dinner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_discount"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_donksoft"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_donuts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_engi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_games"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_joe"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_medical"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_parts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_plant"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_ptech"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_salvage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_sec"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_smoke"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_snack"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "refill_tanks"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 215 B |
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 303 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 257 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 221 B |
|
After Width: | Height: | Size: 202 B |
|
After Width: | Height: | Size: 253 B |
|
After Width: | Height: | Size: 276 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 373 B |
|
After Width: | Height: | Size: 245 B |
|
After Width: | Height: | Size: 244 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 209 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 230 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 184 B |
|
After Width: | Height: | Size: 232 B |