using AcDream.Content; using AcDream.Core.Items; using DatReaderWriter; using DatReaderWriter.DBObjs; using DatReaderWriter.Types; namespace AcDream.App.UI.Layout; /// /// Resolves the authored enum display names consumed by retail's appraisal /// helpers. Material names follow /// MaterialTypeEnumMapper::MaterialTypeToString @ 0x005CD500; /// creature and heritage names follow /// AppraisalSystem::InqCreatureDisplayName @ 0x005B59E0 and /// InqHeritageGroupDisplayName @ 0x005B4710. /// public sealed class RetailAppraisalNameResolver { private const uint MaterialClientEnum = 0x10000001u; private const uint MaterialSubEnum = 1u; public static RetailAppraisalNameResolver Empty { get; } = new( new Dictionary(), new CreatureDisplayNameResolver(new Dictionary())); private readonly IReadOnlyDictionary _materials; private readonly CreatureDisplayNameResolver _creatures; public RetailAppraisalNameResolver( IReadOnlyDictionary materials, CreatureDisplayNameResolver creatures) { _materials = materials ?? throw new ArgumentNullException(nameof(materials)); _creatures = creatures ?? throw new ArgumentNullException(nameof(creatures)); } public static RetailAppraisalNameResolver Load( IDatReaderWriter dats, CreatureDisplayNameResolver creatures) { ArgumentNullException.ThrowIfNull(dats); ArgumentNullException.ThrowIfNull(creatures); var materials = new Dictionary(); uint masterDid = (uint)dats.Portal.Db.Header.MasterMapId; EnumIDMap? master = masterDid == 0u ? null : dats.Get(masterDid); if (master is not null && master.ClientEnumToID.TryGetValue( MaterialClientEnum, out uint materialRootMapDid) && dats.Get(materialRootMapDid) is { } materialRootMap && materialRootMap.ClientEnumToID.TryGetValue( MaterialSubEnum, out uint materialMapDid) && dats.Get(materialMapDid) is { } materialMap) { foreach ((uint id, PStringBase text) in materialMap.ClientEnumToName) { materials.TryAdd(id, Normalize(text.Value)); } } return new RetailAppraisalNameResolver(materials, creatures); } public string ResolveCreature(int creatureType) => _creatures.Resolve(creatureType); public string ResolveHeritage(int heritageGroup) => heritageGroup switch { 2 => "Gharu'ndim", 5 => "Umbraen", 13 => "Olthoi", _ => CharacterIdentityText.HeritageGroupDisplayName(heritageGroup) ?? string.Empty, }; public string ResolveMaterial(int materialType) => materialType > 0 && _materials.TryGetValue((uint)materialType, out string? name) ? name : string.Empty; /// /// Port of the material-decoration tail in /// ACCWeenieObject::GetObjectName @ 0x0058E6E0. Retail first /// chooses the singular/plural base name, removes an already-authored /// occurrence of the resolved material, trims it, then prefixes the /// material exactly once. /// public string ResolveAppropriateName(ClientObject obj) { ArgumentNullException.ThrowIfNull(obj); string baseName = obj.GetAppropriateName(); if (obj.MaterialType is not { } materialType) return baseName; string material = ResolveMaterial(unchecked((int)materialType)); if (string.IsNullOrEmpty(material)) return baseName; string remainder = baseName .Replace(material, string.Empty, StringComparison.Ordinal) .Trim(); return string.IsNullOrEmpty(remainder) ? material : $"{material} {remainder}"; } private static string Normalize(string value) => value.Replace('_', ' '); }