Files
mod_items_base/src/ui/InventoryItemUi.cs
T
2026-10-18 12:41:40 +03:00

142 lines
5.6 KiB
C#

using System.Collections.Generic;
using Cthangover.Core.Items;
using Cthangover.Core.UI.Theming;
using Godot;
namespace Cthangover.Core.UI.Inventory
{
/// <summary>
/// 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. <see cref="ItemType"/> 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
/// <see cref="BadgeOrder"/> defines that priority consistently.
/// A custom verb can be supplied by mods through the item's
/// <c>Properties</c> bag under the <c>verb</c> key; it is treated as a
/// locale key when it contains a slash and as a literal otherwise.
/// </summary>
public static class InventoryItemUi
{
/// <summary>Badge order from most narrative to most technical flag.</summary>
public static readonly IReadOnlyList<ItemType> BadgeOrder = new[]
{
ItemType.Quest,
ItemType.Used,
ItemType.TargetUsed,
ItemType.Food,
ItemType.Resource,
ItemType.Recipe,
ItemType.CantDrop,
};
/// <summary>
/// Mirrors <c>InventoryPanelBehaviour</c> use-button rule: an item is
/// usable only when it carries an action and one of the "used" flags.
/// Food or resources without an <see cref="IItemAction"/> are inert.
/// </summary>
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);
}
/// <summary>False only for <see cref="ItemType.CantDrop"/> items (quest objectives, key items).</summary>
public static bool CanDrop(IItem item)
{
return item != null && !item.ItemType.HasFlag(ItemType.CantDrop);
}
/// <summary>
/// Locale key (or literal) of the verb shown on the action button.
/// Resolution order: mod-provided <c>verb</c> property, recipe,
/// targeted, food, generic use.
/// </summary>
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";
}
/// <summary>
/// Short corner tag for the grid cell. Only actionable items get a
/// tag — an inert resource must not advertise a verb it cannot run.
/// </summary>
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";
}
/// <summary>
/// Accent colour of an item: quest gold dominates, then recipe,
/// food, targeted, used and finally plain resources.
/// </summary>
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;
}
/// <summary>Locale key of the badge caption for a single type flag.</summary>
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;
}
/// <summary>Translates a locale key, falling back to the key itself for unknown keys and literals.</summary>
public static string Translate(string keyOrLiteral)
{
if (string.IsNullOrEmpty(keyOrLiteral))
return string.Empty;
return TranslationServer.Translate(keyOrLiteral).ToString();
}
}
}