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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user