Entity's Attributes
Introduction
Attributes allow you to define and manage entities characteristics that can be queried and modified during the entities life time. This section will guide you though using the attributes system in both declarative and programmatic way providing examples in both Rust and Lua along the way.
Anatomy of an Attribute
Attributes are composed of a few fields that define them.
| Field | Type | Description |
|---|---|---|
| id | UUID | The attribute unique identifier |
| name | String | The attribute name (e.g 'dex', 'str', 'level', 'class'...) |
| description | String | An human friendly attribute description |
| base_value | Alacrity::Value | The attribute base value (defined in its blueprint or while creating a new one programmatically) |
| value | Alacrity::Value | The current attribute calculated value (after applying buffs) |
| modifiers | Vec<Modifier> | A vector of active modifiers that affect the attribute |
Continue reading to find a detailed description about each of the fields in the sections below
ID
Each attribute has an unique ID, this is generated automatically by Alacrity when an Attribute is created. The ID is basically used internally by Alacrity, users normally doesn't need to worry about it. The ID is always a valid UUID.
Name
The attribute's name is a pretty important piece of information, it is used both to provide of an human-friendly short reference to the attribute and to target the attribute in Modifiers definitions. Attribute's names must always be strings.
⚠️ Alert
Alacrity will not prevent you from creating entities with repeated attribute names in their definitions but be wary that only the last one in the definition will be added to the entity and taken into account.
Also, attribute names can clash with property names, this would probably cause issues when evaluating modifiers and buffs conditions as the condition evaluation Scope is not able to differentiate from attribute or property values while evaluating their [expressions].
Description
Human friendly description of what the attribute represents for the entity.
Base Value
When an attribute is firstly instantiated by a blueprint or programmatically using
the Rust or Lua APIs, it can be assigned a base value. This value will be used in
any [Buff] calculations that modifies or uses the attribute in any avail, if no
buff's modifiers are affecting the attribute, it will return always its base_value
when we request its calculated value or it is check by conditional expressions.
The base value is an Alacrity::Value of kind Int or Float, try to use any other value
kind as an attribute value will result in an error at compilation or run time.
Value
The attribute's value is dynamically calculated by the attribute taking into account the buff's modifiers that are currently affecting the attribute. They are immutable and can be updated only by alacrity's internal routines. The attribute's value will always contain the most up to date calculated value for the attribute at any given moment in time.
Modifiers
A vector of buff's modifiers that are currently affecting the attribute.
Defining Attributes
To define attributes for an entity, you need to specify them within the entity's definition. Attributes are typically declared as key-value pairs, where the key represents the attribute name and the value represents the initial or base value of the attribute. Additionally, the attribute description can also be defined.
Here's an example of defining attributes in Lua:
local attributes = {
{ name = "max_health", value = 100, description = "Max Health parameter" },
{ name = "strength", value = 10, description = "Current strength" },
-- Additional attributes...
}
local e = alacrity.Entity.new({
name = "Entity",
description = "Some Entity",
attributes = attributes,
...
})
And here's the equivalent example in Rust:
#![allow(unused)] fn main() { use alacrity_lib::prelude::*; let attributes = vec![ Attribute::new("max_health", Value::from(100)).unwrap().with_description("Max health parameter"), Attribute::new("strength", Value::from(10)).unwrap().with_description("Current strength"), // Additional attributes ... ]; let e = EntityBuilder::default() .with_name("Entity") .with_description("Some Entity") .with_attributes(attributes) ... .build().expect("Failed to build entity"); }
In both examples, we define two attributes: "max_health" with an initial value of 100 and "strength" with an initial value of 10. You can add as many attributes as needed, each with a unique name and appropriate initial or base value.
Defining Attributes Declaratively
Attributes can be defined declaratively directly in an entity blueprint definition using Lua
local entities = {
{
-- Declare an entity
blueprint_id = "ENTITY#1",
name = "Entity",
description = "Some Entity",
attributes = {
{ name = "max_health", value = 100 },
{ name = "strength", value = 10 },
}
}
}
return entities
In the example above we are creating the exact same entity than in the programmatic examples above but using Alacrity's declarative Lua syntax.
Accessing Attribute Values
Once attributes are defined for an entity, you can access their values during runtime.
In Lua, you can access an attribute's value using the value() method that will return
the latest calculated value for a given attribute. Here's an example:
local max_health = entity:get_field_value("max_health")
print("Current max health:", max_health)
In Rust, you can also use the get_field_value method of the Entity type to retrieve
an attribute's value. Here's an example:
#![allow(unused)] fn main() { let max_health = entity.get_field_value("max_health"); println!("Current max health:", max_health) }
Both examples demonstrate how to retrieve the value of the "max_health" attribute. You can replace "max_health" with the name of any other attribute to access its corresponding value.
If the entity does not contains an attribute of the given name, an error will be returned.
💡 Tip
The
get_field_valuecan be used to retrieve values for both attributes and properties in both APIs Lua and Rust
Recalculating an attribute value
Attributes can be recalculated at any time, some operations, like buff activations, trigger
attribute recalculations automatically but you can trigger an attribute value recalculation
at will using the entity's recalculate_value in both Lua or Rust. The recalculate_value
expects an unique parameter containing the attribute to recalculate name.
If the given attribute can not be found in the entity, the method will return an
[AttributeNotFound] error.
Here is an example in Lua:
local ok, err = pcall(entity:recalculate_value("str"))
if not ok then
-- handle error
end
And here is the equivalent example in Rust:
#![allow(unused)] fn main() { if let Err(err) = entity.recalculate_value("str") { // handle error } }
Access attribute values from Conditional expressions
Entity attribute values can be accessed from conditional expressions through the virtual
object self for example, to access one attribute called str in a buff's conditional
that is attached to an entity we can use the following syntax in the condition expression:
self.str >= 10
The expression above would resolve as true only if the entity's str attribute value is
equal or higher than 10.