From 1a42ac7758cc290bbcca5a466ef3c84c511f9280 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 6 Oct 2026 22:56:05 +0200 Subject: [PATCH] StationServices.BuyPrice: the one number the station charges, which the buy path shows, checks and charges Co-Authored-By: Claude Opus 5.5 --- Assets/Scripts/ServerShared/StationServices.cs | 15 +++++++++++++++ .../Aetheria.Shared.Tests/StationServicesTests.cs | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Assets/Scripts/ServerShared/StationServices.cs b/Assets/Scripts/ServerShared/StationServices.cs index b6b363dde..6250c8f74 100644 --- a/Assets/Scripts/ServerShared/StationServices.cs +++ b/Assets/Scripts/ServerShared/StationServices.cs @@ -8,6 +8,21 @@ using System.Linq; // durabilities exactly as they were. public static class StationServices { + // What the station charges for the item, or for `quantity` units of a commodity (a crafted item is one unit). The + // number TradeMenu shows, checks against the run's credits and charges. + public static int BuyPrice(ItemManager items, ItemInstance item, int quantity = 1) + { + switch (item) + { + case CraftedItemInstance crafted: + return items.GetPrice(crafted); + case SimpleCommodity commodity: + return (int) Math.Min((long) items.GetData(commodity).Price * quantity, int.MaxValue); + default: + throw new ArgumentException($"{item?.GetType().Name ?? "null"} has no buy price.", nameof(item)); + } + } + // What the station pays for the item: its price, scaled by SellFraction and by its condition. A commodity has no // wear, so it sells at the fraction alone; a simple commodity's price is per unit. public static int SellPrice(ItemManager items, ItemInstance item) diff --git a/tests/Aetheria.Shared.Tests/StationServicesTests.cs b/tests/Aetheria.Shared.Tests/StationServicesTests.cs index b91e10018..84d1b154a 100644 --- a/tests/Aetheria.Shared.Tests/StationServicesTests.cs +++ b/tests/Aetheria.Shared.Tests/StationServicesTests.cs @@ -83,6 +83,20 @@ public sealed class StationServicesTests : IDisposable Assert.Equal(15000000, _items.GameplaySettings.StartingCredits); } + [Fact] + public void BuyPrice_is_the_price_and_the_sale_never_beats_it() + { + Assert.Equal(_items.GetPrice(Mint("Gun")), StationServices.BuyPrice(_items, Mint("Gun"))); + // A worn gun costs what a new one does to buy, and pays less to sell. + Assert.Equal(StationServices.BuyPrice(_items, Mint("Gun")), StationServices.BuyPrice(_items, Mint("Gun", 4))); + // A commodity is priced per unit, times the units asked for. + Assert.Equal(7, StationServices.BuyPrice(_items, Ore(10))); + Assert.Equal(70, StationServices.BuyPrice(_items, Ore(1), 10)); + Assert.Equal(int.MaxValue, StationServices.BuyPrice(_items, Ore(1), int.MaxValue)); + Assert.True(StationServices.SellPrice(_items, Mint("Gun")) < StationServices.BuyPrice(_items, Mint("Gun"))); + Assert.Throws(() => StationServices.BuyPrice(_items, null)); + } + [Fact] public void SellPrice_scales_with_condition() {