using Content.Server._CP14.Currency; using Content.Server.Shuttles.Systems; using Content.Server.Station.Events; using Content.Server.Station.Systems; using Content.Shared._CP14.Currency; using Content.Shared._CP14.Cargo; using Content.Shared._CP14.Cargo.Prototype; using Content.Shared.Maps; using Content.Shared.Paper; using Content.Shared.Physics; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Server._CP14.Cargo; public sealed partial class CP14CargoSystem : CP14SharedCargoSystem { [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly ShuttleSystem _shuttles = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly UserInterfaceSystem _userInterface = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly CP14CurrencySystem _currency = default!; [Dependency] private readonly SharedStorageSystem _storage = default!; [Dependency] private readonly TurfSystem _turf = default!; private EntityQuery _xformQuery; private IEnumerable? _buyProto; private IEnumerable? _sellProto; public override void Initialize() { base.Initialize(); InitializeUI(); InitializeShuttle(); _xformQuery = GetEntityQuery(); _buyProto = _proto.EnumeratePrototypes(); _sellProto = _proto.EnumeratePrototypes(); SubscribeLocalEvent(OnProtoReload); SubscribeLocalEvent(OnPostInit); } private void OnProtoReload(PrototypesReloadedEventArgs ev) { _buyProto = _proto.EnumeratePrototypes(); _sellProto = _proto.EnumeratePrototypes(); } public override void Update(float frameTime) { base.Update(frameTime); UpdateShuttle(); } private void OnPostInit(Entity station, ref StationPostInitEvent args) { if (!Deleted(station.Comp.Shuttle)) return; var tradepostMap = _mapManager.CreateMap(); if (!_loader.TryLoad(tradepostMap, station.Comp.ShuttlePath.ToString(), out var shuttleUids)) return; var shuttle = shuttleUids[0]; station.Comp.Shuttle = shuttle; station.Comp.TradePostMap = _mapManager.GetMapEntityId(tradepostMap); var travelingStoreShipComp = EnsureComp(station.Comp.Shuttle.Value); travelingStoreShipComp.Station = station; station.Comp.NextTravelTime = _timing.CurTime + TimeSpan.FromSeconds(10f); UpdateStorePositions(station); } private void UpdateStorePositions(Entity station) { station.Comp.CurrentBuyPositions.Clear(); station.Comp.CurrentSellPositions.Clear(); if (_buyProto is not null) { foreach (var buyPos in _buyProto) { station.Comp.CurrentBuyPositions.Add(buyPos, buyPos.Price.Next(_random)/10*10); } } if (_sellProto is not null) { foreach (var sellPos in _sellProto) { station.Comp.CurrentSellPositions.Add(sellPos, sellPos.Price.Next(_random)/10*10); } } } /// /// Sell all the items we can, and replenish the internal balance /// private void SellingThings(Entity station) { var shuttle = station.Comp.Shuttle; //Get all entities sent to trading posts var toSell = new HashSet(); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var palletXform)) { if (palletXform.ParentUid != shuttle || !palletXform.Anchored) continue; var sentEntities = new HashSet(); _lookup.GetEntitiesInRange(uid, 0.5f, sentEntities, LookupFlags.Dynamic | LookupFlags.Sundries); foreach (var ent in sentEntities) { if (toSell.Contains(ent) || !_xformQuery.TryGetComponent(ent, out _)) continue; toSell.Add(ent); } } var ev = new BeforeSellEntities(ref toSell); RaiseLocalEvent(ev); foreach (var sellPos in station.Comp.CurrentSellPositions) { while (sellPos.Key.Service.TrySell(EntityManager, toSell)) { station.Comp.Balance += sellPos.Value; } } } /// /// Take all the money from the tradebox, and credit it to the internal balance /// private void TopUpBalance(Entity station) { var tradebox = GetTradeBox(station); if (tradebox is null) return; if (!TryComp(tradebox, out var tradeStorage)) return; //Get all currency in tradebox int cash = 0; foreach (var stored in tradeStorage.Container.ContainedEntities) { var price = _currency.GetTotalCurrency(stored); if (price > 0) { cash += price; QueueDel(stored); } } station.Comp.Balance += cash; } private void BuyToQueue(Entity station) { var tradebox = GetTradeBox(station); if (tradebox is null) return; if (!TryComp(tradebox, out var tradeStorage)) return; //Reading all papers in tradebox List> requests = new(); foreach (var stored in tradeStorage.Container.ContainedEntities) { if (!TryComp(stored, out var paper)) continue; var splittedText = paper.Content.Split("#"); foreach (var fragment in splittedText) { foreach (var buyPosition in station.Comp.CurrentBuyPositions) { if (fragment.StartsWith(buyPosition.Key.Code)) requests.Add(buyPosition); } } QueueDel(stored); } //Trying spend tradebox money to buy requested things foreach (var request in requests) { if (station.Comp.Balance < request.Value) continue; station.Comp.Balance -= request.Value; if (!_proto.TryIndex(request.Key, out var indexedBuyed)) continue; foreach (var service in indexedBuyed.Services) { service.Buy(EntityManager, station); } } } //Dequeue buyed items, and spawn they on shuttle private void TrySpawnBuyedThings(Entity station) { var shuttle = station.Comp.Shuttle; var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var palletXform)) { if (station.Comp.BuyedQueue.Count <= 0) break; if (palletXform.ParentUid != shuttle || !palletXform.Anchored) continue; var tileRef = palletXform.Coordinates.GetTileRef(); if (tileRef is null) continue; if (_turf.IsTileBlocked(tileRef.Value, CollisionGroup.ItemMask)) continue; var buyedThing = station.Comp.BuyedQueue.Dequeue(); Spawn(buyedThing, palletXform.Coordinates); } } /// /// Transform all the accumulated balance into physical money, which we will give to the players. /// private void CashOut(Entity station) { var moneyBox = GetTradeBox(station); if (moneyBox is not null) { var coord = Transform(moneyBox.Value).Coordinates; if (station.Comp.Balance > 0) { var coins = _currency.GenerateMoney(CP14SharedCurrencySystem.PP.Key, station.Comp.Balance, coord, out var remainder); station.Comp.Balance = remainder; foreach (var coin in coins) { _storage.Insert(moneyBox.Value, coin, out _); } } if (station.Comp.Balance > 0) { var coins = _currency.GenerateMoney(CP14SharedCurrencySystem.GP.Key, station.Comp.Balance, coord, out var remainder); station.Comp.Balance = remainder; foreach (var coin in coins) { _storage.Insert(moneyBox.Value, coin, out _); } } if (station.Comp.Balance > 0) { var coins = _currency.GenerateMoney(CP14SharedCurrencySystem.SP.Key, station.Comp.Balance, coord, out var remainder); station.Comp.Balance = remainder; foreach (var coin in coins) { _storage.Insert(moneyBox.Value, coin, out _); } } if (station.Comp.Balance > 0) { var coins = _currency.GenerateMoney(CP14SharedCurrencySystem.CP.Key, station.Comp.Balance, coord, out var remainder); station.Comp.Balance = remainder; foreach (var coin in coins) { _storage.Insert(moneyBox.Value, coin, out _); } } } } private EntityUid? GetTradeBox(Entity station) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var xform)) { if (xform.GridUid != station.Comp.Shuttle) continue; return uid; } return null; } }