Skip to content

Story Tools

These Pheno types are made for stories and Personas. Use them in named conditions and actions, in goals, and in rewards. They work anywhere else that Pheno does, too.

In a story, the action or condition runs on the teller, and the player is other. Types that need a player use the player wherever they are.

True when the world rolled this value for a Persona. False while the Persona has not rolled it yet.

{ "type": "pheno:persona_roll", "persona": "examplepack:old_sailor", "roll": "home_port", "value": "north" }
FieldDescription
personaThe Persona ID.
rollThe roll’s name.
valueA value, or a list of values (any of).
containsInstead of value: matches one entry of a comma-separated value, such as "farmer" in "farmer,cook".

True when the entity is within radius blocks of a place marked with pheno:mark_structure. For a player, their own mark. For a villager, the mark of the other player, such as a Persona who travels with you.

{ "type": "pheno:near_marker", "key": "old_wreck", "radius": 48 }

The default radius is 48.

True when a position is inside a work area.

{ "type": "pheno:in_work_area", "area": "townstead:field_post", "at": "job_site" }
FieldDescription
areatownstead:field_post: the ground that a Field Post plans. townstead:field_post_soil: the cells that a Field Post plan marks as soil. Without area, any work area.
atself (default): where the entity stands. job_site: the entity’s workstation, or where it stands when it has none.

True when a mod is installed. With a list, when any of them is.

{ "type": "pheno:mod_loaded", "mod": ["examplefishingmod", "otherfishingmod"] }

In Ink, use mod().

True when this modpack can build a building: a building type matches, and every block it needs exists. A plain name matches every tier from every mod, so kitchen matches any kitchen. A name with / is an exact building type. With a list, when any of them can be built.

{ "type": "pheno:can_build", "building": ["tavern", "cafe"] }

Use this rather than pheno:mod_loaded when content needs a building, not one mod. Several mods can add a kitchen.

True when the villager has at least one day in their weekly schedule with no work hours. With "village": true, when every working resident of the villager’s village has one.

{ "type": "pheno:rest_day", "village": true }

pheno:village has three more fields that stories use often:

FieldTrue when
has_buildingThe village has a building of this type. A name or a list (any of). A plain name matches every tier from every mod.
player_foundedtrue: a player started the village. false: the village was already there.
min_free_bedsThe village has at least this many beds that nobody lives in.

True when a Chronicle counter is in a range. Stories use counters to leave marks that other stories read.

{ "type": "pheno:chronicle_count", "key": "examplepack:heard_the_legend", "at_least": 1 }
FieldDescription
keyThe counter.
at_leastThe default is 1.
at_mostOptional.

Counters are on the server only. Do not use this condition for anything the client must show.

True when the villager is a Persona. With persona, true only for that Persona.

{ "type": "pheno:persona", "inverted": true }
FieldDescription
personaOptional. A Persona ID, such as examplepack:old_sailor.

Use it with "inverted": true when an action picks villagers at random, so that it does not pick a Persona.

How much the entity counts in the town it stands in. 0 outside any town’s range.

{ "type": "pheno:standing", "source": "deeds" }
sourceCounts
total (default)All of the parts below.
heartsThe residents’ hearts toward the entity.
deedsWhat the entity has built in the town.
reputationThe entity’s reputation in the town, from a reputation mod when one is installed.

It makes a good arrival goal: "value": {"type": "pheno:standing"}, "target": 20.

Adds to a Chronicle counter. With "on": "other", on the player.

{ "type": "pheno:add_count", "key": "examplepack:heard_the_legend", "on": "other", "amount": 1 }

The default amount is 1. Read the counter with pheno:chronicle_count.

Another Persona arrives in this village some days later, as if the teller wrote to a friend.

{ "type": "pheno:introduce_persona", "persona": "examplepack:net_maker", "delay_days": [1, 2] }
FieldDescription
personaThe Persona ID.
delay_daysA number of days, or a [min, max] range.

Nothing happens when the Persona already lives there, is already on the way, or the player has met them before.

The teller tells the player their family name. For a Persona with "family_name": "told", the player sees the family name from now on. See Names.

{ "type": "pheno:share_family_name" }

Sends the player somewhere. Townstead finds the nearest structure from a tag, between min and max blocks away, remembers it for the player under key, and gives them a map with the place marked.

{
"type": "pheno:mark_structure",
"key": "old_wreck",
"structures": "#minecraft:shipwreck",
"min": 300,
"max": 900,
"map_name": "A map drawn from memory"
}
FieldDescription
keyRequired. The name of the mark, for pheno:near_marker and goal marker.
structuresA structure tag. The default is #townstead:story_ruins: trail ruins and pillager outposts.
min, maxThe distance band, in blocks. The defaults are 500 and 1500.
fallbackA structure template to place in the band when no structure from the tag is found. The default is a small ruined house.
mapfalse to give no map. The default is true.
map_nameThe map’s name, as a translation key. Plain text also works, in one language only.

It runs once for each key and player. Later runs do nothing.

A goal with "marker": "old_wreck" shows the place in the Quest Ledger, with {x} and {z} in its text.

Gives the player a story item. With "drop": true, the item drops at the feet of the teller instead.

{ "type": "pheno:give_story_item", "item": "examplepack:old_letter", "count": 1 }

Takes items from the player, such as for a delivery. It takes nothing and fails when the player carries fewer than count.

{ "type": "pheno:take_items", "item": "minecraft:cod", "count": 10 }

Name the items with one of item, tag or story_item.

Starts a ritual at the altar of the order in the teller’s village. With "on": "other", the player is the candidate. Without it, the teller is the candidate.

{ "type": "pheno:start_ritual", "ritual": "examplepack:guild_oath", "on": "other" }
FieldDescription
ritualThe ritual ID.
onself, the default, or other.

The action fails when the ritual cannot start, for example when the candidate is too far from the altar. A player candidate sees the reason. Use the result of act() to choose the next line.

A story item is an ordinary item with its own name and text, such as a letter, a keepsake or a key. Stories can recognize it later.

data/<namespace>/story_item/<name>.json
{
"schema": "townstead:story_item/v1",
"base": "minecraft:paper",
"name": { "translate": "story_item.examplepack.old_letter" },
"lore": [ "Sealed with blue wax." ],
"glint": true
}
FieldDescription
schemaRequired. Must be townstead:story_item/v1.
baseRequired. The item it is made from.
nameRequired. The item’s name.
loreLines of description.
custom_model_dataA number for a resource pack’s own model.
glinttrue for the enchantment shine.
bookFor a minecraft:written_book base: title, author and pages.

Text is a plain string, {"text": "..."}, or {"translate": "<key>", "with": [...]}. Townstead makes the text in the player’s language when it gives the item.