diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index 822277a84..f920522ae 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -1423,7 +1423,7 @@ public class ActionGameManager : MonoBehaviour : $"base {d.PBase:P1}"; DebugInfoText.text = - $"FIRE CONTROL - {selectedItem.Data.Name}\n" + + $"FIRE CONTROL - {ItemManager.Title(selectedItem.EquippableItem)}\n" + $"{gates}\n" + $"range {d.Range:F0} [{d.MinRange:F0}..{d.MaxRange:F0}]\n" + $"info {d.Info:F3}/{d.InfoDemandCeiling:F3} sensor {d.PSensor:F3}\n" + diff --git a/Assets/Scripts/ServerShared/ItemManager.cs b/Assets/Scripts/ServerShared/ItemManager.cs index 281228165..bebfb5431 100644 --- a/Assets/Scripts/ServerShared/ItemManager.cs +++ b/Assets/Scripts/ServerShared/ItemManager.cs @@ -221,6 +221,11 @@ public class ItemManager return (ItemData.Get(maker), product); } + // What the player reads an item as: its product's name when its lot's maker has a product of this design, + // otherwise the design's own name (unbranded, console-given and extracted lots, and commodities). + public string Title(ItemInstance item) => + (item is CraftedItemInstance crafted ? Brand(crafted).Product?.Name : null) ?? GetData(item).Name; + public (RarityTier tier, int upgrades) GetTier(CraftedItemInstance item) { var quality = GetLot(item).Quality; diff --git a/Assets/Scripts/UI/Menu/TradeMenu.cs b/Assets/Scripts/UI/Menu/TradeMenu.cs index 5c3245907..1adadcf15 100644 --- a/Assets/Scripts/UI/Menu/TradeMenu.cs +++ b/Assets/Scripts/UI/Menu/TradeMenu.cs @@ -192,9 +192,9 @@ public class TradeMenu : MonoBehaviour columns.Add(("Name", 3, x => () => x.item is CraftedItemInstance craftedItemInstance ? - $"{x.data.Name}" : - x.data.Name, - x => x.data.Name)); + $"{GameManager.ItemManager.Title(x.item)}" : + GameManager.ItemManager.Title(x.item), + x => GameManager.ItemManager.Title(x.item))); if(_hardpointFilter.filter==null) columns.Add(("Type", 2, x => () => @@ -352,7 +352,7 @@ public class TradeMenu : MonoBehaviour { int quantity = 1; Dialog.Clear(); - Dialog.Title.text = $"Buying {i.data.Name}"; + Dialog.Title.text = $"Buying {GameManager.ItemManager.Title(i.item)}"; Dialog.AddField("Quantity", () => quantity, q => quantity = min(min(q, GameManager.Credits / StationServices.BuyPrice(GameManager.ItemManager, s)), s.Quantity)); diff --git a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs index 3e8a3c5ae..a39226ccc 100644 --- a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs +++ b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs @@ -376,7 +376,6 @@ public class PropertiesPanel : MonoBehaviour sheet.AddStat("Manufacturer", () => maker.Name); if (product != null) { - AddProperty(product.Name); AddProperty(product.Description); } } @@ -430,10 +429,9 @@ public class PropertiesPanel : MonoBehaviour private string GetTitle(EquippableItem item) { - var data = GameManager.ItemManager.GetData(item); var (tier, upgrades) = GameManager.ItemManager.GetTier(item); return - $"{data.Name} ({tier.Name}{new string('+', upgrades)})"; + $"{GameManager.ItemManager.Title(item)} ({tier.Name}{new string('+', upgrades)})"; } public void Inspect(EquippedItem item) diff --git a/Assets/Scripts/Zone Display/ZoneRenderer.cs b/Assets/Scripts/Zone Display/ZoneRenderer.cs index adff35396..e969670db 100644 --- a/Assets/Scripts/Zone Display/ZoneRenderer.cs +++ b/Assets/Scripts/Zone Display/ZoneRenderer.cs @@ -605,7 +605,7 @@ public class ZoneRenderer : MonoBehaviour var itemPickup = gridObject.gameObject.GetComponent(); itemPickup.Item = item; itemPickup.ZoneRenderer = this; - itemPickup.ScanLabel.text = ItemManager.GetData(item).Name; + itemPickup.ScanLabel.text = ItemManager.Title(item); if (item is CraftedItemInstance craftedItemInstance) { var c = ItemManager.GetTier(craftedItemInstance).tier.Color.ToColor(); diff --git a/tests/Aetheria.Shared.Tests/ItemTitleTests.cs b/tests/Aetheria.Shared.Tests/ItemTitleTests.cs new file mode 100644 index 000000000..3df7484cc --- /dev/null +++ b/tests/Aetheria.Shared.Tests/ItemTitleTests.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.IO; +using CultMath; +using GameCult.Caching; +using Xunit; + +// Items are titled by their product (ruling catalog-grows-generic-designs-branded-products): ItemManager.Title reads +// Brand, so the lot's maker picks which of a design's products names the unit, and nothing else carries a name. +public sealed class ItemTitleTests : IDisposable +{ + private readonly string _root = Path.Combine(Path.GetTempPath(), "aetheria-itemtitle-" + Guid.NewGuid().ToString("N")); + private readonly CultCache _cache; + private readonly ItemManager _items; + private readonly FactionProductData _panopticon, _clapBack, _spiceBlend; + private readonly CultRecordRef _stranger; + private readonly CompoundCommodityData _spice; + private readonly GearData _array; + + public ItemTitleTests() + { + Directory.CreateDirectory(_root); + _cache = AetheriaStores.Open(Path.Combine(_root, "Aetheria.cc"), catalogWritable: true); + _cache.Upsert(new TestCatalogGlobal { Name = "Temperament" }); + _array = new GearData { Name = "Array", Hardpoint = HardpointType.Sensors, Shape = new Shape(), Price = 10, Durability = 5 }; + _cache.Upsert(_array); + _cache.Upsert(new SimpleCommodityData { Name = "Ore", Shape = new Shape(), Price = 7, MaxStack = 100 }); + var finch = _cache.Upsert(new Faction { Name = "Finch", ShortName = "FIN" }); + var lucent = _cache.Upsert(new Faction { Name = "Lucent", ShortName = "LUC" }); + _stranger = _cache.Upsert(new Faction { Name = "Stranger", ShortName = "STR" }); + _spice = new CompoundCommodityData { Name = "Spice", Shape = new Shape(), Price = 3 }; + _cache.Upsert(_spice); + var design = _cache.RefOf(_cache.GetByName("Array")); + _panopticon = new FactionProductData { Name = "Panopticon Prime", Design = design, Manufacturer = finch }; + _clapBack = new FactionProductData { Name = "ClapBack Ultra", Design = design, Manufacturer = lucent }; + _cache.Commit(batch => batch.Upsert(typeof(FactionProductData), _panopticon, new CultRecordKey("array-finch"))); + _cache.Commit(batch => batch.Upsert(typeof(FactionProductData), _clapBack, new CultRecordKey("array-lucent"))); + _spiceBlend = new FactionProductData { Name = "Finch Reserve", Design = _cache.RefOf(_spice), Manufacturer = finch }; + _cache.Commit(batch => batch.Upsert(typeof(FactionProductData), _spiceBlend, new CultRecordKey("spice-finch"))); + _items = new ItemManager(_cache, new ProvenanceLedger(), RunSaveTests.TestSettings(), _ => { }); + } + + public void Dispose() + { + _cache.Dispose(); + Directory.Delete(_root, true); + } + + [Fact] + public void A_product_unit_is_titled_by_its_product() + { + var unit = _items.CreateInstance(_items.CreateLot(_panopticon)); + Assert.Equal("Panopticon Prime", _items.Title(unit)); + Assert.NotEqual("Panopticon Prime", _items.GetData(unit).Name); + } + + [Fact] + public void Two_makers_title_their_own_units() + { + var finch = _items.CreateInstance(_items.CreateLot(_panopticon)); + var lucent = _items.CreateInstance(_items.CreateLot(_clapBack)); + Assert.Equal(_items.GetData(finch).Name, _items.GetData(lucent).Name); + Assert.Equal("Panopticon Prime", _items.Title(finch)); + Assert.Equal("ClapBack Ultra", _items.Title(lucent)); + } + + [Fact] + public void Unbranded_units_are_titled_by_design() + { + var given = _items.CreateInstance(_items.CreateLot(_array, default, .5f)); + Assert.Equal("Array", _items.Title(given)); + + var extractedLot = _items.Lots.Add(new Lot + { + Design = _cache.RefOf(_array), Origin = new Extracted(), Quality = .5f, Roles = new List() + }); + Assert.Equal("Array", _items.Title(_items.CreateInstance(extractedLot))); + + var ore = new SimpleCommodity { Data = _cache.RefOf(_cache.GetByName("Ore")), Quantity = 3 }; + Assert.Equal("Ore", _items.Title(ore)); + } + + [Fact] + public void A_maker_without_a_product_of_the_design_is_titled_by_design() + { + var unit = _items.CreateInstance(_items.CreateLot(_array, _stranger, .5f)); + Assert.Equal("Stranger", _items.Brand(unit).Maker.Name); + Assert.Equal("Array", _items.Title(unit)); + } + + [Fact] + public void A_crafted_commodity_with_a_product_is_titled_by_its_product() + { + var unit = _items.CreateInstance(_items.CreateLot(_spiceBlend)); + Assert.IsType(unit); + Assert.Equal("Finch Reserve", _items.Title(unit)); + } +}