Add trade stations (#23863)

* puters

* Start on fulfillment

* weh

* Smol update

* FTL sound fixes or smth iunno

* Add consoles

* More tweaks

* Make it unanchorable

* final wehs

* weh

* Fix 1 test

* Shrimply bump the distance

* cat
This commit is contained in:
metalgearsloth
2024-01-19 13:02:28 +11:00
committed by GitHub
parent f69f3e0f41
commit a7388e5c05
17 changed files with 2413 additions and 2188 deletions

View File

@@ -1,39 +1,27 @@
using System.Linq;
using Content.Server.Cargo.Components;
using Content.Server.GameTicking.Events;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Shared.Stacks;
using Content.Shared.Cargo;
using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Components;
using Content.Shared.Cargo.Events;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Whitelist;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using Content.Shared.Coordinates;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Robust.Shared.Audio;
namespace Content.Server.Cargo.Systems;
public sealed partial class CargoSystem
{
/*
* Handles cargo shuttle mechanics.
* Handles cargo shuttle / trade mechanics.
*/
public MapId? CargoMap { get; private set; }
private static readonly SoundPathSpecifier ApproveSound = new("/Audio/Effects/Cargo/ping.ogg");
private void InitializeShuttle()
{
SubscribeLocalEvent<CargoShuttleComponent, FTLStartedEvent>(OnCargoFTLStarted);
SubscribeLocalEvent<CargoShuttleComponent, FTLCompletedEvent>(OnCargoFTLCompleted);
SubscribeLocalEvent<CargoShuttleComponent, FTLTagEvent>(OnCargoFTLTag);
SubscribeLocalEvent<TradeStationComponent, GridSplitEvent>(OnTradeSplit);
SubscribeLocalEvent<CargoShuttleConsoleComponent, ComponentStartup>(OnCargoShuttleConsoleStartup);
@@ -42,32 +30,6 @@ public sealed partial class CargoSystem
SubscribeLocalEvent<CargoPalletConsoleComponent, BoundUIOpenedEvent>(OnPalletUIOpen);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
_cfgManager.OnValueChanged(CCVars.GridFill, SetGridFill);
}
private void ShutdownShuttle()
{
_cfgManager.UnsubValueChanged(CCVars.GridFill, SetGridFill);
}
private void SetGridFill(bool obj)
{
if (obj)
{
SetupCargoShuttle();
}
}
private void OnCargoFTLTag(EntityUid uid, CargoShuttleComponent component, ref FTLTagEvent args)
{
if (args.Handled)
return;
// Just saves mappers forgetting.
args.Handled = true;
args.Tag = "DockCargo";
}
#region Console
@@ -156,6 +118,15 @@ public sealed partial class CargoSystem
#endregion
private void OnTradeSplit(EntityUid uid, TradeStationComponent component, ref GridSplitEvent args)
{
// If the trade station gets bombed it's still a trade station.
foreach (var gridUid in args.NewGrids)
{
EnsureComp<TradeStationComponent>(gridUid);
}
}
#region Shuttle
/// <summary>
@@ -206,9 +177,9 @@ public sealed partial class CargoSystem
return space;
}
private List<(EntityUid Entity, CargoPalletComponent Component)> GetCargoPallets(EntityUid gridUid)
private List<(EntityUid Entity, CargoPalletComponent Component, TransformComponent PalletXform)> GetCargoPallets(EntityUid gridUid)
{
var pads = new List<(EntityUid, CargoPalletComponent)>();
_pads.Clear();
var query = AllEntityQuery<CargoPalletComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var comp, out var compXform))
@@ -219,23 +190,43 @@ public sealed partial class CargoSystem
continue;
}
pads.Add((uid, comp));
_pads.Add((uid, comp, compXform));
}
return pads;
return _pads;
}
private IEnumerable<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)>
GetFreeCargoPallets(EntityUid gridUid,
List<(EntityUid Entity, CargoPalletComponent Component, TransformComponent Transform)> pallets)
{
_setEnts.Clear();
foreach (var pallet in pallets)
{
var aabb = _lookup.GetAABBNoContainer(pallet.Entity, pallet.Transform.LocalPosition, pallet.Transform.LocalRotation);
if (_lookup.AnyLocalEntitiesIntersecting(gridUid, aabb, LookupFlags.Dynamic))
continue;
yield return pallet;
}
}
#endregion
#region Station
private void SellPallets(EntityUid gridUid, EntityUid? station, out double amount)
private bool SellPallets(EntityUid gridUid, EntityUid? station, out double amount)
{
station ??= _station.GetOwningStation(gridUid);
GetPalletGoods(gridUid, out var toSell, out amount);
Log.Debug($"Cargo sold {toSell.Count} entities for {amount}");
if (toSell.Count == 0)
return false;
if (station != null)
{
var ev = new EntitySoldEvent(station.Value, toSell);
@@ -246,6 +237,8 @@ public sealed partial class CargoSystem
{
Del(ent);
}
return true;
}
private void GetPalletGoods(EntityUid gridUid, out HashSet<EntityUid> toSell, out double amount)
@@ -253,10 +246,15 @@ public sealed partial class CargoSystem
amount = 0;
toSell = new HashSet<EntityUid>();
foreach (var (palletUid, _) in GetCargoPallets(gridUid))
foreach (var (palletUid, _, _) in GetCargoPallets(gridUid))
{
// Containers should already get the sell price of their children so can skip those.
foreach (var ent in _lookup.GetEntitiesIntersecting(palletUid, LookupFlags.Dynamic | LookupFlags.Sundries | LookupFlags.Approximate))
_setEnts.Clear();
_lookup.GetEntitiesIntersecting(palletUid, _setEnts,
LookupFlags.Dynamic | LookupFlags.Sundries);
foreach (var ent in _setEnts)
{
// Dont sell:
// - anything already being sold
@@ -304,21 +302,6 @@ public sealed partial class CargoSystem
return true;
}
private void AddCargoContents(EntityUid shuttleUid, CargoShuttleComponent shuttle, StationCargoOrderDatabaseComponent orderDatabase)
{
var xformQuery = GetEntityQuery<TransformComponent>();
var pads = GetCargoPallets(shuttleUid);
while (pads.Count > 0)
{
var coordinates = new EntityCoordinates(shuttleUid, xformQuery.GetComponent(_random.PickAndTake(pads).Entity).LocalPosition);
if (!FulfillOrder(orderDatabase, coordinates, shuttle.PrinterOutput))
{
break;
}
}
}
private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletSellMessage args)
{
var player = args.Session.AttachedEntity;
@@ -327,114 +310,29 @@ public sealed partial class CargoSystem
return;
var bui = _uiSystem.GetUi(uid, CargoPalletConsoleUiKey.Sale);
if (Transform(uid).GridUid is not EntityUid gridUid)
var xform = Transform(uid);
if (xform.GridUid is not EntityUid gridUid)
{
_uiSystem.SetUiState(bui,
new CargoPalletConsoleInterfaceState(0, 0, false));
return;
}
SellPallets(gridUid, null, out var price);
if (!SellPallets(gridUid, null, out var price))
return;
var stackPrototype = _protoMan.Index<StackPrototype>(component.CashType);
_stack.Spawn((int) price, stackPrototype, uid.ToCoordinates());
_stack.Spawn((int) price, stackPrototype, xform.Coordinates);
_audio.PlayPvs(ApproveSound, uid);
UpdatePalletConsoleInterface(uid);
}
private void OnCargoFTLStarted(EntityUid uid, CargoShuttleComponent component, ref FTLStartedEvent args)
{
var stationUid = _station.GetOwningStation(uid);
// Called
if (CargoMap == null ||
args.FromMapUid != _mapManager.GetMapEntityId(CargoMap.Value) ||
!TryComp<StationCargoOrderDatabaseComponent>(stationUid, out var orderDatabase))
{
return;
}
AddCargoContents(uid, component, orderDatabase);
UpdateOrders(stationUid!.Value, orderDatabase);
UpdateCargoShuttleConsoles(uid, component);
}
private void OnCargoFTLCompleted(EntityUid uid, CargoShuttleComponent component, ref FTLCompletedEvent args)
{
var xform = Transform(uid);
// Recalled
if (xform.MapID != CargoMap)
return;
var stationUid = _station.GetOwningStation(uid);
if (TryComp<StationBankAccountComponent>(stationUid, out var bank))
{
SellPallets(uid, stationUid, out var amount);
bank.Balance += (int) amount;
}
}
#endregion
private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
Reset();
CleanupCargoShuttle();
}
private void OnRoundStart(RoundStartingEvent ev)
{
if (_cfgManager.GetCVar(CCVars.GridFill))
SetupCargoShuttle();
}
private void CleanupCargoShuttle()
{
if (CargoMap == null || !_mapManager.MapExists(CargoMap.Value))
{
CargoMap = null;
DebugTools.Assert(!EntityQuery<CargoShuttleComponent>().Any());
return;
}
_mapManager.DeleteMap(CargoMap.Value);
CargoMap = null;
// Shuttle may not have been in the cargo dimension (e.g. on the station map) so need to delete.
var query = AllEntityQuery<CargoShuttleComponent>();
while (query.MoveNext(out var uid, out var _))
{
if (TryComp<StationCargoOrderDatabaseComponent>(uid, out var station))
{
station.Shuttle = null;
}
QueueDel(uid);
}
}
private void SetupCargoShuttle()
{
if (CargoMap != null && _mapManager.MapExists(CargoMap.Value))
{
return;
}
// It gets mapinit which is okay... buuutt we still want it paused to avoid power draining.
CargoMap = _mapManager.CreateMap();
var mapUid = _mapManager.GetMapEntityId(CargoMap.Value);
var ftl = EnsureComp<FTLDestinationComponent>(_mapManager.GetMapEntityId(CargoMap.Value));
ftl.Whitelist = new EntityWhitelist()
{
Components = new[]
{
_factory.GetComponentName(typeof(CargoShuttleComponent))
}
};
_metaSystem.SetEntityName(mapUid, $"Trading post {_random.Next(1000):000}");
_console.RefreshShuttleConsoles();
}
}