* feat: #26107 uplink discounts for traitors and nukies * refactor: #26107 extracted discount label from price of StoreListingControl * refactor: minor renaming * refactor: parametrized adding discounts to uplink store * fix: #26107 prevent exception on empty discountOptions * feat: uplink now have 'Discounted' category which contains all discounted items on this session. * after merge fixups * rename discount categories according to common sense * refactor: DiscountOptions is now optional (nullable) on ListingData * add nullability check ignore for already checked listingData.DiscountOptions * fix after merge store menu ui * remove unused using * final fix after merge conflicts * [refactor]: #26107 fix variables naming in UplinkSystem * fix: #26107 fix after merge * refactor: #26107 now supports discountDownUntil on ListingItem, instead of % of discount * feat: #26107 support multiple currency discount in store on side of discount message label * refactor: #26107 extracted discounts initialization to separate system. StoreDiscountData are spread as array and not list now * refactor: #26107 move more code from storesystem to StoreDiscountComponent * refactor: #26107 separated StoreSystem and StoreDiscountSystem using events * fix: #26107 placed not-nullable variable initialization in ListingData for tests * refactor: #26107 minor renaming, xml-docs * fix: #26107 changed most of discounts to be down to half price for balance purposes * ids used in with discounts are now ProtoIds, dicountCategories are now prototypes, code with weights simplified * decoupled storesystem and store discount system * xml-docs * refactor: #26107 xml-doc for StoreDiscountSystem * is now a thing (tmp) * fix: compilation errors + StoreDiscountData.DiscountCategoryId * refactor: rename ListingDataWithCostModifiers, fix all cost related code, enpittyfy performance, uglify uplink_catalog * refactor: removed unused code, more StoreDiscountSystem docs, simplify code * refactor: moved discount category logic to respective system, now creating ListingData c-tor clones all mutable fields as expected * refactor: rename back (its not prototype) * refactor: move ListingItemsInitializingEvent to file with handling logic * refactor: comments for StoreBuyFinishedEvent handling, more logging * refactor: moved StoreInitializedEvent, xml-doc * refactor: simplify StoreDiscountSystem code (reduce nesting) + xml-doc * refactor: restore old listing data cost field name * refactor: fix linter in uplink_catalog.yml * refactor: xml-doc for ListingDataWithCostModifiers * refactor: limit usage of ListingData in favour of ListingDataWithCostModifiers * refactor: purged linq, removed custom datafield names, minor cleanup * refactor: removed double-allocation on getting available listings * refactor: StoreSystem.OnBuyRequest now uses component.FullListingsCatalog as reference point (as it was in original code) * fix: minor discount categories on uplink items changes following design overview * refactor: StoreBuyListingMessage now uses protoId and not whole object * refactor: store refund and discount integration test, RefreshAllListings now translates previous cost modifiers to refreshed list, if state previous to refresh had any listing items --------- Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Store;
|
||||
using Content.Shared.Store.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -13,25 +14,43 @@ public sealed partial class StoreSystem
|
||||
/// <param name="component">The store to refresh</param>
|
||||
public void RefreshAllListings(StoreComponent component)
|
||||
{
|
||||
component.Listings = GetAllListings();
|
||||
var previousState = component.FullListingsCatalog;
|
||||
var newState = GetAllListings();
|
||||
// if we refresh list with existing cost modifiers - they will be removed,
|
||||
// need to restore them
|
||||
if (previousState.Count != 0)
|
||||
{
|
||||
foreach (var previousStateListingItem in previousState)
|
||||
{
|
||||
if (!previousStateListingItem.IsCostModified
|
||||
|| !TryGetListing(newState, previousStateListingItem.ID, out var found))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var (modifierSourceId, costModifier) in previousStateListingItem.CostModifiersBySourceId)
|
||||
{
|
||||
found.AddCostModifier(modifierSourceId, costModifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component.FullListingsCatalog = newState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all listings from a prototype.
|
||||
/// </summary>
|
||||
/// <returns>All the listings</returns>
|
||||
public HashSet<ListingData> GetAllListings()
|
||||
public HashSet<ListingDataWithCostModifiers> GetAllListings()
|
||||
{
|
||||
var allListings = _proto.EnumeratePrototypes<ListingPrototype>();
|
||||
|
||||
var allData = new HashSet<ListingData>();
|
||||
|
||||
foreach (var listing in allListings)
|
||||
var clones = new HashSet<ListingDataWithCostModifiers>();
|
||||
foreach (var prototype in _proto.EnumeratePrototypes<ListingPrototype>())
|
||||
{
|
||||
allData.Add((ListingData) listing.Clone());
|
||||
clones.Add(new ListingDataWithCostModifiers(prototype));
|
||||
}
|
||||
|
||||
return allData;
|
||||
return clones;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,7 +58,7 @@ public sealed partial class StoreSystem
|
||||
/// </summary>
|
||||
/// <param name="component">The store to add the listing to</param>
|
||||
/// <param name="listingId">The id of the listing</param>
|
||||
/// <returns>Whetehr or not the listing was added successfully</returns>
|
||||
/// <returns>Whether or not the listing was added successfully</returns>
|
||||
public bool TryAddListing(StoreComponent component, string listingId)
|
||||
{
|
||||
if (!_proto.TryIndex<ListingPrototype>(listingId, out var proto))
|
||||
@@ -47,6 +66,7 @@ public sealed partial class StoreSystem
|
||||
Log.Error("Attempted to add invalid listing.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryAddListing(component, proto);
|
||||
}
|
||||
|
||||
@@ -56,9 +76,9 @@ public sealed partial class StoreSystem
|
||||
/// <param name="component">The store to add the listing to</param>
|
||||
/// <param name="listing">The listing</param>
|
||||
/// <returns>Whether or not the listing was add successfully</returns>
|
||||
public bool TryAddListing(StoreComponent component, ListingData listing)
|
||||
public bool TryAddListing(StoreComponent component, ListingPrototype listing)
|
||||
{
|
||||
return component.Listings.Add(listing);
|
||||
return component.FullListingsCatalog.Add(new ListingDataWithCostModifiers(listing));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,9 +88,9 @@ public sealed partial class StoreSystem
|
||||
/// <param name="store"></param>
|
||||
/// <param name="component">The store the listings are coming from.</param>
|
||||
/// <returns>The available listings.</returns>
|
||||
public IEnumerable<ListingData> GetAvailableListings(EntityUid buyer, EntityUid store, StoreComponent component)
|
||||
public IEnumerable<ListingDataWithCostModifiers> GetAvailableListings(EntityUid buyer, EntityUid store, StoreComponent component)
|
||||
{
|
||||
return GetAvailableListings(buyer, component.Listings, component.Categories, store);
|
||||
return GetAvailableListings(buyer, component.FullListingsCatalog, component.Categories, store);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,11 +101,12 @@ 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(
|
||||
public IEnumerable<ListingDataWithCostModifiers> GetAvailableListings(
|
||||
EntityUid buyer,
|
||||
HashSet<ListingData>? listings,
|
||||
IReadOnlyCollection<ListingDataWithCostModifiers>? listings,
|
||||
HashSet<ProtoId<StoreCategoryPrototype>> categories,
|
||||
EntityUid? storeEntity = null)
|
||||
EntityUid? storeEntity = null
|
||||
)
|
||||
{
|
||||
listings ??= GetAllListings();
|
||||
|
||||
@@ -131,4 +152,19 @@ public sealed partial class StoreSystem
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetListing(IReadOnlyCollection<ListingDataWithCostModifiers> collection, string listingId, [MaybeNullWhen(false)] out ListingDataWithCostModifiers found)
|
||||
{
|
||||
foreach(var current in collection)
|
||||
{
|
||||
if (current.ID == listingId)
|
||||
{
|
||||
found = current;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
found = null!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user