Mudlib documentation

Help Library

Browse the live Insomnia help files directly from the mudlib — races, classes, commands, lore and creator notes, cleaned up for comfortable reading on the web.

Creator help topic

Crafting Creator

Crafting creator notes This document is for builders and coders who want to extend the player crafting system in their own areas. Core files

Creator 9 KB Updated 30 Jun 2026
Crafting creator notes

This document is for builders and coders who want to extend the player
crafting system in their own areas.

Core files

  /daemon/crafting.c
    Player state and actions: learned recipes, craft skill repair, material
    counts, gathering, processing, crafting, quality, and resource cooldowns.

  /daemon/crafting_recipes.c
    The central recipe registry.  Add normal player recipes here.

  /std/crafting/material.c
    Base object for crafting materials.

  /std/crafting/recipe_book.c
    Base object for recipe books and plans.

  /std/crafted_weapon.c
  /std/crafted_armour.c
  /std/crafted_component.c
  /std/crafted_tool.c
    Output bases used by recipes.

  /cmds/creator/_craftaudit.c
    Creator-side economy and recipe sanity audit.

Material objects

Materials should inherit /std/crafting/material and call set_craft_material:

  inherit "/std/crafting/material";

  void create() {
    ::create();
    set_name("rough stone");
    set_id(({ "stone", "rough stone", "crafting material" }));
    set_short("a chunk of rough stone");
    set_long("A dense chunk of workable stone.");
    set_craft_material("rough_stone", "stone", 1);
    set_mass(16);
    set_value(18);
  }

The id is what recipes consume.  The group is descriptive and useful for
future tooling.  Grade is normally 1; higher grades add a bounded quality
bonus when the finished item is crafted.

Gatherable room resources

At the lowest level, rooms expose gatherable materials with the craft resource
property:

  set_property("craft resource", ([
    "id": "rough_wood",
    "name": "rough wood",
    "file": OBJ+"material_rough_wood",
    "difficulty": 8
  ]));

Players use gather, or local verbs such as mine/harvest if an inheritable room
forwards to /daemon/crafting->gather_resource().  The daemon applies both a
room cooldown and a player/room/material cooldown after success.  Difficulty is
checked against the player's Craft skill.

Mine rooms

Mine-style resource rooms should normally inherit MINE rather than copying
local mine command code:

  inherit MINE;

  void create() {
    ::create();
    set_mine_resource(([
      "id": "iron_ore",
      "name": "iron ore",
      "file": OBJ+"material_iron_ore",
      "difficulty": 10
    ]));
    set_mine_default_target("ore");
    set_mine_legacy_ore_file(OBJ+"ore");
  }

/std/mine inherits VAULT, so it has the normal room/vault capabilities.  It
adds the mine verb, sends simple mine <material> commands through the crafting
daemon, and preserves the older mine <ore> with <tool> behaviour when
set_mine_legacy_ore_file() is configured.  Use set_mine_legacy_targets() if
the old tool-mining path should accept names other than ore and iron ore.

Harvest rooms

Plant, wood, fibre, cotton, herb, reed, moss, fruit, and similar resources
should normally inherit HARVEST rather than MINE:

  inherit HARVEST;

  void create() {
    ::create();
    set_harvest_resource(([
      "id": "plant_fibre",
      "name": "plant fibre",
      "file": OBJ+"material_plant_fibre",
      "difficulty": 16
    ]));
    set_harvest_default_target("fibre");
    set_harvest_aliases(({ "fibre", "vines", "vine" }));
  }

/std/harvest inherits VAULT and adds gather, harvest, pick, collect, strip,
cut, and chop as local resource verbs.  It still uses the same crafting daemon
resource/cooldown code as MINE.  Use MINE for rock faces, seams, quarry walls,
ore, rough stone, crystals, gems, salt, coal, clay, and similar extractive
resources.  Use HARVEST for resources that are picked, cut, stripped, or
salvaged from plants and woodland.

Processing experts

NPCs can process one material into another by exposing query_crafting_processes:

  mapping query_crafting_processes() {
    return ([
      "seasoned_wood": ([
        "input_name": "seasoned wood",
        "output_name": "arrow shafts",
        "output": OBJ+"material_arrow_shafts",
        "fee": 20
      ])
    ]);
  }

The player command is process <material>.  The crafting daemon looks for an
NPC in the player's current room with query_crafting_processes(), checks the
player has the input material and fee, destroys one input, creates the output,
and awards a little Craft skill practice.

Craft stations

Recipes may require a station.  Put this on the room:

  set_property("craft station", "forge");

or, for multiple stations:

  set_property("craft station", ({ "forge", "lapidary bench" }));

Common current station names include forge, tailor bench, carpenter bench,
fletcher bench, and lapidary bench.

Recipes

Add recipes to the mapping in /daemon/crafting_recipes.c.  Recipe ids are
lowercase underscore keys.  Player input is normalised, so "iron spear" and
"iron_spear" both resolve to iron_spear.

Example weapon:

  "iron_spear": ([
    "id": "iron_spear",
    "name": "iron spear",
    "category": "weapon",
    "tier": 1,
    "skill": 5,
    "station": "forge",
    "materials": ([ "steel_ingot": 1 ]),
    "output": "/std/crafted_weapon",
    "weapon_type": "blade",
    "base_name": "iron spear",
    "ids": ({ "spear", "iron spear", "crafted spear" }),
    "wc_min": 5,
    "wc_max": 9,
    "ac": 1,
    "mass": 18,
    "value": 220,
    "description": "A practical iron spear with a narrow forged head."
  ])

Armour uses category "armour", output /std/crafted_armour, armour_type,
ac_min, and ac_max.

Tools use category "tool" and output /std/crafted_tool.  Components use
category "component" and output /std/crafted_component.

Crafted ammunition

Crafted bows and crossbows can require crafted ammunition:

  "ammo_type_required": "arrow"

on a /std/crafted_weapon recipe.  Ammunition components use:

  "ammo_type": "arrow",
  "ammo_count": 12

on a /std/crafted_component recipe.  Combat checks require_ammunition() on
the weapon before the hit roll and consumes one matching ammunition unit.

Player-named crafted items

Players may use:

  craft <recipe> named <custom name>

or:

  craft <recipe> called <custom name>

The custom name is cosmetic and is handled by /daemon/crafting.c before the
materials are consumed.  It must be short, printable, globally unique, and
must include the base noun from the recipe's base_name/name.  Thus a recipe
with base_name "iron spear" may become "the witchbane spear", but not just
"the witchbane".  The finished object receives custom_name,
custom_name_key, base_crafted_name, and material_summary in its crafted data.
The /std/crafted_* bases use that to set the short/id strings while keeping
the long description anchored to the original recipe, maker, quality, and
materials.  Builders should therefore keep recipe base_name values clear and
noun-final.

Recipe books

Players must learn a recipe before using it.  Normal recipe books inherit
/std/crafting/recipe_book:

  inherit "/std/crafting/recipe_book";

  void create() {
    ::create();
    set_recipe("stone_chisel", "stone chisel",
      "a lapidary's stone chisel plan",
      "A practical plan for making a stone chisel.",
      ({ "recipe", "book", "plan", "chisel", "crafting recipe" }),
      130);
  }

Stock recipe books in an existing vendor storage room or a specialist shop.
Recipe books should have vendor type "crafting recipe"; the base does this.

Vendor rules and economy

Finished crafted items deliberately use vendor type "crafted".  Ordinary
shops should not include "crafted" in set_item_types(), otherwise a
gather/process/craft loop can become an NPC gold-printing route.

Use a specialist broker if an area needs NPC trade in crafted goods:

  set_item_types(({ "crafted", "crafting recipe" }));

The Artisans' Exchange in Lucidity is the current example.

Auditing

Run:

  craftaudit

after adding or changing recipes.  It instantiates recipe outputs, checks
material recurring cost against maximum value, and reports ordinary NPC resale
exposure.  A normal crafted item should show vendor:crafted and npc:0.

Loading checklist

  1. update material/output base files if changed.
  2. update /daemon/crafting_recipes.
  3. update recipe book files.
  4. update storage rooms/vendors/NPC processors/rooms.
  5. reset affected rooms.
  6. run craftaudit.
  7. test gather, process, study, craft, and any combat behaviour.
  8. check /log/runtime and /log/catch.

Use adjacent openclaw/ backup directories when changing existing mudlib files.