Skip to content

Subjects

A subject is a thing to talk about. A subject file names a source. When a topic is about to start, Townstead asks the source for live instances for the speaker and the listener. For example, the weather source gives one instance with the variant rain while it rains.

Each instance has:

PartDescriptionUsed by lines through
VariantA word for the kind of instance, such as rain, hungry or marriage.variants
Valencepositive, negative or neutral.valence
SlotsNamed values for the text, such as {who} or {biome}. A person slot also holds the ID of that person.Placeholders, persp
ProvenanceHow the speaker knows: witnessed, heard, and shared when the listener already knows.provenance
UrgencyHow much the speaker wants to raise it, from -1 to 1.Topic choice. See Goals.
data/<namespace>/conversation_subject/<name>.json

The file ID is the subject ID. Topics, frames and lines name subjects by ID. A line can write "subjects": "weather" for townstead:weather.

{
"schema": "townstead:conversation_subject/v1",
"source": { "type": "townstead:mob_sighting" },
"register": "social",
"slots": {
"mob": { "type": "text", "from": "mob.name" },
"a_mob": { "type": "text", "from": "mob.name_with_article" },
"who": { "type": "person", "from": "mob.witness", "required": false }
},
"valence": "negative"
}
FieldRequiredDescription
schemaYesMust be townstead:conversation_subject/v1.
sourceYesAn object with type, the source type, and any settings of that source.
registerNoThe register of lines about this subject. It replaces the topic’s register. The default is ambient.
requiresNoRequirements that must all be true for the speaker.
Gate fieldsNocontext, relationship, personality_weights, relationship_weights, when, evaluation. A gate of 0 hides the subject. See Gates.
symmetricNoTwo or more slot names for roles that can swap, such as the two people in an argument. When the speaker or listener is in one of these roles, Townstead moves them into the first one. Lines then only need to handle the first role.
slotsNoA description of each slot: type, from, and required. Types are person, place, organization, profession, item, title, topic_phrase, time_ago, amount and text. The name self is reserved. Townstead checks the types, but the source sets which slots an instance has.
valenceNopositive, negative, neutral or from_source. Accepted. The source sets the valence of each instance.
weight, interests, content_tagsNoAccepted, but not used yet.
modsNoA mod gate.

A data pack can use these sources. A new source needs code: a mod can register one with SubjectSources.register.

The weather at the speaker’s position. One instance, neutral, with no slots.

VariantWhen
thunderA thunderstorm.
snowRain where it is cold enough to snow.
rainRain.
clearNo rain.

The biome at the speaker’s position. One instance, neutral, with the slot {biome}.

  • The English text is “the” and the biome name, such as “the plains” or “the dark forest”.
  • The slot has the fact number: plural for biomes such as plains, badlands and peaks, and singular for all others. Use it in selectors.
  • Translations come from townstead.biome_phrase.<namespace>.<path>. See Translations.
  • To write a line for one kind of biome, use the requirement here.biome_tag:<tag>, such as here.biome_tag:c:is_desert.

Stories from the Chronicle that the speaker believes. This is how news and gossip get into conversations. The source settings map Chronicle event templates to subject variants.

"source": {
"type": "townstead:chronicle_account",
"max_age_days": 14,
"min_fidelity": 0.2,
"events": {
"townstead:wedding": {
"variant": "marriage",
"valence": "positive",
"roles": { "who": "partner", "other2": "spouse" }
},
"townstead:zombie_bite": {
"variant": "bitten",
"valence": "negative",
"roles": { "who": "bitten" },
"while_infected": true
}
}
},
"symmetric": ["who", "other2"]
SettingDescription
eventsA map from Chronicle event template ID to a mapping. Stories from other templates are ignored.
events.<id>.variantThe variant of the instance.
events.<id>.valencepositive, negative or neutral. The default is neutral.
events.<id>.rolesA map from slot name to a role of the Chronicle event. Each slot is a person slot.
events.<id>.while_infectedWhen true, the story goes stale once the person in it is no longer infected. Townstead checks villagers that are loaded.
max_age_daysStories older than this many days are ignored. The default is 14.
min_fidelityStories that the speaker believes less than this, from 0 to 1, are ignored. The default is 0.

How instances work:

  • The speaker uses the names they believe. A distorted story can have the wrong name.
  • A story about both the speaker and the listener is skipped.
  • Provenance is witnessed when the speaker took part in the event, else heard. It also has shared when the listener knows the story or took part in it.
  • Urgency is -0.3 for a shared story. For a story the speaker learned in the last day, it is 0.6 × fidelity + 0.2. For older stories it is 0.
  • When a line with the spreads move tells the story, the listener learns it.

Townstead ships two subjects with this source: townstead:event (arguments, masteries and weddings) and townstead:infection_news (bites, cures and villagers who turned).

One instance, neutral, with no variant and no slots. Use it for a topic that is always available, such as jokes.

One instance, neutral, while the speaker is at a hangout. Use the state key venue and the venue.* requirements to write lines for kinds of venue.

The speaker’s most pressing need. One instance, negative, with no slots.

VariantNeed bandsUrgency
hungryhungry, famished0.4, 0.8
thirstythirsty, parched0.4, 0.8
tiredtired, drowsy0.4, 0.8
coldcold, freezing0.8, 1.0
hothot, sweltering0.8, 1.0

Only enabled needs count. A villager only mentions cold or heat when it is strong: chilly and warm are left out.

Hostile mobs that villagers in the speaker’s village saw today or in the two days before. There is one instance for each sighting, negative.

SlotValue
{mob}The mob’s name, in lowercase, such as “zombie”.
{a_mob}The name with an article, such as “a zombie” or “an enderman”.
{who}The witness, as a person slot.
  • When a villager looks for someone to talk to, Townstead records the nearest hostile mob that the villager can see within 24 blocks.
  • A villager that takes the place of a wild mob counts as that mob. The sighting uses the mob’s name.
  • Townstead keeps at most one sighting of each mob type for each village each day, and at most 8 sightings for each village.
  • A speaker does not tell the witness about their own sighting.
  • Provenance is witnessed for the witness, else heard.
  • Urgency is 0.9 for a sighting today and 0.5 for an older one.
  • The subject file also names a {where} slot. Townstead does not fill it yet, so lines that use {where} do not appear.

A friend that the speaker wants to spend time with. One instance, positive, when the speaker’s affection toward the listener is 10 or more.

VariantAffection
friend10 to 24
close25 or more

Urgency is affection / 50, at most 0.8.

A zombie infection that the speaker can talk about now. Each instance is negative, with the person slot {who} and the provenance witnessed.

InstanceVariantUrgency
The speaker was bitten, and has no fever yet.bitten0.6
The speaker has a fever.fever0.8
The listener has a fever.fever0.9
  • MCA infection progress goes from 0 to 1. The fever starts at 0.2. After 0.6, MCA turns the villager’s speech into babble, so the source gives nothing.
  • A crabby, grumpy, greedy, shy, introverted or confident villager keeps a fresh bite to themselves. They only talk about it once the fever shows.
  • Use "persp": {"who": "me"} for lines about the speaker’s own infection, and "persp": {"who": "you"} for lines about the listener’s.

A villager who has an entity state, such as a transformation that a supported mod adds. One instance, with the person slot {who} and the provenance witnessed.

"source": {
"type": "townstead:aspect_neighbor",
"state": "examplepack:werebear",
"group": "werebear"
},
"valence": "from_source",
"slots": {
"who": { "type": "person", "from": "neighbor.who" }
}
SettingDescription
stateThe entity state ID. Required. When no entity state has this ID, the source gives nothing.
groupA disposition group. When one of the speaker’s factions welcomes this group, the speaker talks about the neighbour warmly.
VariantWhenValenceUrgency
listenerThe listener has the state.neutral0.5
welcomedAnother resident of the speaker’s home village has the state, and a faction of the speaker welcomes group.positive0.4
waryAnother resident of the speaker’s home village has the state, and no faction of the speaker welcomes group.negative0.4
  • A speaker who has the state does not use this source.
  • For welcomed and wary, {who} is the nearest resident who has the state. Townstead checks residents that are loaded.
  • Use "persp": {"who": "you"} for listener lines.

To talk about a state that the speaker has, use the townstead:general source with a when gate on the subject. See Gates.

These sources exist, but give no instances yet. Townstead ships subjects and lines for them, so the talk starts when the game systems exist.

SourcePlanned subject
townstead:quest_boardJobs on the quest board. Slots {quest} and {quest_title}.
townstead:projectVillage building projects. Slot {project}.
townstead:realm_rumourRumours about rulers. Slots {ruler} and {heir}.

A subject tag groups subjects, so a topic, frame or line can name them all at once with #.

data/<namespace>/tags/conversation_subject/<name>.json
{ "values": ["townstead:event", "townstead:infection_news"] }

Use it as "subjects": ["#examplepack:news"]. Tags with the same ID from several packs add their values together.