Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Port] Uplink Discounts From White Dream #930

Merged
merged 5 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Content.Client/Store/Ui/StoreMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Content.Client.Message;
using Content.Shared.FixedPoint;
using Content.Shared.Store;
using Content.Client.Stylesheets;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
Expand Down Expand Up @@ -147,6 +148,10 @@ private void AddListingGui(ListingData listing)
}

var newListing = new StoreListingControl(listing, GetListingPriceString(listing), hasBalance, texture);

if (listing.DiscountValue > 0)
newListing.StoreItemBuyButton.AddStyleClass(StyleNano.ButtonColorDangerDefault.ToString());

newListing.StoreItemBuyButton.OnButtonDown += args
=> OnListingButtonPressed?.Invoke(args, listing);

Expand Down
6 changes: 6 additions & 0 deletions Content.Server/Store/Systems/StoreSystem.Ui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,12 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi
listing.PurchaseAmount++; //track how many times something has been purchased
_audio.PlayEntity(component.BuySuccessSound, msg.Session, uid); //cha-ching!

if (listing.SaleLimit != 0 && listing.DiscountValue > 0 && listing.PurchaseAmount >= listing.SaleLimit)
{
listing.DiscountValue = 0;
listing.Cost = listing.OldCost;
}

UpdateUserInterface(buyer, uid, component);
}

Expand Down
6 changes: 5 additions & 1 deletion Content.Server/Store/Systems/StoreSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using System.Linq;
using Content.Server.StoreDiscount;
using Robust.Shared.Utility;

namespace Content.Server.Store.Systems;
Expand All @@ -22,6 +23,7 @@ public sealed partial class StoreSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly StoreDiscountSystem _storeDiscount = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -199,6 +201,8 @@ public void InitializeFromPreset(StorePresetPrototype preset, EntityUid uid, Sto
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);

_storeDiscount.ApplyDiscounts(component.Listings, preset);

var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key);
if (ui != null)
{
Expand All @@ -225,7 +229,7 @@ public CurrencyInsertAttemptEvent(EntityUid user, EntityUid target, EntityUid us


/// <summary>
/// Nyano/DeltaV Code. For penguin bombs and what not.
/// Nyano/DeltaV Code. For penguin bombs and what not.
/// Raised on an item when it is purchased.
/// An item may need to set it upself up for its purchaser.
/// For example, to make sure it isn't hostile to them or
Expand Down
55 changes: 55 additions & 0 deletions Content.Server/StoreDiscount/StoreDiscountSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Linq;
using Content.Shared.FixedPoint;
using Content.Shared.Store;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server.StoreDiscount;

public sealed class StoreDiscountSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;

public void ApplyDiscounts(IEnumerable<ListingData> listings, StorePresetPrototype store)
{
if (!store.Sales.Enabled)
return;

var count = _random.Next(store.Sales.MinItems, store.Sales.MaxItems + 1);

listings = listings
.Where(l =>
!l.SaleBlacklist
&& l.Cost.Any(x => x.Value > 1)
&& store.Categories.Overlaps(ChangedFormatCategories(l.Categories)))
.OrderBy(_ => _random.Next()).Take(count).ToList();

foreach (var listing in listings)
{
var sale = GetDiscount(store.Sales.MinMultiplier, store.Sales.MaxMultiplier);
var newCost = listing.Cost.ToDictionary(x => x.Key,
x => FixedPoint2.New(Math.Max(1, (int) MathF.Round(x.Value.Float() * sale))));

if (listing.Cost.All(x => x.Value.Int() == newCost[x.Key].Int()))
continue;

var key = listing.Cost.First(x => x.Value > 0).Key;
listing.OldCost = listing.Cost;
listing.DiscountValue = 100 - (newCost[key] / listing.Cost[key] * 100).Int();
listing.Cost = newCost;
listing.Categories = new() {store.Sales.SalesCategory};
}
}

private IEnumerable<string> ChangedFormatCategories(List<ProtoId<StoreCategoryPrototype>> categories)
{
var modified = from p in categories select p.Id;

return modified;
}

private float GetDiscount(float minMultiplier, float maxMultiplier)
{
return _random.NextFloat() * (maxMultiplier - minMultiplier) + minMultiplier;
}
}
5 changes: 5 additions & 0 deletions Content.Shared/Store/ListingLocalisationHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public static string GetLocalisedNameOrEntityName(ListingData listingData, IProt
else if (listingData.ProductEntity != null)
name = prototypeManager.Index(listingData.ProductEntity.Value).Name;

if (listingData.DiscountValue > 0)
name += " " + Loc.GetString("store-sales-amount", ("amount", listingData.DiscountValue));
else if (listingData.OldCost.Count > 0)
name += " " + Loc.GetString("store-sales-over");

return name;
}

Expand Down
18 changes: 18 additions & 0 deletions Content.Shared/Store/ListingPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ public partial class ListingData : IEquatable<ListingData>, ICloneable
[DataField]
public TimeSpan RestockTime = TimeSpan.Zero;

[DataField]
public int SaleLimit = 3;

[DataField]
public bool SaleBlacklist;

public int DiscountValue;

public Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> OldCost = new();

[DataField]
public List<string> Components = new();

public bool Equals(ListingData? listing)
{
if (listing == null)
Expand Down Expand Up @@ -166,6 +179,11 @@ public object Clone()
ProductEvent = ProductEvent,
PurchaseAmount = PurchaseAmount,
RestockTime = RestockTime,
SaleLimit = SaleLimit,
SaleBlacklist = SaleBlacklist,
DiscountValue = DiscountValue,
OldCost = OldCost,
Components = Components,
};
}
}
Expand Down
4 changes: 4 additions & 0 deletions Content.Shared/Store/StorePresetPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Shared.StoreDiscount;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
Expand Down Expand Up @@ -38,4 +39,7 @@ public sealed partial class StorePresetPrototype : IPrototype
/// </summary>
[DataField("currencyWhitelist", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<CurrencyPrototype>))]
public HashSet<string> CurrencyWhitelist { get; private set; } = new();

[DataField]
public SalesSpecifier Sales { get; private set; } = new();
}
38 changes: 38 additions & 0 deletions Content.Shared/StoreDiscount/SalesSpecifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace Content.Shared.StoreDiscount;

[DataDefinition]
public sealed partial class SalesSpecifier
{
[DataField]
public bool Enabled { get; private set; }

[DataField]
public float MinMultiplier { get; private set; }

[DataField]
public float MaxMultiplier { get; private set; }

[DataField]
public int MinItems { get; private set; }

[DataField]
public int MaxItems { get; private set; }

[DataField]
public string SalesCategory { get; private set; } = 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;
}
}
2 changes: 2 additions & 0 deletions Resources/Locale/en-US/store/sales.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
store-sales-amount = [DISCOUNT] { $amount }%!
store-sales-over = [The sale is over]
2 changes: 2 additions & 0 deletions Resources/Locale/ru-RU/store/sales.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
store-sales-amount = [СКИДКА] { $amount }%!
store-sales-over = [Скидка закончилась]
Loading
Loading