using Content.Server.Stack; using Content.Server.Store.Components; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Store; using Robust.Shared.Player; using Robust.Shared.Prototypes; using System.Linq; using Content.Server.UserInterface; namespace Content.Server.Store.Systems; /// /// Manages general interactions with a store and different entities, /// getting listings for stores, and interfacing with the store UI. /// public sealed partial class StoreSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent((_,c,a) => UpdateUserInterface(a.User, c)); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); InitializeUi(); } private void OnStartup(EntityUid uid, StoreComponent component, ComponentStartup args) { RaiseLocalEvent(uid, new StoreAddedEvent(), true); } private void OnShutdown(EntityUid uid, StoreComponent component, ComponentShutdown args) { RaiseLocalEvent(uid, new StoreRemovedEvent(), true); } private void OnAfterInteract(EntityUid uid, CurrencyComponent component, AfterInteractEvent args) { if (args.Handled || !args.CanReach) return; if (args.Target == null || !TryComp(args.Target, out var store)) return; //if you somehow are inserting cash before the store initializes. if (!store.Opened) { RefreshAllListings(store); InitializeFromPreset(store.Preset, store); store.Opened = true; } args.Handled = TryAddCurrency(GetCurrencyValue(component), store); if (args.Handled) { var msg = Loc.GetString("store-currency-inserted", ("used", args.Used), ("target", args.Target)); _popup.PopupEntity(msg, args.Target.Value); QueueDel(args.Used); } } /// /// Gets the value from an entity's currency component. /// Scales with stacks. /// /// /// The value of the currency public Dictionary GetCurrencyValue(CurrencyComponent component) { TryComp(component.Owner, out var stack); var amount = stack?.Count ?? 1; return component.Price.ToDictionary(v => v.Key, p => p.Value * amount); } /// /// Tries to add a currency to a store's balance. /// /// The currency to add /// The store to add it to /// Whether or not the currency was succesfully added public bool TryAddCurrency(CurrencyComponent component, StoreComponent store) { return TryAddCurrency(GetCurrencyValue(component), store); } /// /// Tries to add a currency to a store's balance /// /// The value to add to the store /// The store to add it to /// Whether or not the currency was succesfully added public bool TryAddCurrency(Dictionary currency, StoreComponent store) { //verify these before values are modified foreach (var type in currency) { if (!store.CurrencyWhitelist.Contains(type.Key)) return false; } foreach (var type in currency) { if (!store.Balance.TryAdd(type.Key, type.Value)) store.Balance[type.Key] += type.Value; } UpdateUserInterface(null, store); return true; } /// /// Initializes a store based on a preset ID /// /// The ID of a store preset prototype /// The store being initialized public void InitializeFromPreset(string? preset, StoreComponent component) { if (preset == null) return; if (!_proto.TryIndex(preset, out var proto)) return; InitializeFromPreset(proto, component); } /// /// Initializes a store based on a given preset /// /// The StorePresetPrototype /// The store being initialized public void InitializeFromPreset(StorePresetPrototype preset, StoreComponent component) { component.Preset = preset.ID; component.CurrencyWhitelist.UnionWith(preset.CurrencyWhitelist); component.Categories.UnionWith(preset.Categories); if (component.Balance == new Dictionary() && preset.InitialBalance != null) //if we don't have a value stored, use the preset TryAddCurrency(preset.InitialBalance, component); var ui = _ui.GetUiOrNull(component.Owner, StoreUiKey.Key); if (ui != null) _ui.SetUiState(ui, new StoreInitializeState(preset.StoreName)); } }