Clean up store system (#28463)
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.Store.Ui;
|
namespace Content.Client.Store.Ui;
|
||||||
@@ -13,9 +14,6 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private StoreMenu? _menu;
|
private StoreMenu? _menu;
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
private string _windowName = Loc.GetString("store-ui-default-title");
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private string _search = string.Empty;
|
private string _search = string.Empty;
|
||||||
|
|
||||||
@@ -28,7 +26,9 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
|
|||||||
|
|
||||||
protected override void Open()
|
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.OpenCentered();
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
@@ -64,25 +64,15 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
base.UpdateState(state);
|
base.UpdateState(state);
|
||||||
|
|
||||||
if (_menu == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case StoreUpdateState msg:
|
case StoreUpdateState msg:
|
||||||
_listings = msg.Listings;
|
_listings = msg.Listings;
|
||||||
|
|
||||||
_menu.UpdateBalance(msg.Balance);
|
_menu?.UpdateBalance(msg.Balance);
|
||||||
UpdateListingsWithSearchFilter();
|
UpdateListingsWithSearchFilter();
|
||||||
_menu.SetFooterVisibility(msg.ShowFooter);
|
_menu?.SetFooterVisibility(msg.ShowFooter);
|
||||||
_menu.UpdateRefund(msg.AllowRefund);
|
_menu?.UpdateRefund(msg.AllowRefund);
|
||||||
break;
|
|
||||||
case StoreInitializeState msg:
|
|
||||||
_windowName = msg.Name;
|
|
||||||
if (_menu != null && _menu.Window != null)
|
|
||||||
{
|
|
||||||
_menu.Window.Title = msg.Name;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public sealed partial class StoreMenu : DefaultWindow
|
|||||||
|
|
||||||
private List<ListingData> _cachedListings = new();
|
private List<ListingData> _cachedListings = new();
|
||||||
|
|
||||||
public StoreMenu(string name)
|
public StoreMenu()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
@@ -40,9 +40,6 @@ public sealed partial class StoreMenu : DefaultWindow
|
|||||||
WithdrawButton.OnButtonDown += OnWithdrawButtonDown;
|
WithdrawButton.OnButtonDown += OnWithdrawButtonDown;
|
||||||
RefundButton.OnButtonDown += OnRefundButtonDown;
|
RefundButton.OnButtonDown += OnRefundButtonDown;
|
||||||
SearchBar.OnTextChanged += _ => SearchTextUpdated?.Invoke(this, SearchBar.Text);
|
SearchBar.OnTextChanged += _ => SearchTextUpdated?.Invoke(this, SearchBar.Text);
|
||||||
|
|
||||||
if (Window != null)
|
|
||||||
Window.Title = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBalance(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> balance)
|
public void UpdateBalance(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> balance)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameTicking.Components;
|
using Content.Server.GameTicking.Components;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using Robust.Shared.Random;
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Movement.Pulling.Components;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Movement.Pulling.Systems;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Collections;
|
using Robust.Shared.Collections;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Server.PDA.Ringer;
|
|||||||
using Content.Server.Station.Systems;
|
using Content.Server.Station.Systems;
|
||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
using Content.Server.Store.Systems;
|
using Content.Server.Store.Systems;
|
||||||
|
using Content.Server.Traitor.Uplink;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.CartridgeLoader;
|
using Content.Shared.CartridgeLoader;
|
||||||
using Content.Shared.Chat;
|
using Content.Shared.Chat;
|
||||||
@@ -15,6 +16,7 @@ using Content.Shared.Light;
|
|||||||
using Content.Shared.Light.Components;
|
using Content.Shared.Light.Components;
|
||||||
using Content.Shared.Light.EntitySystems;
|
using Content.Shared.Light.EntitySystems;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Server.Containers;
|
using Robust.Server.Containers;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
@@ -152,7 +154,7 @@ namespace Content.Server.PDA
|
|||||||
|
|
||||||
var address = GetDeviceNetAddress(uid);
|
var address = GetDeviceNetAddress(uid);
|
||||||
var hasInstrument = HasComp<InstrumentComponent>(uid);
|
var hasInstrument = HasComp<InstrumentComponent>(uid);
|
||||||
var showUplink = HasComp<StoreComponent>(uid) && IsUnlocked(uid);
|
var showUplink = HasComp<UplinkComponent>(uid) && IsUnlocked(uid);
|
||||||
|
|
||||||
UpdateStationName(uid, pda);
|
UpdateStationName(uid, pda);
|
||||||
UpdateAlertLevel(uid, pda);
|
UpdateAlertLevel(uid, pda);
|
||||||
@@ -237,8 +239,8 @@ namespace Content.Server.PDA
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// check if its locked again to prevent malicious clients opening locked uplinks
|
// check if its locked again to prevent malicious clients opening locked uplinks
|
||||||
if (TryComp<StoreComponent>(uid, out var store) && IsUnlocked(uid))
|
if (HasComp<UplinkComponent>(uid) && IsUnlocked(uid))
|
||||||
_store.ToggleUi(msg.Actor, uid, store);
|
_store.ToggleUi(msg.Actor, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaLockUplinkMessage msg)
|
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaLockUplinkMessage msg)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Shared.PDA;
|
|||||||
using Content.Shared.PDA.Ringer;
|
using Content.Shared.PDA.Ringer;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using Content.Shared.Popups;
|
|||||||
using Content.Shared.Revenant;
|
using Content.Shared.Revenant;
|
||||||
using Content.Shared.Revenant.Components;
|
using Content.Shared.Revenant.Components;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
using Content.Server.Store.Systems;
|
using Content.Server.Store.Systems;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Store.Conditions;
|
namespace Content.Server.Store.Conditions;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
using System.Linq;
|
||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Server.Administration;
|
using Content.Server.Administration;
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
namespace Content.Server.Store.Systems;
|
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 (args.Length == 2 && NetEntity.TryParse(args[0], out var uidNet) && TryGetEntity(uidNet, out var uid))
|
||||||
{
|
{
|
||||||
if (TryComp<StoreComponent>(uid, out var store))
|
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;
|
return CompletionResult.Empty;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Store.Components;
|
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.Store.Systems;
|
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="categories">What categories to filter by.</param>
|
||||||
/// <param name="storeEntity">The physial entity of the store. Can be null.</param>
|
/// <param name="storeEntity">The physial entity of the store. Can be null.</param>
|
||||||
/// <returns>The available listings.</returns>
|
/// <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();
|
listings ??= GetAllListings();
|
||||||
|
|
||||||
@@ -117,7 +122,7 @@ public sealed partial class StoreSystem
|
|||||||
/// <param name="listing">The listing itself.</param>
|
/// <param name="listing">The listing itself.</param>
|
||||||
/// <param name="categories">The categories to check through.</param>
|
/// <param name="categories">The categories to check through.</param>
|
||||||
/// <returns>If the listing was present in one of the categories.</returns>
|
/// <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)
|
foreach (var cat in categories)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
namespace Content.Server.Store.Systems;
|
namespace Content.Server.Store.Systems;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Content.Shared.FixedPoint;
|
|||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Mind;
|
using Content.Shared.Mind;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Content.Shared.UserInterface;
|
using Content.Shared.UserInterface;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.Audio.Systems;
|
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="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="store">The store entity itself</param>
|
||||||
/// <param name="component">The store component being refreshed.</param>
|
/// <param name="component">The store component being refreshed.</param>
|
||||||
/// <param name="ui"></param>
|
|
||||||
public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null)
|
public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(store, ref component))
|
if (!Resolve(store, ref component))
|
||||||
return;
|
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.
|
//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
|
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.
|
//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)}");
|
$"{ToPrettyString(buyer):player} purchased listing \"{ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listing, _prototypeManager)}\" from {ToPrettyString(uid)}");
|
||||||
|
|
||||||
listing.PurchaseAmount++; //track how many times something has been purchased
|
listing.PurchaseAmount++; //track how many times something has been purchased
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ using Content.Shared.Implants.Components;
|
|||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Stacks;
|
using Content.Shared.Stacks;
|
||||||
using Content.Shared.Store;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Store.Systems;
|
namespace Content.Server.Store.Systems;
|
||||||
@@ -44,7 +43,6 @@ public sealed partial class StoreSystem : EntitySystem
|
|||||||
private void OnMapInit(EntityUid uid, StoreComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, StoreComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
RefreshAllListings(component);
|
RefreshAllListings(component);
|
||||||
InitializeFromPreset(component.Preset, uid, component);
|
|
||||||
component.StartingMap = Transform(uid).MapUid;
|
component.StartingMap = Transform(uid).MapUid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +52,6 @@ public sealed partial class StoreSystem : EntitySystem
|
|||||||
if (MetaData(uid).EntityLifeStage == EntityLifeStage.MapInitialized)
|
if (MetaData(uid).EntityLifeStage == EntityLifeStage.MapInitialized)
|
||||||
{
|
{
|
||||||
RefreshAllListings(component);
|
RefreshAllListings(component);
|
||||||
InitializeFromPreset(component.Preset, uid, component);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ev = new StoreAddedEvent();
|
var ev = new StoreAddedEvent();
|
||||||
@@ -167,43 +164,6 @@ public sealed partial class StoreSystem : EntitySystem
|
|||||||
UpdateUserInterface(null, uid, store);
|
UpdateUserInterface(null, uid, store);
|
||||||
return true;
|
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
|
public sealed class CurrencyInsertAttemptEvent : CancellableEntityEventArgs
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
using Content.Shared.Store;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Traitor.Uplink.SurplusBundle;
|
namespace Content.Server.Traitor.Uplink.SurplusBundle;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -12,14 +9,6 @@ public sealed partial class SurplusBundleComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Total price of all content inside bundle.
|
/// Total price of all content inside bundle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
[DataField]
|
||||||
[DataField("totalPrice")]
|
|
||||||
public int TotalPrice = 20;
|
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";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,76 +3,67 @@ using Content.Server.Storage.EntitySystems;
|
|||||||
using Content.Server.Store.Systems;
|
using Content.Server.Store.Systems;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
using Robust.Shared.Prototypes;
|
using Content.Shared.Store.Components;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Server.Traitor.Uplink.SurplusBundle;
|
namespace Content.Server.Traitor.Uplink.SurplusBundle;
|
||||||
|
|
||||||
public sealed class SurplusBundleSystem : EntitySystem
|
public sealed class SurplusBundleSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly EntityStorageSystem _entityStorage = default!;
|
[Dependency] private readonly EntityStorageSystem _entityStorage = default!;
|
||||||
[Dependency] private readonly StoreSystem _store = default!;
|
[Dependency] private readonly StoreSystem _store = default!;
|
||||||
|
|
||||||
private ListingData[] _listings = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<SurplusBundleComponent, MapInitEvent>(OnMapInit);
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMapInit(EntityUid uid, SurplusBundleComponent component, MapInitEvent args)
|
private void OnMapInit(EntityUid uid, SurplusBundleComponent component, MapInitEvent args)
|
||||||
{
|
{
|
||||||
FillStorage(uid, component);
|
if (!TryComp<StoreComponent>(uid, out var store))
|
||||||
}
|
|
||||||
|
|
||||||
private void FillStorage(EntityUid uid, SurplusBundleComponent? component = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref component))
|
|
||||||
return;
|
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)
|
foreach (var item in content)
|
||||||
{
|
{
|
||||||
var ent = EntityManager.SpawnEntity(item.ProductEntity, cords);
|
var dode = Spawn(item.ProductEntity, cords);
|
||||||
_entityStorage.Insert(ent, uid);
|
_entityStorage.Insert(dode, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wow, is this leetcode reference?
|
// wow, is this leetcode reference?
|
||||||
private List<ListingData> GetRandomContent(FixedPoint2 targetCost)
|
private List<ListingData> GetRandomContent(Entity<SurplusBundleComponent, StoreComponent> ent)
|
||||||
{
|
{
|
||||||
var ret = new List<ListingData>();
|
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;
|
return ret;
|
||||||
|
|
||||||
var totalCost = FixedPoint2.Zero;
|
var totalCost = FixedPoint2.Zero;
|
||||||
var index = 0;
|
var index = 0;
|
||||||
while (totalCost < targetCost)
|
while (totalCost < ent.Comp1.TotalPrice)
|
||||||
{
|
{
|
||||||
// All data is sorted in price descending order
|
// All data is sorted in price descending order
|
||||||
// Find new item with the lowest acceptable price
|
// Find new item with the lowest acceptable price
|
||||||
// All expansive items will be before index, all acceptable after
|
// All expansive items will be before index, all acceptable after
|
||||||
var remainingBudget = targetCost - totalCost;
|
var remainingBudget = ent.Comp1.TotalPrice - totalCost;
|
||||||
while (_listings[index].Cost.Values.Sum() > remainingBudget)
|
while (listings[index].Cost.Values.Sum() > remainingBudget)
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
if (index >= _listings.Length)
|
if (index >= listings.Count)
|
||||||
{
|
{
|
||||||
// Looks like no cheap items left
|
// Looks like no cheap items left
|
||||||
// It shouldn't be case for ss14 content
|
// It shouldn't be case for ss14 content
|
||||||
@@ -82,8 +73,8 @@ public sealed class SurplusBundleSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Select random listing and add into crate
|
// Select random listing and add into crate
|
||||||
var randomIndex = _random.Next(index, _listings.Length);
|
var randomIndex = _random.Next(index, listings.Count);
|
||||||
var randomItem = _listings[randomIndex];
|
var randomItem = listings[randomIndex];
|
||||||
ret.Add(randomItem);
|
ret.Add(randomItem);
|
||||||
totalCost += randomItem.Cost.Values.Sum();
|
totalCost += randomItem.Cost.Values.Sum();
|
||||||
}
|
}
|
||||||
|
|||||||
7
Content.Server/Traitor/Uplink/UplinkComponent.cs
Normal file
7
Content.Server/Traitor/Uplink/UplinkComponent.cs
Normal file
@@ -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;
|
||||||
@@ -5,6 +5,7 @@ using Content.Shared.PDA;
|
|||||||
using Content.Server.Store.Components;
|
using Content.Server.Store.Components;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Store;
|
using Content.Shared.Store;
|
||||||
|
using Content.Shared.Store.Components;
|
||||||
|
|
||||||
namespace Content.Server.Traitor.Uplink
|
namespace Content.Server.Traitor.Uplink
|
||||||
{
|
{
|
||||||
@@ -17,18 +18,6 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
[ValidatePrototypeId<CurrencyPrototype>]
|
[ValidatePrototypeId<CurrencyPrototype>]
|
||||||
public const string TelecrystalCurrencyPrototype = "Telecrystal";
|
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>
|
/// <summary>
|
||||||
/// Adds an uplink to the target
|
/// Adds an uplink to the target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -37,7 +26,7 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
/// <param name="uplinkPresetId">The id of the storepreset</param>
|
/// <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>
|
/// <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>
|
/// <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
|
// Try to find target item
|
||||||
if (uplinkEntity == null)
|
if (uplinkEntity == null)
|
||||||
@@ -47,11 +36,10 @@ namespace Content.Server.Traitor.Uplink
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EnsureComp<UplinkComponent>(uplinkEntity.Value);
|
||||||
var store = EnsureComp<StoreComponent>(uplinkEntity.Value);
|
var store = EnsureComp<StoreComponent>(uplinkEntity.Value);
|
||||||
_store.InitializeFromPreset(uplinkPresetId, uplinkEntity.Value, store);
|
|
||||||
store.AccountOwner = user;
|
store.AccountOwner = user;
|
||||||
store.Balance.Clear();
|
store.Balance.Clear();
|
||||||
|
|
||||||
if (balance != null)
|
if (balance != null)
|
||||||
{
|
{
|
||||||
store.Balance.Clear();
|
store.Balance.Clear();
|
||||||
|
|||||||
@@ -1,46 +1,41 @@
|
|||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Store;
|
|
||||||
using Robust.Shared.Audio;
|
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;
|
||||||
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>
|
/// <summary>
|
||||||
/// This component manages a store which players can use to purchase different listings
|
/// 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.
|
/// through the ui. The currency, listings, and categories are defined in yaml.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent]
|
||||||
public sealed partial class StoreComponent : Component
|
public sealed partial class StoreComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
[DataField]
|
||||||
/// The default preset for the store. Is overriden by default values specified on the component.
|
public LocId Name = "store-ui-default-title";
|
||||||
/// </summary>
|
|
||||||
[DataField("preset", customTypeSerializer: typeof(PrototypeIdSerializer<StorePresetPrototype>))]
|
|
||||||
public string? Preset;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All the listing categories that are available on this store.
|
/// All the listing categories that are available on this store.
|
||||||
/// The available listings are partially based on the categories.
|
/// The available listings are partially based on the categories.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("categories", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<StoreCategoryPrototype>))]
|
[DataField]
|
||||||
public HashSet<string> Categories = new();
|
public HashSet<ProtoId<StoreCategoryPrototype>> Categories = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total amount of currency that can be used in the store.
|
/// The total amount of currency that can be used in the store.
|
||||||
/// The string represents the ID of te currency prototype, where the
|
/// The string represents the ID of te currency prototype, where the
|
||||||
/// float is that amount.
|
/// float is that amount.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("balance", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, CurrencyPrototype>))]
|
[DataField]
|
||||||
public Dictionary<string, FixedPoint2> Balance = new();
|
public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> Balance = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of currencies that can be inserted into this store.
|
/// The list of currencies that can be inserted into this store.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables(VVAccess.ReadOnly), DataField("currencyWhitelist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<CurrencyPrototype>))]
|
[DataField]
|
||||||
public HashSet<string> CurrencyWhitelist = new();
|
public HashSet<ProtoId<CurrencyPrototype>> CurrencyWhitelist = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The person who "owns" the store/account. Used if you want the listings to be fixed
|
/// 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>
|
/// <summary>
|
||||||
/// All listings, including those that aren't available to the buyer
|
/// All listings, including those that aren't available to the buyer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
public HashSet<ListingData> Listings = new();
|
public HashSet<ListingData> Listings = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,7 +66,7 @@ public sealed partial class StoreComponent : Component
|
|||||||
/// The total balance spent in this store. Used for refunds.
|
/// The total balance spent in this store. Used for refunds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables, DataField]
|
[ViewVariables, DataField]
|
||||||
public Dictionary<string, FixedPoint2> BalanceSpent = new();
|
public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> BalanceSpent = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls if the store allows refunds
|
/// Controls if the store allows refunds
|
||||||
@@ -95,7 +91,7 @@ public sealed partial class StoreComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sound played to the buyer when a purchase is succesfully made.
|
/// The sound played to the buyer when a purchase is succesfully made.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("buySuccessSound")]
|
[DataField]
|
||||||
public SoundSpecifier BuySuccessSound = new SoundPathSpecifier("/Audio/Effects/kaching.ogg");
|
public SoundSpecifier BuySuccessSound = new SoundPathSpecifier("/Audio/Effects/kaching.ogg");
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -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]
|
[Serializable, NetSerializable]
|
||||||
public sealed class StoreRequestUpdateInterfaceMessage : BoundUserInterfaceMessage
|
public sealed class StoreRequestUpdateInterfaceMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,3 +8,6 @@ store-ui-traitor-warning = Operatives must lock their uplinks after use to avoid
|
|||||||
store-withdraw-button-ui = Withdraw {$currency}
|
store-withdraw-button-ui = Withdraw {$currency}
|
||||||
store-ui-button-out-of-stock = {""} (Out of Stock)
|
store-ui-button-out-of-stock = {""} (Out of Stock)
|
||||||
store-not-account-owner = This {$store} is not bound to you!
|
store-not-account-owner = This {$store} is not bound to you!
|
||||||
|
|
||||||
|
store-preset-name-uplink = Uplink
|
||||||
|
store-preset-name-spellbook = Spellbook
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: CrateSyndicateSurplusBundle
|
id: CrateSyndicateSurplusBundle
|
||||||
parent: CrateSyndicate
|
parent: [ CrateSyndicate, StorePresetUplink ]
|
||||||
name: Syndicate surplus crate
|
name: Syndicate surplus crate
|
||||||
description: Contains 50 telecrystals worth of completely random Syndicate items. It can be useless junk or really good.
|
description: Contains 50 telecrystals worth of completely random Syndicate items. It can be useless junk or really good.
|
||||||
components:
|
components:
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CrateSyndicateSuperSurplusBundle
|
id: CrateSyndicateSuperSurplusBundle
|
||||||
parent: CrateSyndicate
|
parent: [ CrateSyndicate, StorePresetUplink ]
|
||||||
name: Syndicate super surplus crate
|
name: Syndicate super surplus crate
|
||||||
description: Contains 125 telecrystals worth of completely random Syndicate items.
|
description: Contains 125 telecrystals worth of completely random Syndicate items.
|
||||||
components:
|
components:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
abstract: true
|
abstract: true
|
||||||
parent: BaseItem
|
parent: [ BaseItem, StorePresetUplink ] #PDA's have uplinks so they have to inherit the data.
|
||||||
id: BasePDA
|
id: BasePDA
|
||||||
name: PDA
|
name: PDA
|
||||||
description: Personal Data Assistant.
|
description: Personal Data Assistant.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
id: WizardsGrimoire
|
id: WizardsGrimoire
|
||||||
name: wizards grimoire
|
name: wizards grimoire
|
||||||
suffix: Wizard
|
suffix: Wizard
|
||||||
parent: BaseItem
|
parent: [ BaseItem, StorePresetSpellbook ]
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Misc/books.rsi
|
sprite: Objects/Misc/books.rsi
|
||||||
@@ -46,7 +46,6 @@
|
|||||||
- type: Store
|
- type: Store
|
||||||
refundAllowed: true
|
refundAllowed: true
|
||||||
ownerOnly: true # get your own tome!
|
ownerOnly: true # get your own tome!
|
||||||
preset: StorePresetSpellbook
|
|
||||||
balance:
|
balance:
|
||||||
WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
|
WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
|
||||||
|
|
||||||
@@ -55,12 +54,11 @@
|
|||||||
id: WizardsGrimoireNoRefund
|
id: WizardsGrimoireNoRefund
|
||||||
name: wizards grimoire
|
name: wizards grimoire
|
||||||
suffix: Wizard, No Refund
|
suffix: Wizard, No Refund
|
||||||
parent: WizardsGrimoire
|
parent: [ WizardsGrimoire, StorePresetSpellbook ]
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
refundAllowed: false
|
refundAllowed: false
|
||||||
ownerOnly: true # get your own tome!
|
ownerOnly: true # get your own tome!
|
||||||
preset: StorePresetSpellbook
|
|
||||||
balance:
|
balance:
|
||||||
WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
|
WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@
|
|||||||
- Cuffable # useless if you cant be cuffed
|
- Cuffable # useless if you cant be cuffed
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseSubdermalImplant
|
parent: [ BaseSubdermalImplant, StorePresetUplink ]
|
||||||
id: UplinkImplant
|
id: UplinkImplant
|
||||||
name: uplink implant
|
name: uplink implant
|
||||||
description: This implant lets the user access a hidden Syndicate uplink at will.
|
description: This implant lets the user access a hidden Syndicate uplink at will.
|
||||||
@@ -155,7 +155,6 @@
|
|||||||
components:
|
components:
|
||||||
- Hands # prevent mouse buying grenade penguin since its not telepathic
|
- Hands # prevent mouse buying grenade penguin since its not telepathic
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 0
|
Telecrystal: 0
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
# Uplinks
|
# Uplinks
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseItem
|
parent: [ BaseItem, StorePresetUplink ]
|
||||||
id: BaseUplinkRadio
|
id: BaseUplinkRadio
|
||||||
name: syndicate uplink
|
name: syndicate uplink
|
||||||
description: Suspiciously looking old radio...
|
description: Suspiciously looking old radio...
|
||||||
@@ -68,7 +68,6 @@
|
|||||||
- type: ActivatableUI
|
- type: ActivatableUI
|
||||||
key: enum.StoreUiKey.Key
|
key: enum.StoreUiKey.Key
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 0
|
Telecrystal: 0
|
||||||
|
|
||||||
@@ -78,7 +77,6 @@
|
|||||||
suffix: 20 TC
|
suffix: 20 TC
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 20
|
Telecrystal: 20
|
||||||
|
|
||||||
@@ -88,7 +86,6 @@
|
|||||||
suffix: 25 TC
|
suffix: 25 TC
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 25
|
Telecrystal: 25
|
||||||
|
|
||||||
@@ -99,7 +96,6 @@
|
|||||||
suffix: 40 TC, NukeOps
|
suffix: 40 TC, NukeOps
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 40
|
Telecrystal: 40
|
||||||
- type: Tag
|
- type: Tag
|
||||||
@@ -112,7 +108,6 @@
|
|||||||
suffix: 60 TC, LoneOps
|
suffix: 60 TC, LoneOps
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 60
|
Telecrystal: 60
|
||||||
- type: Tag
|
- type: Tag
|
||||||
@@ -125,6 +120,5 @@
|
|||||||
suffix: DEBUG
|
suffix: DEBUG
|
||||||
components:
|
components:
|
||||||
- type: Store
|
- type: Store
|
||||||
preset: StorePresetUplink
|
|
||||||
balance:
|
balance:
|
||||||
Telecrystal: 99999
|
Telecrystal: 99999
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
- type: storePreset
|
- type: entity
|
||||||
id: StorePresetUplink
|
id: StorePresetUplink
|
||||||
storeName: Uplink
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: Store
|
||||||
|
name: store-preset-name-uplink
|
||||||
categories:
|
categories:
|
||||||
- UplinkWeaponry
|
- UplinkWeaponry
|
||||||
- UplinkAmmo
|
- UplinkAmmo
|
||||||
@@ -15,10 +18,15 @@
|
|||||||
- UplinkPointless
|
- UplinkPointless
|
||||||
currencyWhitelist:
|
currencyWhitelist:
|
||||||
- Telecrystal
|
- Telecrystal
|
||||||
|
balance:
|
||||||
|
Telecrystal: 0
|
||||||
|
|
||||||
- type: storePreset
|
- type: entity
|
||||||
id: StorePresetSpellbook
|
id: StorePresetSpellbook
|
||||||
storeName: Spellbook
|
abstract: true
|
||||||
|
components:
|
||||||
|
- type: Store
|
||||||
|
name: store-preset-name-spellbook
|
||||||
categories:
|
categories:
|
||||||
- SpellbookOffensive #Fireball, Rod Form
|
- SpellbookOffensive #Fireball, Rod Form
|
||||||
- SpellbookDefensive #Magic Missile, Wall of Force
|
- SpellbookDefensive #Magic Missile, Wall of Force
|
||||||
|
|||||||
Reference in New Issue
Block a user