Items#
This page lets you add or change what a player wears, crafts, enchants and drinks: affixes, set bonuses, forge catalysts, potions and the glyphs that draw equipment. Every example is JSON only.
What you can change#
- Affixes, their effects and synergies:
equipment.json. - Set bonuses and enchantment mechanics:
equipment.json. - Reagent enchantments and recipes:
crafting.json. Forge catalysts:resources.json. - Item kinds, consumables and found objects:
items.json. - Equipment glyphs:
equipment.json.
All files are in public/config/. Visible text is never written inline: you write a text key (in capitals, like AFFIX_NAME_OF_THE_GOURMET) and add it to every language file in public/config/locales/.
Affixes and their tiers#
An affix is a named bonus on an item, such as "of the Gourmet". Its family points at an effect, which is what the bonus does. Add affixes to affixes in equipment.json.
Goal: a ring or amulet suffix that reduces the hunger you use.
{
"id": "of-the-gourmet",
"label": "AFFIX_NAME_OF_THE_GOURMET",
"position": "suffix",
"family": "satiety",
"kinds": ["ring", "amulet"],
"tiers": [[3, 5], [5, 8], [8, 12], [12, 16]],
"weight": 5,
"minLevel": 1,
"group": "satiety"
}
Rings and amulets can drop with "of the Gourmet". A tier 1 item rolls a value from 3 to 5; a tier 4 item rolls 12 to 16. The item's quality caps the tier it can reach.
positionisprefixorsuffix.familymust be a declared effect.tiersholds one[min, max]range per tier: whole numbers from 0 to 1000, never lower than the tier before.weight(above 0) is the drop chance andminLevel(1 to 100) the first depth where it appears. Two affixes with the samegroupnever share an item.
Affix effects#
An effect holds modifiers (numbers that change) and listeners (reactions to an event). In both, "$value" stands for the number the affix rolled. The game ships 16 effects in affixEffects.
Goal: a "siphon" effect: when a projectile spell hits a creature, you get mana back.
{
"siphon": {
"text": "AFFIX_EFFECT_SIPHON",
"listeners": [
{
"id": "siphon-mana",
"on": "spell.hit",
"when": { "kind": "projectile" },
"action": "restoreMana",
"params": { "amount": "$value" },
"cooldown": 2
}
]
}
}
Write an affix with "family": "siphon", as above. Every effect also needs exactly one engraving reagent, in engrave.reagentByFamily of crafting.json:
{ "siphon": "pearl" }
An item with the affix returns mana equal to its value when a projectile spell hits, at most every 2 turns. Players engrave the affix with pearl.
- For a plain number, use a modifier instead of a listener:
"modifiers": [{ "hook": "mana.max", "op": "add", "value": "$value" }]. "perSkill": truegives each affix its ownskill, which a condition reads as"when": { "skill": "$skill" }.- Give listeners an
id, so their cooldown survives your edits.
Synergies#
A synergy rewards a named item that carries affixes from several families. Add it to synergies in equipment.json. Its effect is always on; its special is a listener, or a chance modifier.
Goal: a critical hit heals you.
{
"id": "bloodthirst",
"label": "SYNERGY_BLOODTHIRST",
"requires": ["damage", "drain"],
"priority": 5,
"effect": {
"text": "SYNERGY_BLOODTHIRST_EFFECT",
"modifiers": [{ "hook": "hit.drain", "op": "add", "value": 1 }]
},
"special": {
"text": "SYNERGY_BLOODTHIRST_SPECIAL",
"announce": "SYNERGY_BLOODTHIRST_TRIGGERED",
"on": "hit.dealt",
"when": { "critical": true },
"action": "heal",
"params": { "amount": "$power" },
"power": 2
}
}
An item with a damage affix and a drain affix gains +1 life drain on every hit. Each critical hit also heals 2 life (4 on an exceptional item) and writes the announcement to the log.
- Synergies refuse
"$value". Aspecialmay use"$power"once it declarespower. - Add
"chance": 0.5to the special for a 50 % trigger.
Set bonuses#
A set bonus applies when the player wears enough pieces of a set. Each threshold in a set's thresholds list (in sets.equipmentSets of equipment.json) has its own modifiers and listeners.
Goal: a third bonus for the 4-piece "lanterniers" set.
{
"pieces": 3,
"modifiers": [
{ "hook": "hunger.cost", "op": "mul", "value": 0.9 },
{ "hook": "attack.accuracy", "op": "add", "value": 1, "when": { "target": "lit" } }
],
"listeners": [
{
"on": "floor.entered",
"action": "revealTraps",
"params": { "radius": 6 }
}
]
}
With 3 pieces worn, hunger costs 10 % less, attacks on lit targets gain +1 accuracy, and each new floor reveals traps within 6 cells. The 2-piece bonus still applies.
piecesis a whole number from 1 to the set size, unique in the set. Thresholds stack.- Write plain numbers:
"$value"is refused here. - A brand new set also needs each piece in
basesand one recipe link incrafting.json. List the piece undersets.equipmentSetsinequipment.json; this membership is its only set reference.
Enchantments#
An enchantment is a permanent power the player writes on an item with a reagent. Its behaviour is an enchantment mechanic in enchantments.mechanics of equipment.json. There, "$value" is the strength of the inscription.
Goal: every third hit sends an arcane wave around you.
{
"wave-third": {
"text": "ENCHANTING_EFFECT_WAVE_THIRD",
"listeners": [
{
"id": "third-blow-wave",
"on": "hit.dealt",
"action": "wave",
"params": { "every": 3, "element": "arcane", "amount": "$value" }
}
]
}
}
On a weapon with this enchantment, every third hit deals arcane damage to all adjacent enemies.
Attach the mechanic to a reagent in enchanting.permanentEffects of crafting.json: "resonance": { "base": 1, "step": 34, "weapon": "wave-third", "armor": "shock-recharge" }. Each reagent names one mechanic for weapons and one for armor. A weapon mechanic can only listen to hit.dealt; an armor mechanic to hit.taken or turn.started.
To share an existing affix effect, write only { "affixEffect": "mana" } for the mechanic. Do not add a second text, modifiers or listeners beside that reference. Mana and light use their shared description with {value}; direct mechanic descriptions use {p0}. Add new text keys to all nine language files. In this context only $value is available, never $skill.
Forge catalysts#
A catalyst is an item the forge burns to help one crafting. Add it to craftingCatalysts in resources.json.
Goal: +30 forge skill and one gold coin per crafting, using two units each time.
{
"id": "moon-dust",
"name": "WORLD_MOON_DUST",
"symbol": "*",
"color": "#abcdef",
"units": 2,
"modifiers": [{ "hook": "craft.skill", "op": "add", "value": 30 }],
"listeners": [{ "on": "item.crafted", "action": "giveGold", "params": { "amount": 1 } }]
}
Crafting with moon dust uses 2 units, rolls quality as if forge skill were 30 higher, and pays 1 gold when the item is made. Outside that crafting it does nothing.
unitsis a whole number from 1 to 10, spent even if quality does not improve.- Modifiers may target only
craft.skill,craft.qualityandcraft.duration. Listeners may react only toitem.crafted.
Item kinds and consumables#
An item kind is a family of objects (potion, torch, tome) declared in itemKinds of items.json. It says whether items are consumable, which forge they need and what they do when used. A recipe link in crafting.json points to its output. The base in equipment.json or the recipe item in items.json declares the kind.
Goal: a potion that restores mana, sold by merchants and listed under its own filter.
First the filter, added to itemFilters:
{
"mana-draught": { "label": "GAME_MANA_ELIXIR", "inventoryOrder": 20, "craftOrder": 20, "tieBreakOrder": 20 }
}
Then the kind:
{
"mana-draught": {
"consumable": true, "equippable": false,
"effects": [{ "action": "restoreMana", "params": { "amount": "$power" } }],
"needsForge": true, "craftSkill": "alchemy", "namedByRecipe": true,
"merchantStock": 1, "alwaysStocked": false,
"filter": "mana-draught",
"description": { "category": "INVENTORY_DETAIL_CONSUMABLE", "text": "MANA_ELIXIR_DESCRIPTION" },
"statLabel": { "heading": "INVENTORY_DETAIL_RESTORATION", "value": "ITEM_EFFECT_MANA" },
"protection": false, "sheetGroup": null
}
}
Then the item itself, added to recipeItems in items.json, and the recipe that makes it, added to recipes in crafting.json. Both are shown together here:
{
"item": {
"id": "mod-mana-draught", "kind": "mana-draught",
"name": "GAME_MANA_ELIXIR", "icon": "!", "power": 15, "lore": "MANA_ELIXIR_DESCRIPTION"
},
"recipe": { "id": "mod-mana-draught", "output": { "item": "mod-mana-draught" }, "cost": { "pearl": 1, "root": 1 } }
}
The player crafts the draught from a pearl and a root and finds it under its own filter. Drinking it restores 15 mana: $power is the power of that item.
- An item may carry its own
effectslist to replace its kind's. An empty list means no effect. - Unknown actions and wrong parameters are refused at load.
Effects and use#
An effects list is a series of actions run in order. The optional use block says how the item is aimed: scope is self, adjacent, direction or item, with a range.
{
"scope": "direction", "range": 5,
"effects": [{ "action": "noise", "params": { "intensity": 2 } }]
}
The player aims up to 5 cells away. A noise of intensity 2 is made in the target cell, and nearby creatures may hear it.
A modifier on consumable.amount changes what a consumable restores. Add action to a condition to target one action:
{
"hook": "consumable.amount", "op": "add", "value": 2,
"when": { "kind": "potion", "action": "restoreMana" }
}
Advanced: found objects and reagent use
An object with no recipe goes in objects of items.json. A loot table in loot.json points to it with "type": "object". Its kind must not be equippable.
{
"id": "mod-smoke-vial", "kind": "active",
"name": "ACTIVE_SMOKE_VIAL_NAME", "icon": "!",
"description": "ACTIVE_SMOKE_VIAL_DESCRIPTION", "power": 0,
"use": { "scope": "direction", "range": 5,
"effects": [{ "action": "field",
"params": { "field": "smoke", "radius": 1, "turns": 6 } }] }
}
Throwing it fills a radius of 1 with smoke for 6 turns. A reagent in resources.json can also declare a use with "scope": "item", to act on another item; write its effects explicitly.
Equipment glyphs#
Each piece of equipment is drawn with one character. glyphs in equipment.json sets it by kind, by base item, or by empty slot. A base glyph wins over its kind's.
{
"kinds": { "weapon": "/", "armor": "[", "shield": "]", "helmet": "^", "boots": "⌟", "gloves": "(", "ring": "=", "amulet": "\"" },
"bases": { "pilgrims-staff": "|", "crossbow": "}" },
"slots": { "ring-left": "○", "ring-right": "○", "neck": "⌐" }
}
Crossbows show as } and pilgrim's staves as |. Other weapons show as /. Empty ring and neck slots show their own signs.
- Every kind that a slot accepts needs a glyph. Referenced bases and slots must exist.
- A glyph is one visible character: no spaces, combining marks, invisible characters or emoji.
Next#
- How it works
Modifiers, listeners and conditions in depth.
- Troubleshooting
What the error messages mean.
- Catalogue
Every hook, event, condition and action.