Resource (Power Type)
Provides a variable with an assignable, modifiable, and optionally dynamic minimum and maximum value.
Provides a variable with an assignable, modifiable, and optionally dynamic minimum and maximum value.
Type ID: apoli:resource
This power type provides a variable that can be changed with the apoli:modify_resource (and the legacy apoli:change_resource, which auto-translates into Modify Resource), and the value of which can be checked with the Resource (Entity Condition Type).
What’s new vs. Apace’s apoli:resource
min,max, andstart_valueaccept either an Integer or an Expression. When an Expression is used, the limit is re-evaluated on every tick so the ceiling can shift in response to other resources, entity stats, or world state.enforce_limitsandretain_valueare first-class options (taken from theapoli:modifiable_resourcepower type in Origins: Math). Whenenforce_limitsisfalsethe value can travel outside[min, max]until something clamps it.- Values persist across server restarts via the entity’s
PowerContaineraux-data store. maxis optional. Leave it out and the resource is uncapped upwards — useful for score counters and running totals that should never hit a ceiling.minis optional too, and leaving it out makes the resource uncapped downwards.sizeturns one power into a table of that many independently addressable slots.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
min | Integer OR Expression | unbounded | The minimum value of the resource. When an Expression, re-evaluated each tick. Omit it and the resource has no lower bound. |
max | Integer OR Expression | unbounded | The maximum value of the resource. When an Expression, re-evaluated each tick. Omit it and the resource has no upper bound. |
start_value | Integer OR Expression | value of min, or 0 when there is no min | The value of the resource when the entity first receives the power. Also aliased as default. |
size | Integer | 1 | How many values this resource stores. Above 1 the power becomes a table of that many slots, each addressed by a position from 0 to size - 1. Also aliased as positions and slots. There is no upper limit — see Big tables. |
hud_render | Hud Render | hidden | Determines how the resource is visualized on the HUD. A bar needs a value to fill up to, so an uncapped resource needs a max on the hud_render — see Hud Render. |
enforce_limits | Boolean | true | Whether the resource value is clamped to [min, max]. |
retain_value | Boolean | false | When enforce_limits is true: if a modification would push the value outside the bounds, keep the old value instead of clamping. |
min_action | Entity Action Type | optional | Run on the entity whenever the value reaches min. |
max_action | Entity Action Type | optional | Run on the entity whenever the value reaches max. |
persistent | Boolean | true | When true, the value survives server restart (and survives the entity unloading/reloading). When false, the value resets to start_value whenever the entity rejoins the world. Useful for resources that semantically should reset, like daily-quest counters or cooldowns you want to clear on login. |
Storing more than one value
Set size and the resource holds a row of independent values instead of a single one. Every slot shares the same min / max / start_value / enforce_limits rules, and every slot is addressed by a position — a zero-based index.
{
"type":"apoli:resource",
"min":0,
"max":64,
"start_value":0,
"size":6
} That stores six values, 0 through 5, all starting at 0.
Reading and writing a slot:
- apoli:resource (entity condition) takes a
position. Leave it out and the condition passes if any slot matches. - apoli:modify_resource takes a
position. Leave it out and the modification is applied to every slot. - In an Expression,
example:table[2]reads slot 2,example:table_sizeis the slot count, andresource_contains(example:table, 5)asks whether any slot holds5. /apoli:resource get|set|change <targets> <power> [position]reads or writes one slot;/apoli:resource listprints the whole table.
Slot 0 is the resource’s scalar value: anything that reads the resource without a position (the HUD bar, an unindexed Expression reference, min_action / max_action) sees slot 0.
Big tables
Slots are only allocated when they are written. Declaring "size": 1000000 costs nothing on its own: the resource stores slot 0 and grows only as far as the highest slot you have actually written to. A slot you have never written reads as start_value, so an unwritten table behaves exactly as if it were full of that value.
That is why there is no cap on size. What it costs you is decided by which slots you write, not by the number you declare. Writing slot 999999 does allocate a million slots’ worth of memory for that holder — about 4 MB — and that memory is saved to disk and sent to clients with the rest of the power’s data, so write high slots deliberately rather than by accident.
size is also the guard on a computed position: a write to a slot at or above size is refused, so however wrong an index expression goes, it can never allocate past the number you declared. Declaring a size far larger than you need gives that guard nothing to do, so pick a number that reflects the table you actually want.
Apoli logs one warning naming the power if a declared size is above 65536, as a check against a typo like an extra zero.
min_actionandmax_actionfire per slot in table mode, so a write with noposition— which touches every slot — can firemax_actionseveral times in one go.
Because slots are ordinary Expression values, a table doubles as a vector store.
example:pos[0],example:pos[1]andexample:pos[2]feed straight into any field that takes an Expression — a velocity, a damage amount, a modifier — with noif_else_listof hard-coded numbers in between.
Available variables in Expression fields
When min, max, or start_value are written as Expression strings, the following variables are bound:
value: The current value of this same resource (useful for limits that depend on the current stockpile, e.g. a max that grows as the resource accrues).<namespace>:<path>: Any other resource the entity has, referenced by its full power id. Add[n]to read a slot of a table resource, and the_min/_max/_sizesuffixes to read its bounds and length.health,max_health,food,air,xp_level,xp_progress: Common entity stats.world_time,day_time: Long ticks from the entity’s level.
See the Expression page for the complete list.
A
min_actionormax_actionthat fails to parse is dropped, not silently ignored. The log carries a warning naming the power and the field —Ignoring the 'max_action' field of <power id> — it is present but failed to parse— followed by the underlying reason. The rest of the resource still loads, so the bar works and only the boundary action is missing.
The most common cause is a legacy damage source: apoli:damage takes
damage_type(a damage type ID), not the pre-1.19.4sourceobject.
Examples
A binary flag (boolean-like resource):
{
"type":"apoli:resource",
"min":0,
"max":1,
"hud_render":{
"should_render":false
},
"min_action":{
"type":"apoli:heal",
"amount":6
}
} A mana pool whose maximum scales with the player’s XP level:
{
"type":"apoli:resource",
"min":0,
"max":"20 + 5 * xp_level",
"start_value":0,
"hud_render":{
"should_render":true,
"bar_index":2
}
} A bar has no scale without a
max. If you want one on an uncapped resource, put amaxon thehud_renderinstead — the resource stays uncapped and the bar fills up to that value.
An uncapped score counter — no max, so it can grow forever:
{
"type":"apoli:resource",
"min":0,
"start_value":0
} A six-slot table used as a saved position (x, y, z) plus three spare slots:
{
"type":"apoli:resource",
"min":-30000000,
"max":30000000,
"start_value":0,
"size":6
} A resource whose ceiling is the value of another resource (composes cleanly without nesting):
{
"type":"apoli:resource",
"min":0,
"max":"example:mana_capacity",
"start_value":0
}