Tagging Entities

Introduction

In Alacrity, entity tags play a crucial role in identifying and categorizing entities within a simulation or game. Tags are used to label entities based on specific characteristics, properties, or roles they possess. They provide a flexible and efficient way to filter, group, and apply actions or effects to specific subsets of entities.

Understanding Entity Tags

Entity tags are lightweight metadata attached to entities. They consist of a name-value pair that describes a certain aspect of an entity. The name represents the category or type of tag, while the value provides further details or specific identification within that category.

Tags serve as a powerful mechanism to query and manipulate entities based on common traits, relationships, or conditions. They can be utilized in various scenarios, such as filtering entities for specific behaviors, targeting entities for buffs or debuffs, applying game rules based on entity aspects, and much more.

Tags are immutable, once a tag is attached to an entity it can not be modified in any way. If one desires to "update" a tag value, the tag must be re-attached to the entity passing the boolean argument replace as true in both rust and lua APIs to the method add_tags.

🚨 Warning

modifying tags in a live entity could trigger buffs activations or deactivations, initiate complex and expensive buff propagation maps or trigger other behaviors that might have been setup in the game or simulation, be wary of the possible connotations of mutating tags data in live entities.

Simple Tags

Tags that doesn't contain a value are known as "simple", they are regularly used to identify the entities for some kind of filtering or grouping. This is the most common case of tagging, and it is widely used by the buff's propagation system to known to which entities a buff must be propagated or not.

Complex Tags

Tags that contains a value are known as "complex", they can be used for the same purposes as their simple counterpart but they can carry additional metadata in their value. They are also used by the buff's propagation system to apply extra conditional behavior to buffs propagations. For example a buff propagation can contain a rule that allow the buff to propagate to tags of an specific tag key but that also have an specific value like:

{
    name = "humanoid", value = "centaur"
}

In the example above, the buff would only propagate to entities that contain an humanoid tag with a value of centaur.

Different ways of tagging entities

Entities can be tagged both using the Rust or Lua APIs or tags can be included in the entity's blueprint or template definitions. The tags field in a blueprint or template contains an array of tag objects, where each object represents a specific tag associated with the entity. Each tag object consist of a name-value pair that defines the category and value of the tag.

Example using Lua declarative syntax

Here is an example of tagging entities on their definition using the blueprint's Lua declarative syntax:

local entities = {
    -- Entity Dark Paladin PC
    {
        blueprint_id = "PC_DARK_PALADIN",
        name = "pc_dark_paladin",
        description = "A playable Dark Paladin Entity",
        tags = {
            { name = "entity_type", value = "playable_character" },
            { name = "archetype", value = "paladin" },
            { name = "alignment", value = "evil" },
        },
        attributes = {
            { name = "str", value = 10 },
            { name = "cha", value = 16 },
            { name = "dex", value = 2 },
            { name = "con", vale = 18 },
            { name = "int", value = 2 },
            { name = "wis", value = 1 },
        },
        properties = {
            { name = "level", value = 1 },
            { name = "race", value = "human" },
        }
        buffs = {},
        version = "0.1.0"
    },
    -- More entities --
}

return entities

In this example, an entity is tagged using the "entity_type" category that defines the kind of entity this entity is, a tag for the "archetype" category that defines the character's archetype or class, and a final tag for the "alignment" category that identifies the character as "evil".

The tag category can be customized based on specific context and requirements of your game or simulation.

ℹ️ Info

note that currently, tags are not accessible from buffs and/or buff's modifiers conditional so if you are planning to use them in your conditional operations you will also need to add a property that contains the data that you want to check. This might be changed in the future to allow condition scopes to have access to tag data to run in their expressions.

Example using Rust programmatic syntax

We can add tags to live entities programmatically using the Rust API. Here's an example:

use alacrity_lib::prelude::*;

static BLUEPRINT_ID: &str = "ENTITY_EXAMPLE_BLUEPRINT";

fn main() {
    // create a new Entity instance from a blueprint ID 
    let mut e = Entity::new(BLUEPRINT_ID, None).unwrap();
    
    // add new tags to the entity using its rust API
    let tags = vec![
        Tag::new("humanoid", Value::from("centaur".to_string())),
    ];
    
    e.add_tags(&tags, false).unwrap();
}

If we want to replace tags that already exists in the entity and are contained in the tags vector, we can pass true as the second argument to the add_tags method.

Example using Lua programmatic syntax

We can also add tags from Lua using the entity's Lua API:

-- create a new entity instance from a blueprint ID
local e = alacrity.Entity.instance("ENTITY_EXAMPLE_BLUEPRINT")

-- add new tags to the entity using its lua API
local tags = {
    { name = "humanoid", value = "centaur" }
}

e:add_tags(tags, false)

As in the Rust API, if we want to replace tags that already exists in the entity, we can pass true as the second argument to the add_tags method.

Value auto conversion

When creating a Tag with a Value of a different Kind than String or Int, Alacrity will automatically convert the value to Kind::Int or Kind::String based on the following rules:

Value KindConverted To
Bool(true)Int(1)
Bool(false)Int(0)
Float(x.y)Int(x) (truncated)
NilString("")

💡 Tip

Even though the value is auto-converted to a safe value, it is recommended to avoid creating tags with values other than string or int to prevent potential issues and unexpected complications.