Skip to content

Entity States

An entity state is a named number on a villager or a player. Use a state for something an entity is or has for a time, such as a curse, a transformation, an illness, or a mood. A state has a range and optional tiers. Other data can read the state, and can run actions when the state changes.

A state has three kinds of file:

FileFolderPurpose
Statedata/<namespace>/entity_state/Defines the state: its range, tiers, and how long it lasts.
Backingdata/<namespace>/state_backing/Tells Townstead where the value comes from for a kind of entity.
Effectdata/<namespace>/state_effect/Runs actions or grants genes while the state is active or when it changes.

A persistent state with an owned backing also needs a resource of the same ID. See Saving The Value.

This example adds a werebear curse to villagers. The curse has two tiers. A cursed villager growls at random, and gains strength at the second tier.

data/examplepack/entity_state/werebear.json:

{
"schema": "pheno:entity_state/v1",
"min": 0,
"max": 10,
"tiers": [
{ "id": "cursed", "min": 1 },
{ "id": "feral", "min": 5 }
],
"persistence": "persistent",
"death": "keep"
}

data/examplepack/state_backing/werebear_villager.json:

{
"schema": "pheno:state_backing/v1",
"state": "examplepack:werebear",
"applies_to": {
"type": "pheno:or",
"conditions": [
{ "type": "pheno:entity_type", "entity_type": "mca:male_villager" },
{ "type": "pheno:entity_type", "entity_type": "mca:female_villager" }
]
},
"source": { "type": "pheno:owned" },
"writable": true
}

data/examplepack/baseline_power/werebear.json:

{
"type": "pheno:resource",
"min": 0,
"max": 10,
"start": 0,
"persist_on_death": true,
"display": { "visibility": "never" }
}

data/examplepack/state_effect/werebear_growl.json:

{
"schema": "pheno:state_effect/v1",
"state": "examplepack:werebear",
"min_tier": "cursed",
"while_active": {
"interval": 400,
"chance": 0.3,
"do": { "type": "pheno:play_sound", "sound": "minecraft:entity.polar_bear.warning" }
}
}

data/examplepack/state_effect/werebear_strength.json:

{
"schema": "pheno:state_effect/v1",
"state": "examplepack:werebear",
"tier": "feral",
"genes": { "grant": ["examplepack:bear_strength"] }
}
FieldDefaultDescription
schemapheno:entity_state/v1.
idthe file’s IDThe state ID.
modsOptional. Townstead loads the file only when these mods are present.
min, max0, 1The range of the value. min must be less than max.
initialminThe value before anything sets the state.
tiersNamed steps, from low to high. Each tier has an id and a min. See Tiers.
mergemaxHow Townstead combines values from more than one backing: first, max, sum, or latest.
persistencepersistentpersistent saves the value with the entity. session keeps it only until the server stops.
deathclearkeep or clear. What happens to the value when a player dies.
bodyanyvillager lets only entities with the MCA villager body take the state. A Root can allow its own body.
excludesState IDs. While one of these states is active, Townstead cannot give this state to the entity.
aspectShows the state in the editor and in the Aspects screen.

A state is active when a backing gives it a value. When an action sets the state to min or lower, Townstead clears it.

A tier is a named step of the state. The entity is in the highest tier whose min is less than or equal to the value.

Tier FieldDescription
idRequired. The tier name.
minRequired. The lowest value of the tier.
rigOptional. A rig that the entity takes while in this tier, such as a beast form.
talkfalse stops conversation while in this tier. The default is true.
sleepfalse stops sleep while in this tier. The default is true.
ridefalse stops the entity from riding a mount or a vehicle while in this tier. If the entity rides when it enters the tier, it gets off. The default is true.
variantsOptional. Maps rig variant names to other states, such as a coat or eye colour.

A backing tells Townstead where the value comes from. Make one backing for each kind of entity.

FieldDefaultDescription
schemapheno:state_backing/v1.
stateRequired. The state ID.
applies_toOptional Pheno condition. The kinds of entity that this backing is for.
sourceRequired. See the table below.
writablefalsetrue lets actions and commands set the value. Only an owned source can be writable.
read_priority0When more than one backing applies, Townstead reads the highest first.
write_priorityread_priorityWhen more than one writable backing applies, Townstead writes to the highest.
Source TypeFieldsValue
pheno:ownedresourceTownstead stores the value. resource is the resource that holds it, and its default is the state ID.
pheno:status_effecteffect, amplifier, presence_valueThe value comes from a status effect. amplifier maps effect amplifiers to amounts or tiers. Without a match, the value is presence_value, which defaults to 1.
pheno:providerprovider, levelsThe value comes from another mod, through a provider that Townstead registers. levels maps whole-number readings to amounts or tiers.

A persistent state with an owned backing stores its value in a resource. The resource has the same ID as the backing’s resource, which is the state ID by default. Declare it in data/<namespace>/baseline_power/<name>.json as a pheno:resource, with the same range as the state.

If the resource is missing, Townstead cannot read or set the state. Nothing in the game changes, and Townstead does not show an error.

An effect runs actions or grants genes for a state. An effect needs at least one hook or genes.

FieldDescription
schemapheno:state_effect/v1.
stateRequired. The state ID.
tierOptional. The effect applies only in this tier.
min_tierOptional. The effect applies in this tier and every higher tier. Do not use it with tier.
conditionOptional Pheno condition. The entity must also pass it.
priorityTownstead applies higher numbers first. The default is 0.
on_enterAction that runs when the state becomes active.
on_tier_changeAction that runs when the tier changes while the state stays active.
on_exitAction that runs when the state stops being active.
while_activeinterval in ticks, chance from 0 to 1, and a do action. The action runs at each interval while the state is active.
genesgrant and suppress lists of gene IDs. Granted genes replace what the entity expresses at the same locus while the effect applies.

An action can set a state with a duration in ticks:

{ "type": "pheno:set_state", "state": "examplepack:curing", "amount": 1, "duration": 3600 }

When the time ends, the state stops being active and its on_exit action runs. A persistent state keeps counting after a restart. Use this for a change that ends later, such as a cure, or an illness that ends by itself. See Gift Reactions for an example.

UseNode
Test a statepheno:state condition, with state and min, max, tier, min_tier, or max_tier
Test if an entity can have a statepheno:state condition, with state and "eligible": true. True when the entity’s body and Root can carry the state, whatever its value is now.
Read the valuepheno:state_amount, pheno:state_tier, and pheno:state_remaining values
Set the valuepheno:set_state action, with amount and an optional duration
Add to the valuepheno:add_state action
Clear the valuepheno:clear_state action