diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 1fe5d7288..5a38d5181 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Assets/Scripts/UI/Menu/TradeMenu.cs b/Assets/Scripts/UI/Menu/TradeMenu.cs index 5a642e07d..014525caf 100644 --- a/Assets/Scripts/UI/Menu/TradeMenu.cs +++ b/Assets/Scripts/UI/Menu/TradeMenu.cs @@ -435,7 +435,9 @@ public class TradeMenu : MonoBehaviour get { if (Item is CraftedItemInstance craftedItemInstance) - return _itemManager.GetPrice(craftedItemInstance); + return TypedItem != null + ? (int)(_itemManager.GameplaySettings.QualityPriceModifier.Evaluate(craftedItemInstance.Quality) * TypedItem.Price) + : 0; return TypedItem != null ? TypedItem.Price : 0; } @@ -479,18 +481,25 @@ public class TradeMenu : MonoBehaviour private void Buy(CraftedItemInstance item) { - var data = GameManager.ItemManager.GetData(item); - var price = GameManager.ItemManager.GetPrice(item); + var typedItem = FindTypedTradeItem(item); + if (typedItem == null) + { + ShowUnableToBuy("Missing typed trade row!"); + return; + } + + var price = GetTypedTradePrice(item, typedItem); if (price < GameManager.Credits) { - if (data is HullData hullData) + if (!string.IsNullOrWhiteSpace(typedItem?.HullType)) { - if (hullData.HullType != HullType.Ship) throw new ArgumentException("Attempted to buy non-ship hull from station, WTF are you doing?!"); + if (!string.Equals(typedItem.HullType, nameof(HullType.Ship), StringComparison.Ordinal)) + throw new ArgumentException("Attempted to buy non-ship hull from station, WTF are you doing?!"); var ship = new Ship(GameManager.ItemManager, GameManager.Zone, item as EquippableItem, GameManager.NewEntitySettings) { IsPlayerShip = true }; ship.SetParent(GameManager.DockedEntity); - GameManager.Credits -= data.Price; + GameManager.Credits -= price; UpdateCreditsLabel(); } else if (Inventory.TryTransferItem(_targetCargo, item)) @@ -519,18 +528,26 @@ public class TradeMenu : MonoBehaviour private void Buy(SimpleCommodity simpleCommodity, int quantity) { - var data = GameManager.ItemManager.GetData(simpleCommodity); + var typedItem = FindTypedTradeItem(simpleCommodity); + if (typedItem == null) + { + ShowUnableToBuy("Missing typed trade row!"); + return; + } + + var maxStack = typedItem.MaxStack > 0 ? typedItem.MaxStack : 1; + var price = typedItem.Price; // Up-rounded integer division from https://stackoverflow.com/a/503201 - int lots = (quantity - 1) / data.MaxStack + 1; + int lots = (quantity - 1) / maxStack + 1; int remaining = quantity; for (int i = 0; i < lots; i++) { - int q = min(remaining, data.MaxStack); - if (q * data.Price < GameManager.Credits) + int q = min(remaining, maxStack); + if (q * price < GameManager.Credits) { if (Inventory.TryTransferItem(_targetCargo, simpleCommodity, quantity)) { - GameManager.Credits -= q * data.Price; + GameManager.Credits -= q * price; UpdateCreditsLabel(); remaining -= q; } @@ -551,11 +568,22 @@ public class TradeMenu : MonoBehaviour Dialog.MoveToCursor(); return; } - - } } + private int GetTypedTradePrice(CraftedItemInstance item, AetheriaRuntimeCatalogItem typedItem) + { + return (int)(GameManager.ItemManager.GameplaySettings.QualityPriceModifier.Evaluate(item.Quality) * typedItem.Price); + } + + private void ShowUnableToBuy(string reason) + { + Dialog.Clear(); + Dialog.Title.text = $"Unable to buy: {reason}"; + Dialog.Show(); + Dialog.MoveToCursor(); + } + void Start() { FoldoutButton.onClick.AddListener(() => diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index e5464957a..4a3e5fc2f 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -156,7 +156,11 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. wraps rows in a typed `TradeRow`: name, mass, price, size, hardpoint type, commodity subtype, hull ownership, and behavior-kind filters read typed catalog rows before any legacy projection is hydrated. Legacy `ItemData` - hydration is lazy and bounded to behavior reflection columns and buy actions. + hydration is lazy and bounded to behavior reflection columns. Trade buy + decisions for crafted price, ship-hull classification, simple commodity base + price, and simple commodity stack size now read typed catalog rows; the + existing inventory transfer and ship-construction paths still own the actual + runtime mutation. The sector properties UI also resolves station/turret/ship counts only through typed hull classifications from the runtime catalog; missing typed hull rows no longer fall back to legacy `HullData`. Loot pickup @@ -640,7 +644,10 @@ First Aetheria surfaces to publish: - Done: move trade menu row presentation for name, mass, price, size, hardpoint type, commodity subtype, hull-owned counts, and behavior-kind filtering onto typed `TradeRow` fields; legacy `ItemData` hydration is - lazy and bounded to behavior reflection columns and buy mechanics. + lazy and bounded to behavior reflection columns. + - Done: move trade menu buy price, ship-hull classification, and simple + commodity stack-size decisions onto typed catalog rows; inventory transfer + and ship construction remain the runtime mutation owners. - Done: move action-bar consumable drop binding onto typed catalog rows; legacy `ConsumableItemData` resolution is lazy and bounded to activation and active-duration fill until typed consumable effect execution exists.