]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Clean up store system (#28463)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Sat, 1 Jun 2024 15:29:17 +0000 (11:29 -0400)
committerGitHub <noreply@github.com>
Sat, 1 Jun 2024 15:29:17 +0000 (11:29 -0400)
26 files changed:
Content.Client/Store/Ui/StoreBoundUserInterface.cs
Content.Client/Store/Ui/StoreMenu.xaml.cs
Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
Content.Server/Implants/SubdermalImplantSystem.cs
Content.Server/PDA/PdaSystem.cs
Content.Server/PDA/Ringer/RingerSystem.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Content.Server/Store/Conditions/BuyBeforeCondition.cs
Content.Server/Store/Systems/StoreSystem.Command.cs
Content.Server/Store/Systems/StoreSystem.Listings.cs
Content.Server/Store/Systems/StoreSystem.Refund.cs
Content.Server/Store/Systems/StoreSystem.Ui.cs
Content.Server/Store/Systems/StoreSystem.cs
Content.Server/Traitor/Uplink/SurplusBundle/SurplusBundleComponent.cs
Content.Server/Traitor/Uplink/SurplusBundle/SurplusBundleSystem.cs
Content.Server/Traitor/Uplink/UplinkComponent.cs [new file with mode: 0644]
Content.Server/Traitor/Uplink/UplinkSystem.cs
Content.Shared/Store/Components/StoreComponent.cs [moved from Content.Server/Store/Components/StoreComponent.cs with 72% similarity]
Content.Shared/Store/StoreUi.cs
Resources/Locale/en-US/store/store.ftl
Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml
Resources/Prototypes/Entities/Objects/Devices/pda.yml
Resources/Prototypes/Entities/Objects/Magic/books.yml
Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml
Resources/Prototypes/Entities/Objects/Specific/syndicate.yml
Resources/Prototypes/Store/presets.yml

index 88ad0e3de8b5b9b1eb5efecd94e6c9518f815d9e..0010aedd96472f7e30b9c66050104834864181b9 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Shared.Store;
 using JetBrains.Annotations;
 using System.Linq;
+using Content.Shared.Store.Components;
 using Robust.Shared.Prototypes;
 
 namespace Content.Client.Store.Ui;
@@ -13,9 +14,6 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
     [ViewVariables]
     private StoreMenu? _menu;
 
-    [ViewVariables]
-    private string _windowName = Loc.GetString("store-ui-default-title");
-
     [ViewVariables]
     private string _search = string.Empty;
 
@@ -28,7 +26,9 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
 
     protected override void Open()
     {
-        _menu = new StoreMenu(_windowName);
+        _menu = new StoreMenu();
+        if (EntMan.TryGetComponent<StoreComponent>(Owner, out var store))
+            _menu.Title = Loc.GetString(store.Name);
 
         _menu.OpenCentered();
         _menu.OnClose += Close;
@@ -64,25 +64,15 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
     {
         base.UpdateState(state);
 
-        if (_menu == null)
-            return;
-
         switch (state)
         {
             case StoreUpdateState msg:
                 _listings = msg.Listings;
 
-                _menu.UpdateBalance(msg.Balance);
+                _menu?.UpdateBalance(msg.Balance);
                 UpdateListingsWithSearchFilter();
-                _menu.SetFooterVisibility(msg.ShowFooter);
-                _menu.UpdateRefund(msg.AllowRefund);
-                break;
-            case StoreInitializeState msg:
-                _windowName = msg.Name;
-                if (_menu != null && _menu.Window != null)
-                {
-                    _menu.Window.Title = msg.Name;
-                }
+                _menu?.SetFooterVisibility(msg.ShowFooter);
+                _menu?.UpdateRefund(msg.AllowRefund);
                 break;
         }
     }
index b7a2c285fe5dbe47653965d75710406f99377a27..388b31291c19e05688de67b9501d1caac3596b65 100644 (file)
@@ -32,7 +32,7 @@ public sealed partial class StoreMenu : DefaultWindow
 
     private List<ListingData> _cachedListings = new();
 
-    public StoreMenu(string name)
+    public StoreMenu()
     {
         RobustXamlLoader.Load(this);
         IoCManager.InjectDependencies(this);
@@ -40,9 +40,6 @@ public sealed partial class StoreMenu : DefaultWindow
         WithdrawButton.OnButtonDown += OnWithdrawButtonDown;
         RefundButton.OnButtonDown += OnRefundButtonDown;
         SearchBar.OnTextChanged += _ => SearchTextUpdated?.Invoke(this, SearchBar.Text);
-
-        if (Window != null)
-            Window.Title = name;
     }
 
     public void UpdateBalance(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> balance)
index d6f1c3c619ab059c91333ad20e688a71659abf86..1b62778d75858cb3164709c33200662957b6f4e5 100644 (file)
@@ -25,6 +25,7 @@ using Robust.Shared.Random;
 using Robust.Shared.Utility;
 using System.Linq;
 using Content.Server.GameTicking.Components;
+using Content.Shared.Store.Components;
 
 namespace Content.Server.GameTicking.Rules;
 
index e8af08b2ebbb9f98b289e230ece133190d17d93b..88c5fb9459253d80c7958fd115e409274511cbfc 100644 (file)
@@ -20,6 +20,7 @@ using Robust.Shared.Random;
 using System.Numerics;
 using Content.Shared.Movement.Pulling.Components;
 using Content.Shared.Movement.Pulling.Systems;
+using Content.Shared.Store.Components;
 using Robust.Shared.Collections;
 using Robust.Shared.Map.Components;
 
index d4934ee24e5f060889f5e3811a3b82eceb3f52f1..43bf571eb45665519203d0c454081f2faa0cc572 100644 (file)
@@ -8,6 +8,7 @@ using Content.Server.PDA.Ringer;
 using Content.Server.Station.Systems;
 using Content.Server.Store.Components;
 using Content.Server.Store.Systems;
+using Content.Server.Traitor.Uplink;
 using Content.Shared.Access.Components;
 using Content.Shared.CartridgeLoader;
 using Content.Shared.Chat;
@@ -15,6 +16,7 @@ using Content.Shared.Light;
 using Content.Shared.Light.Components;
 using Content.Shared.Light.EntitySystems;
 using Content.Shared.PDA;
+using Content.Shared.Store.Components;
 using Robust.Server.Containers;
 using Robust.Server.GameObjects;
 using Robust.Shared.Containers;
@@ -152,7 +154,7 @@ namespace Content.Server.PDA
 
             var address = GetDeviceNetAddress(uid);
             var hasInstrument = HasComp<InstrumentComponent>(uid);
-            var showUplink = HasComp<StoreComponent>(uid) && IsUnlocked(uid);
+            var showUplink = HasComp<UplinkComponent>(uid) && IsUnlocked(uid);
 
             UpdateStationName(uid, pda);
             UpdateAlertLevel(uid, pda);
@@ -237,8 +239,8 @@ namespace Content.Server.PDA
                 return;
 
             // check if its locked again to prevent malicious clients opening locked uplinks
-            if (TryComp<StoreComponent>(uid, out var store) && IsUnlocked(uid))
-                _store.ToggleUi(msg.Actor, uid, store);
+            if (HasComp<UplinkComponent>(uid) && IsUnlocked(uid))
+                _store.ToggleUi(msg.Actor, uid);
         }
 
         private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaLockUplinkMessage msg)
index 47ae41896e22773b286e45e71cadff8438d81f03..e15dcfaa2bc7c9f8cbc6c882462931b45e6c51ff 100644 (file)
@@ -6,6 +6,7 @@ using Content.Shared.PDA;
 using Content.Shared.PDA.Ringer;
 using Content.Shared.Popups;
 using Content.Shared.Store;
+using Content.Shared.Store.Components;
 using Robust.Server.GameObjects;
 using Robust.Shared.Audio;
 using Robust.Shared.Network;
index c390432f3a1b248bfb860ef51f288dcb17f903ef..a05105662d4d6062cae3d9bbcf72c432ab5fa65b 100644 (file)
@@ -17,6 +17,7 @@ using Content.Shared.Popups;
 using Content.Shared.Revenant;
 using Content.Shared.Revenant.Components;
 using Content.Shared.StatusEffect;
+using Content.Shared.Store.Components;
 using Content.Shared.Stunnable;
 using Content.Shared.Tag;
 using Robust.Server.GameObjects;
index 132f3534391ff8de24ca67f63af323256aae7b08..3f0c2de2e18d30aaec5e92fe09a19dbc11331e54 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Store.Components;
 using Content.Server.Store.Systems;
 using Content.Shared.Store;
+using Content.Shared.Store.Components;
 using Robust.Shared.Prototypes;
 
 namespace Content.Server.Store.Conditions;
index d259da2c95e83af6be3f789fc9983a3cf4fd5b53..5ad361eb4279f1cd39e47f928fbe50586eb50882 100644 (file)
@@ -1,7 +1,9 @@
+using System.Linq;
 using Content.Server.Store.Components;
 using Content.Shared.FixedPoint;
 using Content.Server.Administration;
 using Content.Shared.Administration;
+using Content.Shared.Store.Components;
 using Robust.Shared.Console;
 
 namespace Content.Server.Store.Systems;
@@ -58,7 +60,7 @@ public sealed partial class StoreSystem
         if (args.Length == 2 && NetEntity.TryParse(args[0], out var uidNet) && TryGetEntity(uidNet, out var uid))
         {
             if (TryComp<StoreComponent>(uid, out var store))
-                return CompletionResult.FromHintOptions(store.CurrencyWhitelist, "<currency prototype>");
+                return CompletionResult.FromHintOptions(store.CurrencyWhitelist.Select(p => p.ToString()), "<currency prototype>");
         }
 
         return CompletionResult.Empty;
index a56d9640d3713c1b61b7e0bc0d59e065ad09f46c..10b53a7c94b8609a7722a338f5d95c69b1d211c9 100644 (file)
@@ -1,5 +1,6 @@
-using Content.Server.Store.Components;
 using Content.Shared.Store;
+using Content.Shared.Store.Components;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Store.Systems;
 
@@ -80,7 +81,11 @@ public sealed partial class StoreSystem
     /// <param name="categories">What categories to filter by.</param>
     /// <param name="storeEntity">The physial entity of the store. Can be null.</param>
     /// <returns>The available listings.</returns>
-    public IEnumerable<ListingData> GetAvailableListings(EntityUid buyer, HashSet<ListingData>? listings, HashSet<string> categories, EntityUid? storeEntity = null)
+    public IEnumerable<ListingData> GetAvailableListings(
+        EntityUid buyer,
+        HashSet<ListingData>? listings,
+        HashSet<ProtoId<StoreCategoryPrototype>> categories,
+        EntityUid? storeEntity = null)
     {
         listings ??= GetAllListings();
 
@@ -117,7 +122,7 @@ public sealed partial class StoreSystem
     /// <param name="listing">The listing itself.</param>
     /// <param name="categories">The categories to check through.</param>
     /// <returns>If the listing was present in one of the categories.</returns>
-    public bool ListingHasCategory(ListingData listing, HashSet<string> categories)
+    public bool ListingHasCategory(ListingData listing, HashSet<ProtoId<StoreCategoryPrototype>> categories)
     {
         foreach (var cat in categories)
         {
index 5a8be4be2bbd758d1ae1e5a50ae5017965eb71da..4e823582e6e871f0ef6b2fc7e9299f7cb18af354 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Server.Store.Components;
+using Content.Shared.Store.Components;
 using Robust.Shared.Containers;
 
 namespace Content.Server.Store.Systems;
index 0a1a8d19f318ab24fcfbc36397e896f04ba63963..983d68d0af735e056c0913b088f3f0d6cd9ea94c 100644 (file)
@@ -10,6 +10,7 @@ using Content.Shared.FixedPoint;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Mind;
 using Content.Shared.Store;
+using Content.Shared.Store.Components;
 using Content.Shared.UserInterface;
 using Robust.Server.GameObjects;
 using Robust.Shared.Audio.Systems;
@@ -82,16 +83,11 @@ public sealed partial class StoreSystem
     /// <param name="user">The person who if opening the store ui. Listings are filtered based on this.</param>
     /// <param name="store">The store entity itself</param>
     /// <param name="component">The store component being refreshed.</param>
-    /// <param name="ui"></param>
     public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null)
     {
         if (!Resolve(store, ref component))
             return;
 
-        // TODO: Why is the state not being set unless this?
-        if (!_ui.HasUi(store, StoreUiKey.Key))
-            return;
-
         //this is the person who will be passed into logic for all listing filtering.
         if (user != null) //if we have no "buyer" for this update, then don't update the listings
         {
@@ -259,7 +255,8 @@ public sealed partial class StoreSystem
         }
 
         //log dat shit.
-        _admin.Add(LogType.StorePurchase, LogImpact.Low,
+        _admin.Add(LogType.StorePurchase,
+            LogImpact.Low,
             $"{ToPrettyString(buyer):player} purchased listing \"{ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listing, _prototypeManager)}\" from {ToPrettyString(uid)}");
 
         listing.PurchaseAmount++; //track how many times something has been purchased
index e310194778b00cd23a2f7d9cc9258a6a7dc042b6..0fd92cfb96516a4b010c5082b3015bf8b6bc723d 100644 (file)
@@ -5,11 +5,10 @@ using Content.Shared.Implants.Components;
 using Content.Shared.Interaction;
 using Content.Shared.Popups;
 using Content.Shared.Stacks;
-using Content.Shared.Store;
 using JetBrains.Annotations;
-using Robust.Server.GameObjects;
 using Robust.Shared.Prototypes;
 using System.Linq;
+using Content.Shared.Store.Components;
 using Robust.Shared.Utility;
 
 namespace Content.Server.Store.Systems;
@@ -44,7 +43,6 @@ public sealed partial class StoreSystem : EntitySystem
     private void OnMapInit(EntityUid uid, StoreComponent component, MapInitEvent args)
     {
         RefreshAllListings(component);
-        InitializeFromPreset(component.Preset, uid, component);
         component.StartingMap = Transform(uid).MapUid;
     }
 
@@ -54,7 +52,6 @@ public sealed partial class StoreSystem : EntitySystem
         if (MetaData(uid).EntityLifeStage == EntityLifeStage.MapInitialized)
         {
             RefreshAllListings(component);
-            InitializeFromPreset(component.Preset, uid, component);
         }
 
         var ev = new StoreAddedEvent();
@@ -167,43 +164,6 @@ public sealed partial class StoreSystem : EntitySystem
         UpdateUserInterface(null, uid, store);
         return true;
     }
-
-    /// <summary>
-    /// Initializes a store based on a preset ID
-    /// </summary>
-    /// <param name="preset">The ID of a store preset prototype</param>
-    /// <param name="uid"></param>
-    /// <param name="component">The store being initialized</param>
-    public void InitializeFromPreset(string? preset, EntityUid uid, StoreComponent component)
-    {
-        if (preset == null)
-            return;
-
-        if (!_proto.TryIndex<StorePresetPrototype>(preset, out var proto))
-            return;
-
-        InitializeFromPreset(proto, uid, component);
-    }
-
-    /// <summary>
-    /// Initializes a store based on a given preset
-    /// </summary>
-    /// <param name="preset">The StorePresetPrototype</param>
-    /// <param name="uid"></param>
-    /// <param name="component">The store being initialized</param>
-    public void InitializeFromPreset(StorePresetPrototype preset, EntityUid uid, StoreComponent component)
-    {
-        component.Preset = preset.ID;
-        component.CurrencyWhitelist.UnionWith(preset.CurrencyWhitelist);
-        component.Categories.UnionWith(preset.Categories);
-        if (component.Balance == new Dictionary<string, FixedPoint2>() && preset.InitialBalance != null) //if we don't have a value stored, use the preset
-            TryAddCurrency(preset.InitialBalance, uid, component);
-
-        if (_ui.HasUi(uid, StoreUiKey.Key))
-        {
-            _ui.SetUiState(uid, StoreUiKey.Key, new StoreInitializeState(preset.StoreName));
-        }
-    }
 }
 
 public sealed class CurrencyInsertAttemptEvent : CancellableEntityEventArgs
index 47ce68625a199475073ac1e652e6f8447b4b27e9..120581cf82d641314231ddc350545bee91763082 100644 (file)
@@ -1,6 +1,3 @@
-using Content.Shared.Store;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-
 namespace Content.Server.Traitor.Uplink.SurplusBundle;
 
 /// <summary>
@@ -12,14 +9,6 @@ public sealed partial class SurplusBundleComponent : Component
     /// <summary>
     ///     Total price of all content inside bundle.
     /// </summary>
-    [ViewVariables(VVAccess.ReadOnly)]
-    [DataField("totalPrice")]
+    [DataField]
     public int TotalPrice = 20;
-
-    /// <summary>
-    ///     The preset that will be used to get all the listings.
-    ///     Currently just defaults to the basic uplink.
-    /// </summary>
-    [DataField("storePreset", customTypeSerializer: typeof(PrototypeIdSerializer<StorePresetPrototype>))]
-    public string StorePreset = "StorePresetUplink";
 }
index 5c0a56d346c43f5fba413034bfdf2b3e23e50546..759cad5dedae8e427cec13949fab42d6522b6106 100644 (file)
@@ -3,76 +3,67 @@ using Content.Server.Storage.EntitySystems;
 using Content.Server.Store.Systems;
 using Content.Shared.FixedPoint;
 using Content.Shared.Store;
-using Robust.Shared.Prototypes;
+using Content.Shared.Store.Components;
 using Robust.Shared.Random;
 
 namespace Content.Server.Traitor.Uplink.SurplusBundle;
 
 public sealed class SurplusBundleSystem : EntitySystem
 {
-    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly EntityStorageSystem _entityStorage = default!;
     [Dependency] private readonly StoreSystem _store = default!;
 
-    private ListingData[] _listings = default!;
-
     public override void Initialize()
     {
         base.Initialize();
-        SubscribeLocalEvent<SurplusBundleComponent, MapInitEvent>(OnMapInit);
-
-        SubscribeLocalEvent<SurplusBundleComponent, ComponentInit>(OnInit);
-    }
 
-    private void OnInit(EntityUid uid, SurplusBundleComponent component, ComponentInit args)
-    {
-        var storePreset = _prototypeManager.Index<StorePresetPrototype>(component.StorePreset);
-
-        _listings = _store.GetAvailableListings(uid, null, storePreset.Categories).ToArray();
-
-        Array.Sort(_listings, (a, b) => (int) (b.Cost.Values.Sum() - a.Cost.Values.Sum())); //this might get weird with multicurrency but don't think about it
+        SubscribeLocalEvent<SurplusBundleComponent, MapInitEvent>(OnMapInit);
     }
 
     private void OnMapInit(EntityUid uid, SurplusBundleComponent component, MapInitEvent args)
     {
-        FillStorage(uid, component);
-    }
-
-    private void FillStorage(EntityUid uid, SurplusBundleComponent? component = null)
-    {
-        if (!Resolve(uid, ref component))
+        if (!TryComp<StoreComponent>(uid, out var store))
             return;
 
-        var cords = Transform(uid).Coordinates;
+        FillStorage((uid, component, store));
+    }
 
-        var content = GetRandomContent(component.TotalPrice);
+    private void FillStorage(Entity<SurplusBundleComponent, StoreComponent> ent)
+    {
+        var cords = Transform(ent).Coordinates;
+        var content = GetRandomContent(ent);
         foreach (var item in content)
         {
-            var ent = EntityManager.SpawnEntity(item.ProductEntity, cords);
-            _entityStorage.Insert(ent, uid);
+            var dode = Spawn(item.ProductEntity, cords);
+            _entityStorage.Insert(dode, ent);
         }
     }
 
     // wow, is this leetcode reference?
-    private List<ListingData> GetRandomContent(FixedPoint2 targetCost)
+    private List<ListingData> GetRandomContent(Entity<SurplusBundleComponent, StoreComponent> ent)
     {
         var ret = new List<ListingData>();
-        if (_listings.Length == 0)
+
+        var listings = _store.GetAvailableListings(ent, null, ent.Comp2.Categories)
+            .OrderBy(p => p.Cost.Values.Sum())
+            .ToList();
+
+        if (listings.Count == 0)
             return ret;
 
         var totalCost = FixedPoint2.Zero;
         var index = 0;
-        while (totalCost < targetCost)
+        while (totalCost < ent.Comp1.TotalPrice)
         {
             // All data is sorted in price descending order
             // Find new item with the lowest acceptable price
             // All expansive items will be before index, all acceptable after
-            var remainingBudget = targetCost - totalCost;
-            while (_listings[index].Cost.Values.Sum() > remainingBudget)
+            var remainingBudget = ent.Comp1.TotalPrice - totalCost;
+            while (listings[index].Cost.Values.Sum() > remainingBudget)
             {
                 index++;
-                if (index >= _listings.Length)
+                if (index >= listings.Count)
                 {
                     // Looks like no cheap items left
                     // It shouldn't be case for ss14 content
@@ -82,8 +73,8 @@ public sealed class SurplusBundleSystem : EntitySystem
             }
 
             // Select random listing and add into crate
-            var randomIndex = _random.Next(index, _listings.Length);
-            var randomItem = _listings[randomIndex];
+            var randomIndex = _random.Next(index, listings.Count);
+            var randomItem = listings[randomIndex];
             ret.Add(randomItem);
             totalCost += randomItem.Cost.Values.Sum();
         }
diff --git a/Content.Server/Traitor/Uplink/UplinkComponent.cs b/Content.Server/Traitor/Uplink/UplinkComponent.cs
new file mode 100644 (file)
index 0000000..35f11ce
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Content.Server.Traitor.Uplink;
+
+/// <summary>
+/// This is used for identifying something as a hidden uplink and showing the UI.
+/// </summary>
+[RegisterComponent]
+public sealed partial class UplinkComponent : Component;
index 5670e28ec99919bad992cdc85cfb2a83e4959eed..7c39f1ed666a00f9bebce701c699b27a5e188beb 100644 (file)
@@ -5,6 +5,7 @@ using Content.Shared.PDA;
 using Content.Server.Store.Components;
 using Content.Shared.FixedPoint;
 using Content.Shared.Store;
+using Content.Shared.Store.Components;
 
 namespace Content.Server.Traitor.Uplink
 {
@@ -17,18 +18,6 @@ namespace Content.Server.Traitor.Uplink
         [ValidatePrototypeId<CurrencyPrototype>]
         public const string TelecrystalCurrencyPrototype = "Telecrystal";
 
-        /// <summary>
-        ///     Gets the amount of TC on an "uplink"
-        ///     Mostly just here for legacy systems based on uplink.
-        /// </summary>
-        /// <param name="component"></param>
-        /// <returns>the amount of TC</returns>
-        public int GetTCBalance(StoreComponent component)
-        {
-            FixedPoint2? tcBalance = component.Balance.GetValueOrDefault(TelecrystalCurrencyPrototype);
-            return tcBalance?.Int() ?? 0;
-        }
-
         /// <summary>
         /// Adds an uplink to the target
         /// </summary>
@@ -37,7 +26,7 @@ namespace Content.Server.Traitor.Uplink
         /// <param name="uplinkPresetId">The id of the storepreset</param>
         /// <param name="uplinkEntity">The entity that will actually have the uplink functionality. Defaults to the PDA if null.</param>
         /// <returns>Whether or not the uplink was added successfully</returns>
-        public bool AddUplink(EntityUid user, FixedPoint2? balance, string uplinkPresetId = "StorePresetUplink", EntityUid? uplinkEntity = null)
+        public bool AddUplink(EntityUid user, FixedPoint2? balance, EntityUid? uplinkEntity = null)
         {
             // Try to find target item
             if (uplinkEntity == null)
@@ -47,11 +36,10 @@ namespace Content.Server.Traitor.Uplink
                     return false;
             }
 
+            EnsureComp<UplinkComponent>(uplinkEntity.Value);
             var store = EnsureComp<StoreComponent>(uplinkEntity.Value);
-            _store.InitializeFromPreset(uplinkPresetId, uplinkEntity.Value, store);
             store.AccountOwner = user;
             store.Balance.Clear();
-
             if (balance != null)
             {
                 store.Balance.Clear();
similarity index 72%
rename from Content.Server/Store/Components/StoreComponent.cs
rename to Content.Shared/Store/Components/StoreComponent.cs
index 0b7dbbea0942a9d063867ac819ea3eb0032b56a1..223f507971715ab045b923d290a2d3b6f4ea0cfa 100644 (file)
@@ -1,46 +1,41 @@
 using Content.Shared.FixedPoint;
-using Content.Shared.Store;
 using Robust.Shared.Audio;
-using Robust.Shared.Map;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
 
-namespace Content.Server.Store.Components;
+namespace Content.Shared.Store.Components;
 
 /// <summary>
 /// This component manages a store which players can use to purchase different listings
 /// through the ui. The currency, listings, and categories are defined in yaml.
 /// </summary>
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent]
 public sealed partial class StoreComponent : Component
 {
-    /// <summary>
-    /// The default preset for the store. Is overriden by default values specified on the component.
-    /// </summary>
-    [DataField("preset", customTypeSerializer: typeof(PrototypeIdSerializer<StorePresetPrototype>))]
-    public string? Preset;
+    [DataField]
+    public LocId Name = "store-ui-default-title";
 
     /// <summary>
     /// All the listing categories that are available on this store.
     /// The available listings are partially based on the categories.
     /// </summary>
-    [DataField("categories", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<StoreCategoryPrototype>))]
-    public HashSet<string> Categories = new();
+    [DataField]
+    public HashSet<ProtoId<StoreCategoryPrototype>> Categories = new();
 
     /// <summary>
     /// The total amount of currency that can be used in the store.
     /// The string represents the ID of te currency prototype, where the
     /// float is that amount.
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField("balance", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, CurrencyPrototype>))]
-    public Dictionary<string, FixedPoint2> Balance = new();
+    [DataField]
+    public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> Balance = new();
 
     /// <summary>
     /// The list of currencies that can be inserted into this store.
     /// </summary>
-    [ViewVariables(VVAccess.ReadOnly), DataField("currencyWhitelist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<CurrencyPrototype>))]
-    public HashSet<string> CurrencyWhitelist = new();
+    [DataField]
+    public HashSet<ProtoId<CurrencyPrototype>> CurrencyWhitelist = new();
 
     /// <summary>
     /// The person who "owns" the store/account. Used if you want the listings to be fixed
@@ -52,6 +47,7 @@ public sealed partial class StoreComponent : Component
     /// <summary>
     /// All listings, including those that aren't available to the buyer
     /// </summary>
+    [DataField]
     public HashSet<ListingData> Listings = new();
 
     /// <summary>
@@ -70,7 +66,7 @@ public sealed partial class StoreComponent : Component
     ///     The total balance spent in this store. Used for refunds.
     /// </summary>
     [ViewVariables, DataField]
-    public Dictionary<string, FixedPoint2> BalanceSpent = new();
+    public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> BalanceSpent = new();
 
     /// <summary>
     ///     Controls if the store allows refunds
@@ -95,7 +91,7 @@ public sealed partial class StoreComponent : Component
     /// <summary>
     /// The sound played to the buyer when a purchase is succesfully made.
     /// </summary>
-    [DataField("buySuccessSound")]
+    [DataField]
     public SoundSpecifier BuySuccessSound = new SoundPathSpecifier("/Audio/Effects/kaching.ogg");
     #endregion
 }
index ee4da6991f6cb79eab74a7ea75a6a7035f5c843d..59cf1bbbc81825e9582db72e4f6cfb39c00000fb 100644 (file)
@@ -30,20 +30,6 @@ public sealed class StoreUpdateState : BoundUserInterfaceState
     }
 }
 
-/// <summary>
-/// initializes miscellaneous data about the store.
-/// </summary>
-[Serializable, NetSerializable]
-public sealed class StoreInitializeState : BoundUserInterfaceState
-{
-    public readonly string Name;
-
-    public StoreInitializeState(string name)
-    {
-        Name = name;
-    }
-}
-
 [Serializable, NetSerializable]
 public sealed class StoreRequestUpdateInterfaceMessage : BoundUserInterfaceMessage
 {
index 997afedfc063faa3d9d6965e9c80006a8f8dbe31..5c1a46339e723b6c701515af69a2cd79f3b5d45d 100644 (file)
@@ -8,3 +8,6 @@ store-ui-traitor-warning = Operatives must lock their uplinks after use to avoid
 store-withdraw-button-ui = Withdraw {$currency}
 store-ui-button-out-of-stock = {""} (Out of Stock)
 store-not-account-owner = This {$store} is not bound to you!
+
+store-preset-name-uplink = Uplink
+store-preset-name-spellbook = Spellbook
index 3f9e909c809e84909233fd9c307d10954bb6fb58..ba97af39250742633cf232d47a9d1097a4db6745 100644 (file)
@@ -1,6 +1,6 @@
 - type: entity
   id: CrateSyndicateSurplusBundle
-  parent: CrateSyndicate
+  parent: [ CrateSyndicate, StorePresetUplink ]
   name: Syndicate surplus crate
   description: Contains 50 telecrystals worth of completely random Syndicate items. It can be useless junk or really good.
   components:
@@ -24,7 +24,7 @@
 
 - type: entity
   id: CrateSyndicateSuperSurplusBundle
-  parent: CrateSyndicate
+  parent: [ CrateSyndicate, StorePresetUplink ]
   name: Syndicate super surplus crate
   description: Contains 125 telecrystals worth of completely random Syndicate items.
   components:
index b76ca6a14ad1c5c724fd6d85c4c7ab4f5cc0d91d..b1a6ab0b8fa6be9bef2eb26716c5f65377627dfc 100644 (file)
@@ -1,6 +1,6 @@
 - type: entity
   abstract: true
-  parent: BaseItem
+  parent: [ BaseItem, StorePresetUplink ] #PDA's have uplinks so they have to inherit the data.
   id: BasePDA
   name: PDA
   description: Personal Data Assistant.
index 554c5214c199900e4b5ab750bdddf43b8e71d3fc..e47fa00c45bf5aabea01e825d49495a7ac1dfe63 100644 (file)
@@ -25,7 +25,7 @@
   id: WizardsGrimoire
   name: wizards grimoire
   suffix: Wizard
-  parent: BaseItem
+  parent: [ BaseItem, StorePresetSpellbook ]
   components:
     - type: Sprite
       sprite: Objects/Misc/books.rsi
@@ -46,7 +46,6 @@
     - type: Store
       refundAllowed: true
       ownerOnly: true # get your own tome!
-      preset: StorePresetSpellbook
       balance:
         WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
 
   id: WizardsGrimoireNoRefund
   name: wizards grimoire
   suffix: Wizard, No Refund
-  parent: WizardsGrimoire
+  parent: [ WizardsGrimoire, StorePresetSpellbook ]
   components:
     - type: Store
       refundAllowed: false
       ownerOnly: true # get your own tome!
-      preset: StorePresetSpellbook
       balance:
         WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
 
index c92985c2cbae2aaf6c19045c9f4acec40409c6ba..9690d0bdfe831b8645551c5dc8d610ba0e73c17f 100644 (file)
         - Cuffable # useless if you cant be cuffed
 
 - type: entity
-  parent: BaseSubdermalImplant
+  parent: [ BaseSubdermalImplant, StorePresetUplink ]
   id: UplinkImplant
   name: uplink implant
   description: This implant lets the user access a hidden Syndicate uplink at will.
       components:
       - Hands # prevent mouse buying grenade penguin since its not telepathic
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 0
   - type: UserInterface
index 459beeef1880bd9b3e292da878c3fef38e20f865..53d4f7953b17d8345631841339da9cfa213825f3 100644 (file)
@@ -48,7 +48,7 @@
 
 # Uplinks
 - type: entity
-  parent: BaseItem
+  parent: [ BaseItem, StorePresetUplink ]
   id: BaseUplinkRadio
   name: syndicate uplink
   description: Suspiciously looking old radio...
@@ -68,7 +68,6 @@
   - type: ActivatableUI
     key: enum.StoreUiKey.Key
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 0
 
@@ -78,7 +77,6 @@
   suffix: 20 TC
   components:
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 20
 
@@ -88,7 +86,6 @@
   suffix: 25 TC
   components:
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 25
 
@@ -99,7 +96,6 @@
   suffix: 40 TC, NukeOps
   components:
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 40
   - type: Tag
   suffix: 60 TC, LoneOps
   components:
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 60
   - type: Tag
   suffix: DEBUG
   components:
   - type: Store
-    preset: StorePresetUplink
     balance:
       Telecrystal: 99999
index 166c29fe4165a17aae7b8df1d81464b0627cd604..762ed68921aa8989928ea6a86f30b911460e8d7a 100644 (file)
@@ -1,29 +1,37 @@
-- type: storePreset
+- type: entity
   id: StorePresetUplink
-  storeName: Uplink
-  categories:
-  - UplinkWeaponry
-  - UplinkAmmo
-  - UplinkExplosives
-  - UplinkChemicals
-  - UplinkDeception
-  - UplinkDisruption
-  - UplinkImplants
-  - UplinkAllies
-  - UplinkWearables
-  - UplinkJob
-  - UplinkPointless
-  currencyWhitelist:
-  - Telecrystal
+  abstract: true
+  components:
+  - type: Store
+    name: store-preset-name-uplink
+    categories:
+    - UplinkWeaponry
+    - UplinkAmmo
+    - UplinkExplosives
+    - UplinkChemicals
+    - UplinkDeception
+    - UplinkDisruption
+    - UplinkImplants
+    - UplinkAllies
+    - UplinkWearables
+    - UplinkJob
+    - UplinkPointless
+    currencyWhitelist:
+    - Telecrystal
+    balance:
+      Telecrystal: 0
 
-- type: storePreset
+- type: entity
   id: StorePresetSpellbook
-  storeName: Spellbook
-  categories:
-  - SpellbookOffensive    #Fireball, Rod Form
-  - SpellbookDefensive    #Magic Missile, Wall of Force
-  - SpellbookUtility      #Body Swap, Lich, Teleport, Knock, Polymorph
-  - SpellbookEquipment    #Battlemage Robes, Staff of Locker
-  - SpellbookEvents       #Summon Weapons, Summon Ghosts
-  currencyWhitelist:
+  abstract: true
+  components:
+  - type: Store
+    name: store-preset-name-spellbook
+    categories:
+    - SpellbookOffensive    #Fireball, Rod Form
+    - SpellbookDefensive    #Magic Missile, Wall of Force
+    - SpellbookUtility      #Body Swap, Lich, Teleport, Knock, Polymorph
+    - SpellbookEquipment    #Battlemage Robes, Staff of Locker
+    - SpellbookEvents       #Summon Weapons, Summon Ghosts
+    currencyWhitelist:
     - WizCoin