From b34ade60d87a8ccc37a9f12e3282d695bbb8e8ee Mon Sep 17 00:00:00 2001 From: Aviu00 <93730715+Aviu00@users.noreply.github.com> Date: Fri, 4 Aug 2023 03:44:17 +0300 Subject: [PATCH] Uplink sales (#264) --- Content.Client/Store/Ui/StoreMenu.xaml.cs | 7 ++++ .../Store/Systems/StoreSystem.Listings.cs | 19 ++++++++- Content.Server/Store/Systems/StoreSystem.cs | 40 +++++++++++++++++++ Content.Shared/Store/ListingPrototype.cs | 11 +++++ Content.Shared/Store/StorePresetPrototype.cs | 4 ++ Content.Shared/White/Sales/SalesSpecifier.cs | 38 ++++++++++++++++++ .../Prototypes/Catalog/uplink_catalog.yml | 3 ++ Resources/Prototypes/Store/presets.yml | 8 ++++ .../Prototypes/White/store_categories.yml | 4 ++ 9 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 Content.Shared/White/Sales/SalesSpecifier.cs create mode 100644 Resources/Prototypes/White/store_categories.yml diff --git a/Content.Client/Store/Ui/StoreMenu.xaml.cs b/Content.Client/Store/Ui/StoreMenu.xaml.cs index 835e2c93eb..082ddec538 100644 --- a/Content.Client/Store/Ui/StoreMenu.xaml.cs +++ b/Content.Client/Store/Ui/StoreMenu.xaml.cs @@ -159,7 +159,14 @@ public sealed partial class StoreMenu : DefaultWindow canBuy = false; } + if (listing.SaleAmount > 0) // WD + listingName += $" [СКИДКА] ({listing.SaleAmount}%!)"; + var newListing = new StoreListingControl(listingName, listingDesc, listingInStock, canBuy, texture); + + if (listing.SaleAmount > 0) // WD + newListing.StoreItemBuyButton.AddStyleClass("ButtonColorRed"); + newListing.StoreItemBuyButton.OnButtonDown += args => OnListingButtonPressed?.Invoke(args, listing); diff --git a/Content.Server/Store/Systems/StoreSystem.Listings.cs b/Content.Server/Store/Systems/StoreSystem.Listings.cs index b5d1ae79be..2b2d86350e 100644 --- a/Content.Server/Store/Systems/StoreSystem.Listings.cs +++ b/Content.Server/Store/Systems/StoreSystem.Listings.cs @@ -1,4 +1,6 @@ +using System.Linq; using Content.Server.Store.Components; +using Content.Shared.FixedPoint; using Content.Shared.Store; namespace Content.Server.Store.Systems; @@ -27,7 +29,22 @@ public sealed partial class StoreSystem foreach (var listing in allListings) { - allData.Add((ListingData) listing.Clone()); + // WD EDIT + var listingData = (ListingData) listing.Clone(); + if (_sales.TryGetValue(listing, out var sale)) + { + var newCost = listing.Cost.ToDictionary(x => x.Key, + x => FixedPoint2.New(Math.Max(1, (int) MathF.Round(x.Value.Float() * sale.Item1)))); + + if (listing.Cost.Any(x => x.Value.Int() != newCost[x.Key].Int())) + { + listingData.Cost = newCost; + listingData.SaleAmount = 100 - (int) MathF.Round(sale.Item1 * 100); + listingData.Categories = new() {sale.Item2}; + } + } + allData.Add(listingData); + // WD EDIT END } return allData; diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index d5b17f440e..091a1f0c9d 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -10,6 +10,8 @@ using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Prototypes; using System.Linq; +using Content.Server.GameTicking.Events; +using Robust.Shared.Random; namespace Content.Server.Store.Systems; @@ -21,6 +23,9 @@ public sealed partial class StoreSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IRobustRandom _random = default!; // WD + + private Dictionary _sales = new(); // WD public override void Initialize() { @@ -34,10 +39,45 @@ public sealed partial class StoreSystem : EntitySystem SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnImplantActivate); + SubscribeLocalEvent(OnRoundStart); // WD + InitializeUi(); InitializeCommand(); } + // WD START + private void OnRoundStart(RoundStartingEvent ev) + { + CalculateSales(); + } + + private void CalculateSales() + { + _sales.Clear(); + foreach (var store in _proto.EnumeratePrototypes()) + { + if (!store.Sales.Enabled) + continue; + + var count = _random.Next(store.Sales.MinItems, store.Sales.MaxItems + 1); + + var storeListings = _proto.EnumeratePrototypes() + .Where(l => !l.SaleBlacklist && l.Cost.Any(x => x.Value > 1) && !_sales.ContainsKey(l) && + store.Categories.Overlaps(l.Categories)).OrderBy(_ => _random.Next()).Take(count) + .ToDictionary(l => l, + _ => (GetSale(store.Sales.MinMultiplier, store.Sales.MaxMultiplier), store.Sales.SalesCategory)); + + _sales = _sales.Concat(storeListings).ToDictionary(x => x.Key, x => x.Value); + } + } + + private float GetSale(float minMultiplier, float maxMultiplier) + { + return _random.NextFloat() * (maxMultiplier - minMultiplier) + minMultiplier; + } + // WD END + + private void OnMapInit(EntityUid uid, StoreComponent component, MapInitEvent args) { RefreshAllListings(component); diff --git a/Content.Shared/Store/ListingPrototype.cs b/Content.Shared/Store/ListingPrototype.cs index e18a43544c..deb67a54b7 100644 --- a/Content.Shared/Store/ListingPrototype.cs +++ b/Content.Shared/Store/ListingPrototype.cs @@ -94,6 +94,13 @@ public partial class ListingData : IEquatable, ICloneable [DataField("restockTime")] public int RestockTime; + // WD START + [DataField("saleBlacklist")] + public bool SaleBlacklist; + + public int SaleAmount; + // WD END + public bool Equals(ListingData? listing) { if (listing == null) @@ -147,6 +154,10 @@ public partial class ListingData : IEquatable, ICloneable ProductEvent = ProductEvent, PurchaseAmount = PurchaseAmount, RestockTime = RestockTime, + // WD START + SaleBlacklist = SaleBlacklist, + SaleAmount = SaleAmount, + // WD END }; } } diff --git a/Content.Shared/Store/StorePresetPrototype.cs b/Content.Shared/Store/StorePresetPrototype.cs index ce7f0312b6..62d76ed3a2 100644 --- a/Content.Shared/Store/StorePresetPrototype.cs +++ b/Content.Shared/Store/StorePresetPrototype.cs @@ -2,6 +2,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; using Content.Shared.FixedPoint; +using Content.Shared.White.Sales; namespace Content.Shared.Store; @@ -38,4 +39,7 @@ public sealed partial class StorePresetPrototype : IPrototype /// [DataField("currencyWhitelist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] public HashSet CurrencyWhitelist { get; private set; } = new(); + + [DataField("sales")] + public SalesSpecifier Sales { get; private set; } = new(); // WD } diff --git a/Content.Shared/White/Sales/SalesSpecifier.cs b/Content.Shared/White/Sales/SalesSpecifier.cs new file mode 100644 index 0000000000..6c7b3cd60f --- /dev/null +++ b/Content.Shared/White/Sales/SalesSpecifier.cs @@ -0,0 +1,38 @@ +namespace Content.Shared.White.Sales; + +[DataDefinition] +public sealed class SalesSpecifier +{ + [DataField("enabled")] + public bool Enabled { get; } + + [DataField("minMultiplier")] + public float MinMultiplier { get; } + + [DataField("maxMultiplier")] + public float MaxMultiplier { get; } + + [DataField("minItems")] + public int MinItems { get; } + + [DataField("maxItems")] + public int MaxItems { get; } + + [DataField("salesCategory")] + public string SalesCategory { get; } = string.Empty; + + public SalesSpecifier() + { + } + + public SalesSpecifier(bool enabled, float minMultiplier, float maxMultiplier, int minItems, int maxItems, + string salesCategory) + { + Enabled = enabled; + MinMultiplier = minMultiplier; + MaxMultiplier = maxMultiplier; + MinItems = minItems; + MaxItems = maxItems; + SalesCategory = salesCategory; + } +} diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 64a3464229..659a381cc5 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -669,6 +669,7 @@ blacklist: tags: - NukeOpsUplink + saleBlacklist: true - type: listing id: UplinkDeathRattle @@ -854,6 +855,7 @@ blacklist: components: - SurplusBundle + saleBlacklist: true - type: listing id: UplinkSuperSurplusBundle @@ -873,6 +875,7 @@ blacklist: components: - SurplusBundle + saleBlacklist: true # Tools diff --git a/Resources/Prototypes/Store/presets.yml b/Resources/Prototypes/Store/presets.yml index e623f4c8cd..cc1c50440d 100644 --- a/Resources/Prototypes/Store/presets.yml +++ b/Resources/Prototypes/Store/presets.yml @@ -13,5 +13,13 @@ - UplinkJob - UplinkArmor - UplinkPointless + - UplinkSales currencyWhitelist: - Telecrystal + sales: + enabled: true + minMultiplier: 0.01 + maxMultiplier: 0.99 + minItems: 5 + maxItems: 10 + salesCategory: UplinkSales diff --git a/Resources/Prototypes/White/store_categories.yml b/Resources/Prototypes/White/store_categories.yml new file mode 100644 index 0000000000..d839634d1b --- /dev/null +++ b/Resources/Prototypes/White/store_categories.yml @@ -0,0 +1,4 @@ +- type: storeCategory + id: UplinkSales + name: Скидки! + priority: 10