Tag System
Stack Inventory includes a powerful hierarchical tag system for categorizing and filtering items.
What are Tags?
Section titled “What are Tags?”Tags are labels you attach to items to group them by category, type, or behavior. They enable:
- Categorization - Group items (Weapon, Consumable, Quest Item)
- Filtering - Find items by tag (all weapons, all consumables)
- Behavior - Apply logic based on tags (equippable items, stackable items)
- Hierarchy - Organize tags in parent/child relationships
Creating Tags
Section titled “Creating Tags”Basic Tags
Section titled “Basic Tags”using StackInventory.Core.Items;
// Simple tagvar weaponTag = new ItemTag("Weapon");var consumableTag = new ItemTag("Consumable");var questTag = new ItemTag("Quest");Hierarchical Tags
Section titled “Hierarchical Tags”Tags support hierarchy using dot notation:
// Weapon hierarchyvar meleeTag = new ItemTag("Weapon.Melee");var rangedTag = new ItemTag("Weapon.Ranged");
// Weapon.Melee hierarchyvar swordTag = new ItemTag("Weapon.Melee.Sword");var axeTag = new ItemTag("Weapon.Melee.Axe");
// Weapon.Ranged hierarchyvar bowTag = new ItemTag("Weapon.Ranged.Bow");var gunTag = new ItemTag("Weapon.Ranged.Gun");Hierarchy structure:
Weapon├── Melee│ ├── Sword│ ├── Axe│ └── Hammer└── Ranged ├── Bow ├── Gun └── CrossbowAdding Tags to Items
Section titled “Adding Tags to Items”In the Godot Inspector:
- Create/open an
ItemDefinitionresource - Find the Tags array property
- Click Add Element
- Set the Id field (e.g., “Weapon.Melee.Sword”)
Item (POCS Class)
Section titled “Item (POCS Class)”using StackInventory.Core.Items;
// Create tagsvar tags = new List<ItemTag>{ new ItemTag("Weapon"), new ItemTag("Weapon.Melee"), new ItemTag("Weapon.Melee.Sword"), new ItemTag("Equippable"), new ItemTag("Rare")};
// Create item with tagsvar item = new Item( id: Guid.NewGuid(), name: "Iron Sword", value: 100f, tags: tags, stackMaximum: 1);Checking for Tags
Section titled “Checking for Tags”HasTag Method
Section titled “HasTag Method”// Check exact tagif (item.HasTag("Weapon")){ GD.Print("This is a weapon!");}
// Check hierarchical tagif (item.HasTag("Weapon.Melee")){ GD.Print("This is a melee weapon!");}
// Check specific tagif (item.HasTag("Weapon.Melee.Sword")){ GD.Print("This is specifically a sword!");}Using ItemTag Objects
Section titled “Using ItemTag Objects”var weaponTag = new ItemTag("Weapon");
if (item.HasTag(weaponTag)){ GD.Print("Item has weapon tag");}Tag Hierarchy Matching
Section titled “Tag Hierarchy Matching”The tag system supports hierarchical matching:
var sword = new Item( Guid.NewGuid(), "Iron Sword", 100f, tags: new List<ItemTag> { new("Weapon.Melee.Sword") }, stackMaximum: 1);
// All of these return TRUE:sword.HasTag("Weapon"); // ✓ Parent tagsword.HasTag("Weapon.Melee"); // ✓ Parent tagsword.HasTag("Weapon.Melee.Sword"); // ✓ Exact tag
// This returns FALSE:sword.HasTag("Weapon.Ranged"); // ✗ Different branchRule: An item with tag A.B.C automatically matches A and A.B.
Common Tag Patterns
Section titled “Common Tag Patterns”Equipment Categories
Section titled “Equipment Categories”// Armor"Armor""Armor.Head" // Helmet"Armor.Chest" // Chestplate"Armor.Legs" // Leggings"Armor.Feet" // Boots
// Weapons"Weapon""Weapon.Melee""Weapon.Ranged""Weapon.Magic"
// Accessories"Accessory""Accessory.Ring""Accessory.Amulet"Item Types
Section titled “Item Types”// Consumables"Consumable""Consumable.Potion""Consumable.Food""Consumable.Scroll"
// Resources"Resource""Resource.Ore""Resource.Wood""Resource.Herb"
// Quest"Quest""Quest.Key""Quest.Document"Behavior Tags
Section titled “Behavior Tags”// Functionality"Equippable" // Can be equipped"Consumable" // Can be consumed/used"Stackable" // Can stack in inventory"Tradeable" // Can be sold/traded"Droppable" // Can be dropped in world
// Rarity"Rarity.Common""Rarity.Uncommon""Rarity.Rare""Rarity.Epic""Rarity.Legendary"
// Binding"BindOnPickup" // Cannot trade once picked up"BindOnEquip" // Cannot trade once equipped"Soulbound" // Cannot trade at allFiltering Items by Tag
Section titled “Filtering Items by Tag”Filter Inventory
Section titled “Filter Inventory”public partial class Inventory : Node{ private List<(IItem item, int amount)> _items = new();
public List<IItem> GetItemsWithTag(string tagId) { return _items .Where(i => i.item.HasTag(tagId)) .Select(i => i.item) .ToList(); }
public List<IItem> GetWeapons() { return GetItemsWithTag("Weapon"); }
public List<IItem> GetConsumables() { return GetItemsWithTag("Consumable"); }}Filter UI
Section titled “Filter UI”public partial class InventoryUI : Control{ private string _currentFilter = "";
public void ShowWeapons() { _currentFilter = "Weapon"; RefreshDisplay(); }
public void ShowArmor() { _currentFilter = "Armor"; RefreshDisplay(); }
public void ShowAll() { _currentFilter = ""; RefreshDisplay(); }
private void RefreshDisplay() { var items = string.IsNullOrEmpty(_currentFilter) ? _inventory.GetAllItems() : _inventory.GetItemsWithTag(_currentFilter);
// Update UI to show filtered items }}Advanced Tag Usage
Section titled “Advanced Tag Usage”Multiple Tag Matching
Section titled “Multiple Tag Matching”// Item must have ALL tagspublic bool HasAllTags(IItem item, params string[] tagIds){ return tagIds.All(tagId => item.HasTag(tagId));}
// Example: Find equippable weaponsif (HasAllTags(item, "Weapon", "Equippable")){ GD.Print("Can equip this weapon");}Tag Exclusion
Section titled “Tag Exclusion”// Has one tag but not anotherpublic bool HasTagButNotTag(IItem item, string hasTag, string notTag){ return item.HasTag(hasTag) && !item.HasTag(notTag);}
// Example: Tradeable quest items (not soulbound)if (HasTagButNotTag(item, "Quest", "Soulbound")){ GD.Print("Can trade this quest item");}Dynamic Tag Application
Section titled “Dynamic Tag Application”// Add tag at runtime (if using Item POCS)var item = new Item(...);item.Tags.Add(new ItemTag("Enchanted"));
// Check for enchantmentsif (item.HasTag("Enchanted")){ ApplyEnchantmentEffects(item);}Tag Best Practices
Section titled “Tag Best Practices”- Use hierarchy -
Weapon.Melee.Swordinstead ofSword - Be consistent - Decide on naming convention early
- Use PascalCase -
Weapon.Meleenotweapon.melee - Group logically - Related items under same parent
- Document tags - Keep a list of all tag patterns
DON’T ❌
Section titled “DON’T ❌”- Mix conventions - Don’t use both
Weapon.MeleeandMeleeWeapon - Over-tag - Don’t add every possible tag, be selective
- Use too many levels - More than 3-4 levels gets confusing
- Include spaces - Use
Weapon.MeleenotWeapon.Melee Sword - Hard-code - Store tag constants for reuse
Tag Constants Pattern
Section titled “Tag Constants Pattern”Create a static class for tag constants:
public static class ItemTags{ // Weapons public const string Weapon = "Weapon"; public const string WeaponMelee = "Weapon.Melee"; public const string WeaponMeleeSword = "Weapon.Melee.Sword"; public const string WeaponMeleeAxe = "Weapon.Melee.Axe"; public const string WeaponRanged = "Weapon.Ranged"; public const string WeaponRangedBow = "Weapon.Ranged.Bow";
// Armor public const string Armor = "Armor"; public const string ArmorHead = "Armor.Head"; public const string ArmorChest = "Armor.Chest";
// Consumables public const string Consumable = "Consumable"; public const string ConsumablePotion = "Consumable.Potion"; public const string ConsumableFood = "Consumable.Food";
// Behavior public const string Equippable = "Equippable"; public const string Stackable = "Stackable"; public const string Tradeable = "Tradeable";}
// Usageif (item.HasTag(ItemTags.WeaponMelee)){ // Handle melee weapon}Example: Complete Item with Tags
Section titled “Example: Complete Item with Tags”using StackInventory.Core.Items;
public class ItemFactory{ public static Item CreateIronSword() { return new Item( id: Guid.NewGuid(), name: "Iron Sword", value: 100f, tags: new List<ItemTag> { new(ItemTags.Weapon), new(ItemTags.WeaponMelee), new(ItemTags.WeaponMeleeSword), new(ItemTags.Equippable), new("Rarity.Common") }, stackMaximum: 1, iconPath: "res://icons/weapons/iron_sword.png", tooltip: "A sturdy iron sword. Reliable in combat." ); }
public static Item CreateHealthPotion() { return new Item( id: Guid.NewGuid(), name: "Health Potion", value: 50f, tags: new List<ItemTag> { new(ItemTags.Consumable), new(ItemTags.ConsumablePotion), new(ItemTags.Stackable), new("Rarity.Common") }, stackMaximum: 99, iconPath: "res://icons/consumables/health_potion.png", tooltip: "Restores 50 HP when consumed." ); }}Next Steps
Section titled “Next Steps”- Containers Guide - Build inventory containers
- UI Guide - Create inventory interfaces
- Architecture - Understand the system design
- API Reference - Explore ItemTag class