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 Content.Shared.Power; using Robust.Shared.Audio; using Robust.Shared.Random; using Robust.Shared.Utility; namespace Content.Server.Cargo.Systems; 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(); while (query.MoveNext(out var uid, out var comp)) { // Don't EntityQuery for it as it's not required. TryComp(uid, out var appearance); if (comp.CurrentState == CargoTelepadState.Unpowered) { comp.CurrentState = CargoTelepadState.Idle; _appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Idle, appearance); comp.Accumulator = comp.Delay; continue; } comp.Accumulator -= frameTime; // Uhh listen teleporting takes time and I just want the 1 float. if (comp.Accumulator > 0f) { comp.CurrentState = CargoTelepadState.Idle; _appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Idle, appearance); continue; } if (comp.CurrentOrders.Count == 0) { comp.Accumulator += comp.Delay; continue; } var xform = Transform(uid); var currentOrder = comp.CurrentOrders.First(); if (FulfillOrder(currentOrder, xform.Coordinates, comp.PrinterOutput)) { _audio.PlayPvs(_audio.ResolveSound(comp.TeleportSound), uid, AudioParams.Default.WithVolume(-8f)); if (_station.GetOwningStation(uid) is { } station) UpdateOrders(station); comp.CurrentOrders.Remove(currentOrder); comp.CurrentState = CargoTelepadState.Teleporting; _appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Teleporting, appearance); } comp.Accumulator += comp.Delay; } } private void OnInit(EntityUid uid, CargoTelepadComponent telepad, ComponentInit args) { _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) { // False due to AllCompsOneEntity test where they may not have the powerreceiver. if (!Resolve(uid, ref receiver, ref xform, false)) return; var disabled = !receiver.Powered || !xform.Anchored; // Setting idle state should be handled by Update(); if (disabled) return; TryComp(uid, out var appearance); component.CurrentState = CargoTelepadState.Unpowered; _appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Unpowered, appearance); } private void OnTelepadPowerChange(EntityUid uid, CargoTelepadComponent component, ref PowerChangedEvent args) { SetEnabled(uid, component); } private void OnTelepadAnchorChange(EntityUid uid, CargoTelepadComponent component, ref AnchorStateChangedEvent args) { SetEnabled(uid, component); } }