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

Feature/issue 26107 #1

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c9e9d55
feat: #26107 uplink discounts for traitors and nukies
Mar 20, 2024
1e71c79
refactor: #26107 extracted discount label from price of StoreListingC…
Mar 21, 2024
8695be4
refactor: minor renaming
Mar 21, 2024
fdb5ce2
Merge remote-tracking branch 'origin/master' into feature/issue-26107
Mar 21, 2024
e864cb3
refactor: parametrized adding discounts to uplink store
Mar 21, 2024
60509f4
fix: #26107 prevent exception on empty discountOptions
Mar 22, 2024
1d32e95
feat: uplink now have 'Discounted' category which contains all discou…
Mar 22, 2024
5fe534d
merge with master
Mar 31, 2024
0fa938e
after merge fixups
Mar 31, 2024
b0a62d0
rename discount categories according to common sense
Apr 2, 2024
0e5f244
refactor: DiscountOptions is now optional (nullable) on ListingData
Apr 2, 2024
56e5309
add nullability check ignore for already checked listingData.Discount…
Apr 2, 2024
4728352
merge with master
May 5, 2024
42a59f5
fix after merge store menu ui
May 5, 2024
21265f6
remove unused using
May 5, 2024
6bb0705
final fix after merge conflicts
May 5, 2024
343c733
Merge remote-tracking branch 'origin/master' into feature/issue-26107
May 27, 2024
d885126
[refactor]: #26107 fix variables naming in UplinkSystem
Jul 11, 2024
fb38084
[merge] #26107 merge master
Jul 11, 2024
07e66fc
Merge remote-tracking branch 'origin/master' into feature/issue-26107
Jul 13, 2024
071f83a
fix: #26107 fix after merge
Jul 13, 2024
a3cc70d
refactor: #26107 now supports discountDownUntil on ListingItem, inste…
Jul 14, 2024
856d5c3
feat: #26107 support multiple currency discount in store on side of d…
Jul 14, 2024
84a8d40
refactor: #26107 extracted discounts initialization to separate syste…
Jul 14, 2024
b8b7ec1
refactor: #26107 move more code from storesystem to StoreDiscountComp…
Jul 15, 2024
30b45ef
refactor: #26107 separated StoreSystem and StoreDiscountSystem using …
Jul 15, 2024
7fc197b
fix: #26107 placed not-nullable variable initialization in ListingDat…
Jul 15, 2024
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
10 changes: 8 additions & 2 deletions Content.Client/Store/Ui/StoreBoundUserInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using JetBrains.Annotations;
using System.Linq;
using Content.Shared.Store.Components;
using Content.Shared.StoreDiscount.Components;
using Robust.Shared.Prototypes;

namespace Content.Client.Store.Ui;
Expand All @@ -20,6 +21,9 @@ public sealed class StoreBoundUserInterface : BoundUserInterface
[ViewVariables]
private HashSet<ListingData> _listings = new();

[ViewVariables]
private StoreDiscountData[] _discounts = default!;

public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
Expand Down Expand Up @@ -68,8 +72,10 @@ protected override void UpdateState(BoundUserInterfaceState state)
{
case StoreUpdateState msg:
_listings = msg.Listings;
_discounts = msg.Discounts;

_menu?.UpdateBalance(msg.Balance);

UpdateListingsWithSearchFilter();
_menu?.SetFooterVisibility(msg.ShowFooter);
_menu?.UpdateRefund(msg.AllowRefund);
Expand Down Expand Up @@ -97,7 +103,7 @@ private void UpdateListingsWithSearchFilter()
filteredListings.RemoveWhere(listingData => !ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listingData, _prototypeManager).Trim().ToLowerInvariant().Contains(_search) &&
!ListingLocalisationHelpers.GetLocalisedDescriptionOrEntityDescription(listingData, _prototypeManager).Trim().ToLowerInvariant().Contains(_search));
}
_menu.PopulateStoreCategoryButtons(filteredListings);
_menu.UpdateListing(filteredListings.ToList());
_menu.PopulateStoreCategoryButtons(filteredListings, _discounts);
_menu.UpdateListing(filteredListings.ToList(), _discounts);
}
}
2 changes: 2 additions & 0 deletions Content.Client/Store/Ui/StoreListingControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<BoxContainer Margin="8,8,8,8" Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Name="StoreItemName" HorizontalExpand="True" />
<Label Name="DiscountSubText"
HorizontalAlignment="Right"/>
<Button
Name="StoreItemBuyButton"
MinWidth="64"
Expand Down
5 changes: 4 additions & 1 deletion Content.Client/Store/Ui/StoreListingControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public sealed partial class StoreListingControl : Control

private readonly bool _hasBalance;
private readonly string _price;
public StoreListingControl(ListingData data, string price, bool hasBalance, Texture? texture = null)
private readonly string _discount;
public StoreListingControl(ListingData data, string price, string discount, bool hasBalance, Texture? texture = null)
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
Expand All @@ -31,6 +32,7 @@ public StoreListingControl(ListingData data, string price, bool hasBalance, Text
_data = data;
_hasBalance = hasBalance;
_price = price;
_discount = discount;

StoreItemName.Text = ListingLocalisationHelpers.GetLocalisedNameOrEntityName(_data, _prototype);
StoreItemDescription.SetMessage(ListingLocalisationHelpers.GetLocalisedDescriptionOrEntityDescription(_data, _prototype));
Expand Down Expand Up @@ -63,6 +65,7 @@ private void UpdateBuyButtonText()
}
else
{
DiscountSubText.Text = _discount;
StoreItemBuyButton.Text = _price;
}
}
Expand Down
100 changes: 84 additions & 16 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.Shared.StoreDiscount.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
Expand All @@ -16,6 +17,8 @@ namespace Content.Client.Store.Ui;
[GenerateTypedNameReferences]
public sealed partial class StoreMenu : DefaultWindow
{
private const string DiscountedCategoryPrototypeKey = "DiscountedItems";

[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;

Expand All @@ -31,6 +34,7 @@ public sealed partial class StoreMenu : DefaultWindow
public string CurrentCategory = string.Empty;

private List<ListingData> _cachedListings = new();
private StoreDiscountData[] _cachedDiscounts = Array.Empty<StoreDiscountData>();

public StoreMenu()
{
Expand Down Expand Up @@ -68,22 +72,32 @@ public void UpdateBalance(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> ba
WithdrawButton.Disabled = disabled;
}

public void UpdateListing(List<ListingData> listings)
public void UpdateListing(List<ListingData> listings, StoreDiscountData[] discounts)
{
_cachedListings = listings;
_cachedDiscounts = discounts;
UpdateListing();
}

public void UpdateListing()
{
var sorted = _cachedListings.OrderBy(l => l.Priority).ThenBy(l => l.Cost.Values.Sum());
var sorted = _cachedListings.OrderBy(l => l.Priority)
.ThenBy(l => l.Cost.Values.Sum());

// should probably chunk these out instead. to-do if this clogs the internet tubes.
// maybe read clients prototypes instead?
ClearListings();
var storeDiscounts = _cachedDiscounts.Where(x => x.Count > 0)
.ToDictionary(x => x.ListingId);

foreach (var item in sorted)
{
AddListingGui(item);
storeDiscounts.TryGetValue(item.ID, out var discountData);
if (discountData != null)
{
item.Categories.Add(DiscountedCategoryPrototypeKey);
}
AddListingGui(item, discountData);
}
}

Expand Down Expand Up @@ -114,13 +128,13 @@ private void OnRefundButtonDown(BaseButton.ButtonEventArgs args)
OnRefundAttempt?.Invoke(args);
}

private void AddListingGui(ListingData listing)
private void AddListingGui(ListingData listing, StoreDiscountData? discountData)
{
if (!listing.Categories.Contains(CurrentCategory))
return;

var listingPrice = listing.Cost;
var hasBalance = HasListingPrice(Balance, listingPrice);
var hasBalance = CanBuyListing(Balance, listingPrice, discountData);

var spriteSys = _entityManager.EntitySysManager.GetEntitySystem<SpriteSystem>();

Expand All @@ -143,50 +157,98 @@ private void AddListingGui(ListingData listing)
}
}

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

var newListing = new StoreListingControl(listing, listingInStock, discount, hasBalance, texture);
newListing.StoreItemBuyButton.OnButtonDown += args
=> OnListingButtonPressed?.Invoke(args, listing);

StoreListingsContainer.AddChild(newListing);
}

public bool HasListingPrice(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> currency, Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> price)
public bool CanBuyListing(Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> currentBalance, Dictionary<ProtoId<CurrencyPrototype>, FixedPoint2> price, StoreDiscountData? discountData)
{
foreach (var type in price)
foreach (var (currency, value) in price)
{
if (!currency.ContainsKey(type.Key))
if (!currentBalance.ContainsKey(currency))
return false;

if (currency[type.Key] < type.Value)
var amount = value;
if (discountData != null && discountData.DiscountAmountByCurrency.TryGetValue(currency, out var discount))
{
amount -= discount;
}

if (currentBalance[currency] < amount)
return false;
}

return true;
}

public string GetListingPriceString(ListingData listing)
private (string Price, string Discount) GetListingPriceString(ListingData listing, StoreDiscountData? discountData)
{
var text = string.Empty;
var discountMessage = string.Empty;

var discountMessageList = new List<(FixedPoint2 DiscountPercent, CurrencyPrototype CurrencyPrototype)>();

if (listing.Cost.Count < 1)
text = Loc.GetString("store-currency-free");
else
{
foreach (var (type, amount) in listing.Cost)
{
var currency = _prototypeManager.Index(type);
text += Loc.GetString("store-ui-price-display", ("amount", amount),
("currency", Loc.GetString(currency.DisplayName, ("amount", amount))));
var currency = _prototypeManager.Index<CurrencyPrototype>(type);

var totalAmount = amount;
if (discountData?.DiscountAmountByCurrency.TryGetValue(type, out var discountBy) != null
&& discountBy > 0)
{
var discountPercent = (float)discountBy.Value / totalAmount.Value;
discountMessageList.Add((discountPercent, currency));

totalAmount -= discountBy;
}

text += Loc.GetString(
"store-ui-price-display",
("amount", totalAmount),
("currency", Loc.GetString(currency.DisplayName, ("amount", totalAmount)))
);
}


if (discountMessageList.Count > 1)
{
var discountMessagesPerCurrency = discountMessageList.Select(
x => Loc.GetString(
"store-ui-discount-display-with-currency",
("amount", x.DiscountPercent.Value),
("currency", Loc.GetString(x.CurrencyPrototype.DisplayName))
)
);
discountMessage = string.Join(',', discountMessagesPerCurrency);

}
else if (discountMessageList.Count == 1)
{
discountMessage = Loc.GetString(
"store-ui-discount-display",
("amount", (discountMessageList[0].DiscountPercent.Value))
);
}
}

return text.TrimEnd();
return (text.TrimEnd(), discountMessage);
}

private void ClearListings()
{
StoreListingsContainer.Children.Clear();
}

public void PopulateStoreCategoryButtons(HashSet<ListingData> listings)
public void PopulateStoreCategoryButtons(HashSet<ListingData> listings, StoreDiscountData[] discounts)
{
var allCategories = new List<StoreCategoryPrototype>();
foreach (var listing in listings)
Expand All @@ -199,6 +261,12 @@ public void PopulateStoreCategoryButtons(HashSet<ListingData> listings)
}
}

if (discounts.Any(x => x.Count > 0))
{
var proto = _prototypeManager.Index<StoreCategoryPrototype>(DiscountedCategoryPrototypeKey);
allCategories.Add(proto);
}

allCategories = allCategories.OrderBy(c => c.Priority).ToList();

// This will reset the Current Category selection if nothing matches the search.
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool
// creadth: we need to create uplink for the antag.
// PDA should be in place already
var pda = _uplink.FindUplinkTarget(traitor);
if (pda == null || !_uplink.AddUplink(traitor, startingBalance))
if (pda == null || !_uplink.AddUplink(traitor, startingBalance, giveDiscounts: true))
return false;

// Give traitors their codewords and uplink code to keep in their character info menu
Expand Down
Loading