diff --git a/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs b/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs
index c30db08bbe..2e3b2c2115 100644
--- a/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs
+++ b/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs
@@ -1,4 +1,6 @@
+using Content.Server.Station.Components;
using Content.Shared.Cargo;
+using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Prototypes;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -38,3 +40,17 @@ public sealed partial class StationCargoOrderDatabaseComponent : Component
[DataField]
public EntProtoId PrinterOutput = "PaperCargoInvoice";
}
+
+///
+/// Event broadcast before a cargo order is fulfilled, allowing alternate systems to fulfill the order.
+///
+[ByRefEvent]
+public record struct FulfillCargoOrderEvent(Entity Station, CargoOrderData Order, Entity OrderConsole)
+{
+ public Entity OrderConsole = OrderConsole;
+ public Entity Station = Station;
+ public CargoOrderData Order = Order;
+
+ public EntityUid? FulfillmentEntity;
+ public bool Handled = false;
+}
diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs
index 7a81e1a424..13a1d3d565 100644
--- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs
+++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs
@@ -170,13 +170,20 @@ namespace Content.Server.Cargo.Systems
return;
}
- var tradeDestination = TryFulfillOrder(stationData, order, orderDatabase);
+ var ev = new FulfillCargoOrderEvent((station.Value, stationData), order, (uid, component));
+ RaiseLocalEvent(ref ev);
+ ev.FulfillmentEntity ??= station.Value;
- if (tradeDestination == null)
+ if (!ev.Handled)
{
- ConsolePopup(args.Session, Loc.GetString("cargo-console-unfulfilled"));
- PlayDenySound(uid, component);
- return;
+ ev.FulfillmentEntity = TryFulfillOrder((station.Value, stationData), order, orderDatabase);
+
+ if (ev.FulfillmentEntity == null)
+ {
+ ConsolePopup(args.Session, Loc.GetString("cargo-console-unfulfilled"));
+ PlayDenySound(uid, component);
+ return;
+ }
}
_idCardSystem.TryFindIdCard(player, out var idCard);
@@ -186,14 +193,14 @@ namespace Content.Server.Cargo.Systems
var approverName = idCard.Comp?.FullName ?? Loc.GetString("access-reader-unknown-id");
var approverJob = idCard.Comp?.JobTitle ?? Loc.GetString("access-reader-unknown-id");
- var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast",
+ var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast",
("productName", Loc.GetString(order.ProductName)),
("orderAmount", order.OrderQuantity),
("approverName", approverName),
("approverJob", approverJob),
("cost", cost));
_radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false);
- ConsolePopup(args.Session, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(tradeDestination.Value).EntityName)));
+ ConsolePopup(args.Session, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(ev.FulfillmentEntity.Value).EntityName)));
// Log order approval
_adminLogger.Add(LogType.Action, LogImpact.Low,
@@ -201,10 +208,10 @@ namespace Content.Server.Cargo.Systems
orderDatabase.Orders.Remove(order);
DeductFunds(bank, cost);
- UpdateOrders(station.Value, orderDatabase);
+ UpdateOrders(station.Value);
}
- private EntityUid? TryFulfillOrder(StationDataComponent stationData, CargoOrderData order, StationCargoOrderDatabaseComponent orderDatabase)
+ private EntityUid? TryFulfillOrder(Entity stationData, CargoOrderData order, StationCargoOrderDatabaseComponent orderDatabase)
{
// No slots at the trade station
_listEnts.Clear();
@@ -357,7 +364,7 @@ namespace Content.Server.Cargo.Systems
/// Updates all of the cargo-related consoles for a particular station.
/// This should be called whenever orders change.
///
- private void UpdateOrders(EntityUid dbUid, StationCargoOrderDatabaseComponent _)
+ private void UpdateOrders(EntityUid dbUid)
{
// Order added so all consoles need updating.
var orderQuery = AllEntityQuery();
@@ -392,7 +399,7 @@ namespace Content.Server.Cargo.Systems
string description,
string dest,
StationCargoOrderDatabaseComponent component,
- StationDataComponent stationData
+ Entity stationData
)
{
DebugTools.Assert(_protoMan.HasIndex(spawnId));
@@ -414,7 +421,7 @@ namespace Content.Server.Cargo.Systems
private bool TryAddOrder(EntityUid dbUid, CargoOrderData data, StationCargoOrderDatabaseComponent component)
{
component.Orders.Add(data);
- UpdateOrders(dbUid, component);
+ UpdateOrders(dbUid);
return true;
}
@@ -432,7 +439,7 @@ namespace Content.Server.Cargo.Systems
{
orderDB.Orders.RemoveAt(sequenceIdx);
}
- UpdateOrders(dbUid, orderDB);
+ UpdateOrders(dbUid);
}
public void ClearOrders(StationCargoOrderDatabaseComponent component)
diff --git a/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
index 42aabf2578..f83ec1a512 100644
--- a/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
+++ b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs
@@ -1,9 +1,13 @@
+using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.Power.Components;
+using Content.Server.Power.EntitySystems;
+using Content.Server.Station.Components;
using Content.Shared.Cargo;
using Content.Shared.Cargo.Components;
using Content.Shared.DeviceLinking;
using Robust.Shared.Audio;
+using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Cargo.Systems;
@@ -13,10 +17,44 @@ public sealed partial class CargoSystem
private void InitializeTelepad()
{
SubscribeLocalEvent(OnInit);
+ SubscribeLocalEvent(OnShutdown);
SubscribeLocalEvent(OnTelepadPowerChange);
// Shouldn't need re-anchored event
SubscribeLocalEvent(OnTelepadAnchorChange);
+ SubscribeLocalEvent(OnTelepadFulfillCargoOrder);
}
+
+ private void OnTelepadFulfillCargoOrder(ref FulfillCargoOrderEvent args)
+ {
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var tele, out var xform))
+ {
+ if (tele.CurrentState != CargoTelepadState.Idle)
+ continue;
+
+ if (!this.IsPowered(uid, EntityManager))
+ continue;
+
+ if (_station.GetOwningStation(uid, xform) != args.Station)
+ continue;
+
+ // todo cannot be fucking asked to figure out device linking rn but this shouldn't just default to the first port.
+ if (!TryComp(uid, out var sinkComponent) ||
+ sinkComponent.LinkedSources.FirstOrNull() is not { } console ||
+ console != args.OrderConsole.Owner)
+ continue;
+
+ for (var i = 0; i < args.Order.OrderQuantity; i++)
+ {
+ tele.CurrentOrders.Add(args.Order);
+ }
+ tele.Accumulator = tele.Delay;
+ args.Handled = true;
+ args.FulfillmentEntity = uid;
+ return;
+ }
+ }
+
private void UpdateTelepad(float frameTime)
{
var query = EntityQueryEnumerator();
@@ -33,14 +71,6 @@ public sealed partial class CargoSystem
continue;
}
- if (!TryComp(uid, out var sinkComponent) ||
- sinkComponent.LinkedSources.FirstOrNull() is not { } console ||
- !HasComp(console))
- {
- comp.Accumulator = comp.Delay;
- continue;
- }
-
comp.Accumulator -= frameTime;
// Uhh listen teleporting takes time and I just want the 1 float.
@@ -51,21 +81,22 @@ public sealed partial class CargoSystem
continue;
}
- var station = _station.GetOwningStation(console);
-
- if (!TryComp(station, out var orderDatabase) ||
- orderDatabase.Orders.Count == 0)
+ if (comp.CurrentOrders.Count == 0)
{
comp.Accumulator += comp.Delay;
continue;
}
var xform = Transform(uid);
- if (FulfillNextOrder(orderDatabase, xform.Coordinates, comp.PrinterOutput))
+ var currentOrder = comp.CurrentOrders.First();
+ if (FulfillOrder(currentOrder, xform.Coordinates, comp.PrinterOutput))
{
_audio.PlayPvs(_audio.GetSound(comp.TeleportSound), uid, AudioParams.Default.WithVolume(-8f));
- UpdateOrders(station.Value, orderDatabase);
+ if (_station.GetOwningStation(uid) is { } station)
+ UpdateOrders(station);
+
+ comp.CurrentOrders.Remove(currentOrder);
comp.CurrentState = CargoTelepadState.Teleporting;
_appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Teleporting, appearance);
}
@@ -79,6 +110,29 @@ public sealed partial class CargoSystem
_linker.EnsureSinkPorts(uid, telepad.ReceiverPort);
}
+ private void OnShutdown(Entity ent, ref ComponentShutdown args)
+ {
+ if (ent.Comp.CurrentOrders.Count == 0)
+ return;
+
+ if (_station.GetStations().Count == 0)
+ return;
+
+ if (_station.GetOwningStation(ent) is not { } station)
+ {
+ station = _random.Pick(_station.GetStations().Where(HasComp).ToList());
+ }
+
+ if (!TryComp(station, out var db) ||
+ !TryComp(station, out var data))
+ return;
+
+ foreach (var order in ent.Comp.CurrentOrders)
+ {
+ TryFulfillOrder((station, data), order, db);
+ }
+ }
+
private void SetEnabled(EntityUid uid, CargoTelepadComponent component, ApcPowerReceiverComponent? receiver = null,
TransformComponent? xform = null)
{
diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs
index 194786fca7..0c8c9b6dc5 100644
--- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs
+++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs
@@ -69,7 +69,7 @@ public sealed class CargoGiftsRule : StationEventSystem
Loc.GetString(component.Description),
Loc.GetString(component.Dest),
cargoDb,
- stationData!
+ (station.Value, stationData)
))
{
break;
diff --git a/Content.Shared/Cargo/CargoOrderData.cs b/Content.Shared/Cargo/CargoOrderData.cs
index 831010cedd..ce05d92236 100644
--- a/Content.Shared/Cargo/CargoOrderData.cs
+++ b/Content.Shared/Cargo/CargoOrderData.cs
@@ -1,47 +1,55 @@
using Robust.Shared.Serialization;
-using Content.Shared.Access.Components;
using System.Text;
namespace Content.Shared.Cargo
{
- [NetSerializable, Serializable]
- public sealed class CargoOrderData
+ [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.
///
- public readonly int OrderId;
+ [DataField]
+ public int OrderId { get; private set; }
///
/// Prototype Id for the item to be created
///
- public readonly string ProductId;
+ [DataField]
+ public string ProductId { get; private set; }
///
/// Prototype Name
///
- public readonly string ProductName;
+ [DataField]
+ public string ProductName { get; private set; }
///
/// The number of items in the order. Not readonly, as it might change
/// due to caps on the amount of orders that can be placed.
///
+ [DataField]
public int OrderQuantity;
///
/// How many instances of this order that we've already dispatched
///
+ [DataField]
public int NumDispatched = 0;
- public readonly string Requester;
+ [DataField]
+ public string Requester { get; private set; }
// public String RequesterRank; // TODO Figure out how to get Character ID card data
// public int RequesterId;
- public readonly string Reason;
+ [DataField]
+ public string Reason { get; private set; }
public bool Approved => Approver is not null;
+ [DataField]
public string? Approver;
public CargoOrderData(int orderId, string productId, string productName, int price, int amount, string requester, string reason)
diff --git a/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs b/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs
index 911ea41cca..5bc3934768 100644
--- a/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs
+++ b/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs
@@ -12,11 +12,14 @@ namespace Content.Shared.Cargo.Components;
[RegisterComponent, NetworkedComponent, Access(typeof(SharedCargoSystem))]
public sealed partial class CargoTelepadComponent : Component
{
+ [DataField]
+ public List CurrentOrders = new();
+
///
/// The actual amount of time it takes to teleport from the telepad
///
[DataField("delay"), ViewVariables(VVAccess.ReadWrite)]
- public float Delay = 10f;
+ public float Delay = 5f;
///
/// How much time we've accumulated until next teleport.
diff --git a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml
index d395235a53..9dc9f77cff 100644
--- a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml
+++ b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml
@@ -47,3 +47,5 @@
board: CargoTelepadMachineCircuitboard
- type: Appearance
- type: CollideOnAnchor
+ - type: NameIdentifier
+ group: CargoTelepads
diff --git a/Resources/Prototypes/name_identifier_groups.yml b/Resources/Prototypes/name_identifier_groups.yml
index 82c2f3bce9..4823e31f55 100644
--- a/Resources/Prototypes/name_identifier_groups.yml
+++ b/Resources/Prototypes/name_identifier_groups.yml
@@ -37,3 +37,9 @@
id: Bounty
minValue: 0
maxValue: 999
+
+- type: nameIdentifierGroup
+ id: CargoTelepads
+ prefix: TELE
+ minValue: 0
+ maxValue: 999