Entity's Properties

Introduction

Properties allow you to define and query entities additional information that can be queried and manipulated during the entities life time. Properties allows you to attach key-value pairs of read-only metadata that enables you to customize and extend their functionality beyond core attributes.

Properties are commonly used to store metadata, configuration settings or any other relevant information associated with an entity. They provide a mechanism for adding context specific data that can be accessed and manipulated during gameplay or system interactions.

Anatomy of a Property

Properties are composed of a few fields that define them. They are pretty similar to their siblings Attributes but they differ significantly at a conceptual level.

FieldTypeDescription
idUUIDThe property unique identifier
nameStringThe property name (e.g 'level', 'current_area_name', 'class'...)
descriptionStringAn human friendly property description
valueAlacrity:ValueThe property value (it can be of types i64, f64, String and bool)
appears_in_conditionsboolDetermines if the property will be accessible by Lua in conditional expressions

Continue reading to find a detailed description about each of the fields in the sections below

ID

As attributes, each property has an unique ID, this is generated automatically by Alacrity when a Property is created. The ID is basically used internally by Alacrity, users normally doesn't need to worry about it.

Name

The property's name is used to both provide an human-friendly short reference to the property itself and to target the property while evaluating condition expressions. Property names must always be strings.

⚠️ Alert

Alacrity will not prevent you from creating entities with name clashes between their properties and their attributes. That would probably cause issues while evaluating modifiers and buffs conditions as the condition evaluation Scope is not able to differentiate from attribute or property values while evaluating conditional [expressions].

Description

Human friendly description of what the property represents for the entity.

Value

The property's value is set during property initialization and can be updated programmatically from both Rust and Lua APIs. The value of a Property differs from that of an attribute in the way that property values can contain not only float and integer values but also boolean or String values.

Appears in Conditions

This is a boolean field that determines if the property will be accessible or not for Lua contexts in conditional expressions. If the value of this field is true the property will be accessible through the virtual object self inside the conditional expression, in the other hand, if its value is false, the property value will not be accessible by the Lua context in the expression.

This is useful to prevent leaking of sensible metadata or to prevent conditional Scopes to grow with no need.

Key Features

Dynamic and Flexible

Entity properties offer a dynamic and extensible storage for data associated with entities that needs to be accessed often or fast on runtime. You can define properties on an entity, assign values to them and retrieve or modify those values at runtime.

This flexibility allows you to adapt and customize entities based on specific requirements, scenarios or game mechanics.

Arbitrary Data

Properties can store a wider range of data types including strings, booleans, floating point and integer values. This versatility enables you to capture different aspects of an entity's state or configuration. Whether is a character's level, a quest status, or a custom gameplay flag, properties provide a generic container for various types of data.

Easy access and manipulation

Alacrity provides convenient APIs and syntax for working with entity properties. You can easily access, modify and remove property values through dedicated methods or by using the Lua's API. This streamlined access allows you to integrate properties seamlessly into your gameplay logic or system interactions.

Defining Properties

Properties can be defined in declarative or programmatic way. They can be part of an entity definition or they can be added later during runtime. This differs greatly from attributes that can be defined declaratively only and can not be attached at a later stage without updating the entity's template first.

Properties are typically declared as key-value pairs, where the key represents the property's name and a short reference to access it from both programmatic APIs and conditional expressions.

Here's an example of how to define a property in Lua:

local properties = {
    { name = "class", value = "cleric", description = "Character's class" },
    { name = "level", value = 1, description = "Character's initial level" },
    -- Additional properties ...
}

local e = alacrity.Entity.new({
    name = "Cleric Template",
    description = "A cleric archetype initial character template",
    properties = properties,
    ...
})

Managing Properties

Properties can be managed in runtime from both Rust or Lua APIs. Properties can be added, updated or removed from entities.

⚠️ Alert

Modify the entity properties in any way should trigger buffs checks. This is due the fact that buffs and modifier conditionals that were meet before the change could not be meet after the change or the other way around.

As a rule of thumb, perform an activate_buffs and a deactivate_buffs in the entity after any kind of property modification if their values are used in the conditional expressions for buffs and modifiers.

It might also be a good idea to trigger recalculate_value in specific attributes if you know a related property has changed.

Property Addition

To add a property, the add_properties method is used, for example to add a new property to an entity we could use the following Lua code:

-- let's assume that e is an already defined and initialized entity
local ok, err = pcall(function()
    e:add_properties({
        { name = "level", value = 1, description = "Character's level" }
    })
end)

if not ok then
    -- handle error
end

The same example in Rust would be:

#![allow(unused)]
fn main() {
// let's assume that e is an already defined and initialized entity
if let Err(err) = e.add_properties(&[Property::new("level", Value::from(1)).with_description("Character's level")]) {
    // handle error
}
}

Property Update

Properties can be updated using the update_properties method. This method can also be used to add properties if the optional add_if_missing flag is set to true.

💡 Tip

Use the add_if_missing with new properties if you need to update and add properties so you can do it with a single API call instead of two.

To update a property we can use the following Lua code:

-- let's assume that e is an already defined and initialized entity
e:update_properties({ { name = "class", value = "barbarian" } }, false)

The equivalent code using the Rust API:

#![allow(unused)]
fn main() {
// let's assume that e is an already defined and initialized entity
e.update_properties(&[Property::new("class", Value::from("barbarian"))], false)
}

The update_properties method will not return any errors in case that the property trying to get updated does not exists and add_if_missing is false

Property Removal

Properties can also be removed from entities, there are small differences between the Lua and the Rust API for property removal as while using the Lua api we can use a property instance or the property name in order to remove it from the entity while in the Rust API only property instances are accepted by the method.

-- let's assume that e is an already defined and initialized entity
e:remove_properties({
    { name = "quest_ftue_001_status", value = nil }, -- using an instance
    "player_terms_and_conditions_acceptance" -- using a property name directly as a string
})

The very same example in Rust:

#![allow(unused)]
fn main() {
// let's assume that e is an already defined and initialized entity
e.remove_properties(&[
    Property::new("quest_ftue_001_status", Value::nil()),
    Property::new("player_terms_and_conditions_acceptance", Value::nil())
])
}

The remove_properties method will not raise an error if we try to remove a property that does not exists in the entity.