using System.Collections.Generic; using Cthangover.Core.Items; using Cthangover.Core.UI.Theming; using Godot; namespace Cthangover.Core.UI.Inventory { /// /// Shared presentation rules for inventory items, used by both the grid /// cell and the item passport so the two can never disagree about an /// item's affordances. is a flags enum, so every /// question ("can this be used?", "what badge colour?") has to pick a /// priority among possibly overlapping flags — the order in /// defines that priority consistently. /// A custom verb can be supplied by mods through the item's /// Properties bag under the verb key; it is treated as a /// locale key when it contains a slash and as a literal otherwise. /// public static class InventoryItemUi { /// Badge order from most narrative to most technical flag. public static readonly IReadOnlyList BadgeOrder = new[] { ItemType.Quest, ItemType.Used, ItemType.TargetUsed, ItemType.Food, ItemType.Resource, ItemType.Recipe, ItemType.CantDrop, }; /// /// Mirrors InventoryPanelBehaviour use-button rule: an item is /// usable only when it carries an action and one of the "used" flags. /// Food or resources without an are inert. /// public static bool IsUsable(IItem item) { if (item == null || item.ItemAction == null) return false; return item.ItemType.HasFlag(ItemType.Used) || item.ItemType.HasFlag(ItemType.TargetUsed); } /// False only for items (quest objectives, key items). public static bool CanDrop(IItem item) { return item != null && !item.ItemType.HasFlag(ItemType.CantDrop); } /// /// Locale key (or literal) of the verb shown on the action button. /// Resolution order: mod-provided verb property, recipe, /// targeted, food, generic use. /// public static string VerbKey(IItem item) { if (item == null) return "ui/inventory/verb_use"; var custom = item.Properties?.GetStr("verb"); if (!string.IsNullOrWhiteSpace(custom)) return custom; if (item.ItemType.HasFlag(ItemType.Recipe)) return "ui/inventory/verb_recipe"; if (item.ItemType.HasFlag(ItemType.TargetUsed)) return "ui/inventory/verb_target"; if (item.ItemType.HasFlag(ItemType.Food)) return "ui/inventory/verb_eat"; return "ui/inventory/verb_use"; } /// /// Short corner tag for the grid cell. Only actionable items get a /// tag — an inert resource must not advertise a verb it cannot run. /// public static string TagKey(IItem item) { if (item?.ItemAction == null) return null; if (item.ItemType.HasFlag(ItemType.Recipe)) return "ui/inventory/tag_recipe"; if (item.ItemType.HasFlag(ItemType.TargetUsed)) return "ui/inventory/tag_target"; if (item.ItemType.HasFlag(ItemType.Food)) return "ui/inventory/tag_food"; return "ui/inventory/tag_use"; } /// /// Accent colour of an item: quest gold dominates, then recipe, /// food, targeted, used and finally plain resources. /// public static Color AccentColor(ItemType type) { if (type.HasFlag(ItemType.Quest)) return UiTokens.TypeQuest; if (type.HasFlag(ItemType.Recipe)) return UiTokens.TypeRecipe; if (type.HasFlag(ItemType.Food)) return UiTokens.TypeFood; if (type.HasFlag(ItemType.TargetUsed)) return UiTokens.TypeTarget; if (type.HasFlag(ItemType.Used)) return UiTokens.TypeUsed; if (type.HasFlag(ItemType.Resource)) return UiTokens.TypeResource; return UiTokens.Muted; } /// Locale key of the badge caption for a single type flag. public static string TypeBadgeKey(ItemType type) { if (type == ItemType.Quest) return "ui/inventory/type_quest"; if (type == ItemType.Used) return "ui/inventory/type_used"; if (type == ItemType.TargetUsed) return "ui/inventory/type_target"; if (type == ItemType.Food) return "ui/inventory/type_food"; if (type == ItemType.Resource) return "ui/inventory/type_resource"; if (type == ItemType.Recipe) return "ui/inventory/type_recipe"; if (type == ItemType.CantDrop) return "ui/inventory/type_cant_drop"; return null; } /// Translates a locale key, falling back to the key itself for unknown keys and literals. public static string Translate(string keyOrLiteral) { if (string.IsNullOrEmpty(keyOrLiteral)) return string.Empty; return TranslationServer.Translate(keyOrLiteral).ToString(); } } }