Crafting System Architecture Analysis - elanthia-online/dr-scripts GitHub Wiki

DragonRealms Lich Crafting System Architecture Analysis

Version: 1.3 Date: December 2025 Target Audience: Script Contributors Last Updated: Added spin.lic (fiber spinning utility)


Table of Contents

  1. Executive Summary
  2. Terminology Reference
  3. System Architecture Overview
  4. Data Layer
  5. Script Layer
  6. Common Library (DRCC)
  7. Workflow Analysis
  8. Known Issues and Pain Points
  9. Improvement Opportunities
  10. Feature Gap Analysis
  11. Refactoring Recommendations

Executive Summary

The Lich crafting system is a comprehensive automation framework for DragonRealms crafting disciplines. It consists of:

  • 3 Core Data Files: base-crafting.yaml, base-recipes.yaml, base-ingredients.yaml
  • 15 Scripts: Discipline-specific automation scripts (.lic files)
  • 1 Orchestrator: workorders.lic - coordinates work order completion
  • 1 Training Script: craft.lic - skill training automation
  • 1 Common Library: common-crafting.rb (DRCC module)
  • 1 User Profile: base.yaml - user configuration

Key Strengths

  • Modular discipline-specific scripts
  • Centralized data-driven recipe management
  • Comprehensive work order automation
  • Flexible tool belt support
  • Skill training automation with tier-based item selection

Key Weaknesses

  • Inconsistent error handling across scripts
  • Complex material management with edge cases
  • Adjustable tongs logic is fragile
  • Limited observability and debugging support
  • Inconsistent terminology between scripts and official DR names

Terminology Reference

This section maps official DragonRealms terminology to script/data file usage. Reference: Elanthipedia Crafting

Official Hierarchy

DragonRealms crafting is organized into 5 Skills, each containing Sub-disciplines:

Skill Sub-disciplines Status
Forging Blacksmithing, Armorsmithing, Weaponsmithing Implemented
Engineering Shaping, Carving, Tinkering Implemented
Outfitting Tailoring, Spinning, Jewelry Making, Artistry Partial (Tailoring, Spinning)
Alchemy Remedies, Reactants, Cooking Partial (Remedies only)
Enchanting Artificing, Binding, Invoking Partial (Artificing only)

Terminology Mapping Table

Official Term Script Arg Data File Key Script File Notes
Forging (skill) forging forging_tools - Parent skill
Blacksmithing blacksmithing blacksmithing forge.lic Tools, containers
Armorsmithing armorsmithing blacksmithing forge.lic Shares data with Blacksmithing
Weaponsmithing weaponsmithing blacksmithing forge.lic Shares data with Blacksmithing
Engineering (skill) engineering engineering_tools - Parent skill
Shaping shaping shaping shape.lic Wood items, bows
Carving carving shaping carve.lic Uses shaping data
Tinkering - shaping tinker.lic Uses shaping data
Outfitting (skill) outfitting outfitting_tools - Parent skill
Tailoring tailoring tailoring sew.lic Cloth, leather, knitting
Spinning - - spin.lic Fiber → thread/yarn (utility)
Alchemy (skill) alchemy alchemy_tools - Parent skill
Remedies remedies remedies remedy.lic Potions, salves
Enchanting (skill) enchanting enchanting_tools - Parent skill
Artificing artificing artificing enchant.lic Founts, foci, runestones

Script-Specific Terminology

Script Uses Term Should Be Context
workorders.lic blacksmithing Blacksmithing Correct
workorders.lic weaponsmithing Weaponsmithing Correct
workorders.lic tailoring Tailoring Correct
workorders.lic shaping Shaping Correct
workorders.lic carving Carving Correct
workorders.lic remedies Remedies Correct
workorders.lic artificing Artificing Correct
craft.lic forging Forging (skill) Training the skill
craft.lic outfitting Outfitting (skill) Training the skill
craft.lic engineering Engineering (skill) Training the skill
craft.lic alchemy Alchemy (skill) Training the skill
craft.lic enchanting Enchanting (skill) Training the skill
smith.lic type param Blacksmithing type armorsmithing/weaponsmithing/blacksmithing
forge.lic book_type - Uses blacksmithing, armorsmithing, weaponsmithing
enchant.lic book_type - Uses artificing
sew.lic book_type - Uses outfitting

Book Type Mapping

Book Type Official Sub-discipline Skill
blacksmithing Blacksmithing Forging
armorsmithing Armorsmithing Forging
weaponsmithing Weaponsmithing Forging
shaping Shaping Engineering
carving Carving Engineering
tinkering Tinkering Engineering
outfitting Tailoring Outfitting
remedies Remedies Alchemy
artificing Artificing Enchanting

System Architecture Overview

                         User Invocation
                               |
          +--------------------+--------------------+
          |                                         |
+---------v---------+                    +----------v----------+
|  workorders.lic   |                    |     craft.lic       |
|  (Work Orders)    |                    |  (Skill Training)   |
+---------+---------+                    +----------+----------+
          |                                         |
          +--------------------+--------------------+
                               |
    +---------------+-----------+-----------+---------------+
    |               |           |           |               |
+---v---+       +---v---+   +---v---+   +---v---+       +---v---+
|Forging|       |Outfit.|   | Engin.|   |Alchemy|       |Enchant|
+-------+       +-------+   +-------+   +-------+       +-------+
|forge  |       |sew    |   |shape  |   |remedy |       |enchant|
|smith  |       |spin   |   |carve  |   |alchemy|       |       |
|smelt  |       |       |   |tinker |   |       |       |       |
+---+---+       +---+---+   +---+---+   +---+---+       +---+---+
    |               |           |           |               |
    +---------------+-----------+-----------+---------------+
                                |
                    +-----------v-----------+
                    |   common-crafting.rb  |
                    |      (DRCC Module)    |
                    +-----------+-----------+
                                |
                    +-----------v-----------+
                    |   Data Files (YAML)   |
                    | base-crafting.yaml    |
                    | base-recipes.yaml     |
                    | base-ingredients.yaml |
                    +-----------------------+

Script Hierarchy

Level Component Purpose
0 craft.lic Skill training automation (calls other scripts)
1 workorders.lic Work order orchestration, NPC interaction, logistics
2 smith.lic Mid-level wrapper for Forging with enhancements
3 forge.lic, sew.lic, shape.lic, carve.lic, tinker.lic, remedy.lic, enchant.lic Low-level craft execution engines
4 smelt.lic, alchemy.lic, spin.lic Utility scripts (metal combining, ingredient prep, fiber spinning)
Lib common-crafting.rb Shared functions (DRCC module)

Script by Discipline

Discipline Primary Script Skill Notes
Blacksmithing forge.lic Forging General metal items
Weaponsmithing forge.lic Forging Weapons from metal
Armorsmithing forge.lic Forging Armor from metal
Tailoring sew.lic Outfitting Cloth/leather/knitting
Spinning spin.lic Outfitting Fiber → thread/yarn
Shaping shape.lic Engineering Wood items, bows
Carving carve.lic Engineering Stone/bone items
Tinkering tinker.lic Engineering Crossbows, mechanisms
Remedies remedy.lic Alchemy Potions, salves
Artificing enchant.lic Enchanting Magical items

Data Layer

base-crafting.yaml

Location: scripts/data/base-crafting.yaml

Purpose: Contains town-specific crafting infrastructure data.

Key Sections:

blacksmithing:
  <hometown>:
    stock-room: <room_id>       # Where to buy ingots
    stock-number: <order_num>   # Order number for ingots
    stock-volume: <int>         # Volume per stock purchase
    anvils: [room_ids]          # Available anvil rooms
    crucibles: [room_ids]       # Available crucible rooms
    grindstones: [room_ids]     # Available grindstone rooms
    npc-rooms: [room_ids]       # Work order NPC locations
    npc: <name>                 # NPC first name
    npc_last_name: <name>       # NPC last name for finding
    repair-room: <room_id>      # Tool repair NPC room
    repair-npc: <name>          # Repair NPC name
    finisher-room: <room_id>    # Consumables (oil) room
    finisher-number: <order_num> # Oil order number
    logbook: <type>             # Logbook type (forging/outfitting/etc)

Disciplines Covered:

  • blacksmithing (also used for weaponsmithing/armorsmithing)
  • tailoring
  • shaping
  • remedies
  • artificing
  • stock (material definitions)
  • recipe_parts (component locations)
  • deeds (deed packet locations)

Issues Identified:

  1. Some hometowns have incomplete data
  2. Room IDs may become stale with game updates
  3. No validation layer for data integrity

base-recipes.yaml

Location: scripts/data/base-recipes.yaml

Purpose: Complete recipe catalog with metadata.

Recipe Structure:

- name: "a metal longsword"    # Full recipe name (must match exactly)
  noun: longsword              # Item noun for commands
  volume: 7                    # Material volume required
  type: weaponsmithing         # Discipline type
  work_order: true             # Can be used for work orders
  chapter: 2                   # Recipe book chapter
  part:                        # Required assembly parts
  - hilt

Extended Fields (Alchemy/Enchanting):

# Alchemy recipes
- name: "blister cream"
  herb1: "red flower"
  herb1_stock: 1              # Stock number (null = forage)
  herb2: "nemoih"
  herb2_stock: null
  catalyst: bar
  container: mortar
  noun: cream

# Enchanting recipes
- enchant_stock1_name: "abolition"
  enchant_stock1: 6
  item: 17                    # Base item order number

Statistics (Approximate):

  • 500+ recipes total
  • Covers: blacksmithing, armorsmithing, weaponsmithing, tailoring, shaping, carving, remedies, artificing

base-ingredients.yaml

Location: scripts/data/base-ingredients.yaml

Purpose: Foraging and ingredient processing data.

Structure:

ingredients:
  - name: "red flower"
    output: "dried flower"     # Result after processing
    ranks: 50                  # Outdoorsmanship skill required
    Crossing: 123              # Room ID per hometown
    Riverhaven: 456
    stackable: true

base.yaml (Profile)

Location: scripts/profiles/base.yaml

Purpose: User configuration template.

Key Settings:

hometown: Crossing
crafting_container: backpack
crafting_items_in_container: [tool1, tool2]

# Discipline-specific
forging_belt:
  name: "forging belt"
  items: [tongs, hammer, bellows]
forging_tools: [tongs, hammer, bellows, shovel]
adjustable_tongs: true

# Work order settings
workorder_diff: challenging
workorder_min_items: 1
workorder_max_items: 6
craft_max_mindstate: 32

# Material preferences
workorders_materials:
  metal_type: bronze
  fabric_type: burlap
  wood_type: balsa

Script Layer

workorders.lic (Orchestrator)

Purpose: End-to-end work order automation.

Responsibilities:

  1. Request work orders from NPCs
  2. Validate recipe availability
  3. Calculate material requirements
  4. Dispatch to appropriate craft script
  5. Bundle completed items
  6. Turn in work order

Workflow:

request_work_order() -> find_recipe() -> [discipline]_items() -> bundle_item() -> complete_work_order()

Discipline Method Mapping:

Discipline Method Called Script
blacksmithing/weaponsmithing forge_items[_with_own_ingot] smith.lic -> forge.lic
tailoring (ch 2-4) sew_items sew.lic
tailoring (ch 5) knit_items sew.lic
shaping shape_items shape.lic
carving carve_items carve.lic
remedies remedy_items remedy.lic
artificing enchanting_items enchant.lic

forge.lic (Forging Engine)

Purpose: Core forging state machine.

Modes:

  1. Standard forging (from recipe book)
  2. Instructions-based forging
  3. Enhancements (temper, hone, balance, lighten, reinforce)
  4. Resume interrupted work

State Machine Pattern:

def work(settings)
  loop do
    result = DRC.bput(@command, *PATTERNS)
    case result
    when 'pattern1' then swap_tool('tool1'); @command = 'new_command'
    when 'pattern2' then assemble_part
    when 'Roundtime' then finish if Flags['work-done']
    end
  end
end

Flag System:

  • forge-assembly: Triggers part assembly
  • work-done: Signals craft completion
  • ingot-restow: Handles leftover ingot material

Tool Flow:

anvil work: hammer + tongs
grindstone: wire brush
slack tub: empty hands
oil finishing: oil bottle

smith.lic (Forging Wrapper)

Purpose: Higher-level forging with enhancements.

Responsibilities:

  1. Look up recipe in base-recipes.yaml
  2. Ensure copper on hand
  3. Buy required parts
  4. Buy ingot (if buy flag)
  5. Find anvil
  6. Call forge.lic
  7. Apply enhancements (temper/hone/balance/lighten/reinforce)
  8. Dispose of scrap

Enhancement Flow:

[temper, hone, balance, lighten, reinforce].compact.each do |enhancement|
  DRC.wait_for_script_to_complete('forge', [enhancement, recipe['noun']])
end

sew.lic (Tailoring Engine)

Purpose: Sewing, knitting, and leather work.

Modes:

  1. Standard sewing (cloth/leather)
  2. Knitting (yarn)
  3. Enhancements (seal, reinforce, lighten)
  4. Resume interrupted work

Material Detection:

@cloth = %w[silk wool burlap cotton felt linen electroweave steelsilk ...]
if @cloth.include?(@mat_type)
  # cloth workflow
else
  # leather workflow
end

Tool Flow:

cutting: scissors
sewing: sewing needles + thread
pinning: pins
smoothing: slickstone
measuring: yardstick
hole punching: awl
sealing: sealing wax
knitting: knitting needles + yarn

remedy.lic (Alchemy Engine)

Purpose: Remedy/potion creation.

Flag System:

  • remedy-water: Add water
  • remedy-alcohol: Add alcohol
  • remedy-catalyst: Add catalyst
  • remedy-herb: Add second herb
  • remedy-turn: Turn container
  • remedy-smell: Smell mixture
  • remedy-sieve: Sieve mixture

Container Handling:

@container = mortar (external) or bowl/cauldron (internal)
@pestle = pestle (external) or mixing stick (internal)
@verb = crush (external) or mix (internal)

Special Container Support:

# Water/alcohol containers that generate contents
if @settings.water_container
  fput("rub my #{@settings.water_container}")  # Generate water
end

shape.lic (Woodworking Engine)

Purpose: Lumber shaping and bow crafting.

Modes:

  1. Standard shaping (from lumber)
  2. Arrow fletching (from shafts)
  3. Bow enhancements (laminate, lighten, cable)
  4. Resume interrupted work

Tool Flow:

initial: drawknife
shaping: shaper
carving: carving knife
smoothing: rasp
clamping: clamps
gluing: glue
staining: stain

carve.lic (Carving Engine)

Purpose: Stone and bone carving for Engineering discipline.

Modes:

  1. Standard carving (from stone/bone)
  2. Resume interrupted work

Material Types:

Type Arg Material Main Tool Notes
stack Bone Saw Stackable bone material
bone Bone Saw Alias for stack
rock Stone Chisel Small stone
stone Stone Chisel Medium stone
pebble Stone Chisel Tiny stone
boulder Stone Chisel Large stone (can't pick up)
deed Stone Chisel Deed-based stone on sled

Tool Selection Logic:

@main_tool = if @type == 'stack' || @type == 'bone'
               @settings.carving_tools.find { |item| /\bsaw/i =~ item }
             else
               @settings.carving_tools.find { |item| /\bchisel/i =~ item }
             end

Tool Flow:

cutting: saw (bone) or chisel (stone)
smoothing: rifflers, rasp
polishing: polish

Flag System:

  • carve-assembly: Triggers part assembly (hilt, haft, pole, cord)

Ownership Handling:

# Tracks whether item needs "my" prefix
@my = 'my '   # If we picked it up
@my = ''      # If it's too heavy (boulder) or on sled

Resume Flow:

def resume
  case DRC.bput("analyze my #{@noun}", ...)
  when /prevent|obstruct carving/ then cut
  when /riffler set/ then rub with rifflers
  when /rasp/ then rub with rasp
  when /polish/ then apply polish
  when /finished/ then exit
  end
end

tinker.lic (Tinkering Engine)

Purpose: Crossbow crafting and mechanism creation for Engineering discipline.

Modes:

  1. Standard tinkering (crossbows from lumber)
  2. Bolt fletching (from shafts)
  3. Crossbow enhancements (laminate, lighten, cable)
  4. Mechanism creation (from metal ingots)
  5. Resume interrupted work

Unique Feature - Mechanism Creation:

# Direct invocation for mechanism making
# ;tinker mechanisms bronze 3
def mechanisms(args)
  DRCC.find_shaping_room(@hometown)
  fput("turn press to 4")
  count.times do
    DRCC.get_crafting_item("#{args.material} ingot", ...)
    swap_tool("shovel")   # Fuel the press
    swap_tool("pliers")
    work('push my ingot with press')
    # Combine stacks if making multiple
    DRCC.stow_crafting_item('mechanisms', @bag, nil)
  end
end

Tool Flow:

initial: drawknife (lumber) or shaper (bolts)
shaping: shaper
carving: carving knife
smoothing: rasp
clamping: clamps
gluing: glue
staining: stain
adjusting: tinker tools
mechanism work: pliers + gear press
fuel: shovel (or adjustable tongs)

Flag System:

  • tinkering-assembly: Triggers part assembly (backer, string, pole, cord, strip, lenses, mechanism, boltheads, bolt flights)
  • tinker-done: Signals craft completion

Adjustable Tongs Support:

# Uses same pattern as forge.lic
if next_tool.include?('shovel') && @adjustable_tongs
  DRCC.get_adjust_tongs?('shovel', @bag, @bag_items, @belt, @adjustable_tongs)
end

Mechanism Assembly:

# Special handling for mechanisms vs other parts
if part.include?("mechanism")
  until /is not required/ =~ DRC.bput("assemble my mechanism with my #{@noun}", ...)
    pause 0.05
  end
else
  DRC.bput("assemble my #{@noun} with my #{part}", ...)
end

magic_cleanup Variation:

# Tinker has unique symbiosis handling
def magic_cleanup
  DRC.bput('prepare symbiosis', ...)  # Prepare then release
  DRC.bput('release symbiosis', ...)
  DRC.bput('release spell', ...)
  DRC.bput('release mana', ...)
end

enchant.lic (Enchanting Engine)

Purpose: Magical item creation.

Flag System:

  • enchant-focus: Focus on item
  • enchant-meditate: Meditate on fount
  • enchant-imbue: Cast imbue spell
  • enchant-push: Push with loop
  • enchant-sigil: Trace next sigil
  • enchant-complete: Finished
  • imbue-failed/backlash: Error states

Sigil Tracing:

def trace_sigil(sigil)
  DRCI.get_item?("#{sigil} sigil")
  DRC.bput("study my #{sigil} sigil", /commit the design to memory/)
  DRC.bput("trace #{@item} on #{@brazier}", /trace its form/)
end

Imbue Methods:

  1. Spell-based (from waggle_sets)
  2. Wand-based (imbue wand/rod)

alchemy.lic (Ingredient Preparation Utility)

Purpose: Forage and prepare ingredients for Remedies crafting.

Note: This is a utility script, not a crafting engine. It prepares materials for remedy.lic.

Modes:

  • forage: Gather herbs from the world
  • prepare: Process herbs (dry/crush) at press/grinder

Invocation:

;alchemy <ingredient> forage [quantity]   # Forage ingredient
;alchemy <ingredient> prepare             # Process ingredient
;alchemy <ingredient> forage prepare 25   # Forage 25 then process

Data Source: Uses base-ingredients.yaml for:

  • Ingredient locations per hometown
  • Output product names (e.g., "red flower" → "dried flower")
  • Required Outdoorsmanship ranks
  • Stackability information

Key Settings:

alchemy_herb_quantity: 25        # Default forage quantity
alchemy_herb_storage: haversack  # Where to store raw herbs
herb_container: mortar           # Where processed herbs go
alchemy_prep_quantity: 75        # Max stack size after prep
alchemy_forage_type: careful     # Forage type (careful/precise)
forage_override_room: null       # Override forage location
forage_override_town: null       # Override processing town

Workflow:

def forage_ingredient(ingredient)
  DRCT.walk_to(@forage_location)         # Go to forage room
  while quantity_needed >= 0
    DRC.bput("forage #{ingredient['name']} #{@alchemy_forage_type}")
    DRCI.put_away_item?(ingredient['name'], @alchemy_herb_storage)
    quantity_needed -= 6                  # Forage yields 6 units
  end
end

def prepare_ingredient(ingredient)
  DRCC.find_press_grinder_room(@press_location)
  while count(ingredient['name'], @alchemy_herb_storage) > 0
    if ingredient['output'].include?("dried")
      fput("put my #{ingredient['name']} in press")   # Drying
    else
      fput("put my #{ingredient['name']} in grinder") # Crushing
    end
    # Combine stacks up to 75
  end
end

Count Helper:

# Counts stacked items using ordinals (first, second, etc.)
def count(item, container)
  $ORDINALS.each do |ordinal|
    # "count my first dried flower in my haversack"
    # Stops when "I could not find" is returned
  end
end

craft.lic (Skill Training Automation)

Purpose: Automated skill training through crafting disposable items.

Skill Coverage:

  • Forging (via smith.lic)
  • Outfitting (via sew.lic - knitting and sewing)
  • Engineering (via shape.lic)
  • Alchemy (via remedy.lic + alchemy.lic)
  • Enchanting (via enchant.lic)

Invocation:

;craft forging      # Train Forging skill
;craft outfitting   # Train Outfitting skill
;craft engineering  # Train Engineering skill
;craft alchemy      # Train Alchemy skill
;craft enchanting   # Train Enchanting skill

Tier-Based Item Selection:

The script selects items based on current skill rank to maximize learning:

Skill Tier 1 (0-25) Tier 6 (300-425) Tier 12 (1400+)
Forging shallow metal cup metal armband wire sieve
Outfitting knitted socks knitted cloak artisan's belt
Engineering wood band wood armband ornate burin
Alchemy blister cream chest unguent vigor poultices
Enchanting radiant trinket strange arrow runestone electric focus

Tier Thresholds:

# Rank-based tier selection (12 tiers)
Tier 1:  0-25      # Extremely Easy
Tier 2:  26-50     # Very Easy
Tier 3:  51-100    # Easy
Tier 4:  101-175   # Simple
Tier 5:  176-300   # Basic
Tier 6:  301-425   # Somewhat Challenging
Tier 7:  426-550   # Challenging
Tier 8:  551-700   # Complicated
Tier 9:  701-850   # Intricate
Tier 10: 851-1175  # Difficult
Tier 11: 1176-1400 # Very Difficult
Tier 12: 1401+     # Extremely Difficult

Key Settings:

craft_max_mindstate: 32          # Max XP before exiting
craft_overrides:                 # Override tier item selection
  Forging:
    item: "custom item name"
  Outfitting:
    type: sew                    # or knit
    chapter: 3
    item: "item name"
    volumes: 10                  # fabric volume needed
yarn_quantity: 100               # Minimum yarn before restock
worn_trashcan: "bucket"          # Where to dispose items
worn_trashcan_verb: "put"        # Disposal verb

Training Methods:

Skill Method Sub-script Called
Forging train_forging() smith.lic with buy flag
Outfitting train_outfitting() sew.lic (knit or sew mode)
Engineering train_engineering() shape.lic with trash flag
Alchemy train_alchemy() alchemy.lic + remedy.lic
Enchanting train_enchanting() enchant.lic

Material Handling:

def check_yarn
  buy_yarn if count < @yarn_quantity
end

def check_fabric(fabric_volumes)
  existing = count_fabric_in_bag
  stock_needed = ((fabric_volumes - existing) / 10.0).ceil
  order_fabric(stock_room, stock_needed, ...)
end

def check_wood
  buy_wood if count < 5
end

Classroom Integration:

# Teaching support
def check_teaching
  @settings.classes_to_teach.each { |class| teach_to_pcs }
end

# Learning support
def check_listening
  DRC.listen?(@last_teacher, @settings.listen_observe)
  DRC.assess_teach  # Find classes to join
end

Disposal:

# All crafted items are disposed after completion
DRCI.dispose_trash(item_noun, @worn_trashcan, @worn_trashcan_verb)

smelt.lic (Metal Combining Utility)

Purpose: Combine ingots in crucible.

State Machine:

case result
when 'clumps of molten metal' then turn crucible
when 'flickers' then push bellows
when 'needs more fuel' then push fuel with shovel/tongs
end

spin.lic (Fiber Spinning Utility)

Purpose: Spin raw fibers into thread/yarn for Tailoring.

Note: This is a material preparation utility for Outfitting, similar to how alchemy.lic prepares ingredients for Remedies.

Invocation:

;spin <material> [weight]
# Examples:
;spin silk heavy      # Spin silk fibers into heavy thread
;spin wool yarn       # Spin wool fibers into yarn
;spin cotton          # Defaults to heavy weight

Supported Materials:

Material Stock Index Cost Count Notes
silk 1 187 14 Requires cutting at 10 yards
cotton 2 185 8 Standard processing
linen 3 167 8 Standard processing
wool 4 133 8 Standard processing
burlap 5 201 4 Standard processing

Weight Options:

  • fine - Finest thread
  • thin - Thin thread
  • average - Medium weight
  • thick - Thick thread
  • heavy - Heavy thread (default)
  • yarn - Yarn weight

Workflow:

def initialize
  # 1. Calculate cost and buy fibers
  DRCM.ensure_copper_on_hand(data[:cost] * data[:count], @settings, @hometown)

  # 2. Order and combine fibers
  data[:count].times do |index|
    DRCT.order_item(stock_room, data[:index])
    if index == 0 && data[:name] == 'silk'
      # Silk requires special handling - cut at 10 yards
      DRC.bput('mark my fibers at 10', /mark it for cutting/)
      # Cut with scissors, drop excess
    else
      fput('combine my fiber')
    end
  end

  # 3. Find spinning wheel
  until DRCC.find_wheel(@hometown)
    move('go door')
    pause 30
  end

  # 4. Spin the fiber
  fput('put fiber on wheel')
  fput("adjust wheel to #{args.weight || 'heavy'}")

  # 5. State machine loop
  until DRC.left_hand || DRC.right_hand
    case DRC.bput('spin wheel', ...)
    when 'shade'    then fput('clean wheel')
    when 'twist'    then fput('turn wheel')
    when 'bunch'    then fput('push wheel')
    when 'slide'    then fput('push wheel')
    end
  end

  # 6. Stow result
  fput("stow my #{DRC.right_hand || DRC.left_hand}")
end

State Machine:

Game Output Action Purpose
shade clean wheel Remove debris
twist turn wheel Adjust tension
Individual strands...twisting turn wheel Adjust tension
bunch push wheel Even out fiber
slide push wheel Even out fiber
(other/roundtime) wait Continue spinning

Dependencies:

  • Uses DRCC.find_wheel() from common-crafting.rb
  • Reads tailoring stock room from base-crafting.yaml
  • Uses outfitting_belt for scissors

Common Library (DRCC)

Location: lib/dragonrealms/commons/common-crafting.rb Module: Lich::DragonRealms::DRCC

Key Functions

Room Finding

DRCC.find_anvil(hometown)       # Find empty anvil room
DRCC.find_empty_crucible(hometown)
DRCC.find_grindstone(hometown)
DRCC.find_sewing_room(hometown, override)
DRCC.find_shaping_room(hometown, override)
DRCC.find_enchanting_room(hometown, override)
DRCC.find_wheel(hometown)       # Spinning wheel
DRCC.find_press_grinder_room(hometown)

Tool Management

DRCC.get_crafting_item(name, bag, bag_items, belt, skip_exit = false)
DRCC.stow_crafting_item(name, bag, belt)
DRCC.get_adjust_tongs?(usage, bag, bag_items, belt, adjustable_tongs = false)

Recipe Handling

DRCC.find_recipe(chapter, match_string, book = 'book')
DRCC.find_recipe2(chapter, match_string, book = 'book', discipline = nil)
DRCC.recipe_lookup(recipes, item_name)

Consumables

DRCC.check_consumables(name, room, number, bag, bag_items, belt, count = 3)
DRCC.repair_own_tools(info, tools, bag, bag_items, belt)

Utilities

DRCC.empty_crucible?
DRCC.clean_anvil?
DRCC.clean_brazier?
DRCC.logbook_item(logbook, noun, container)
DRCC.crafting_cost(recipe, hometown, parts, quantity, material)
DRCC.count_raw_metal(container, type = nil)

Workflow Analysis

Forging Work Order Flow

1. workorders.lic: request_work_order()
   - Walk to NPC rooms
   - Ask for work order
   - Filter by recipe availability

2. workorders.lic: forge_items() / forge_items_with_own_ingot()
   - Calculate materials needed
   - Loop for each item:
     a. Order/get ingot
     b. Call smith.lic
     c. Bundle item to logbook

3. smith.lic:
   - Buy parts (hilt/haft)
   - Find anvil (DRCC.find_anvil)
   - Call forge.lic
   - Apply enhancements
   - Dispose scrap

4. forge.lic:
   - Study recipe
   - Main work loop:
     - Match game output
     - Swap tools as needed
     - Assemble parts
     - Manage fuel/temperature
     - Oil and finish

Material Volume Calculation

# workorders.lic
items_per_stock = materials_info['stock-volume'] / recipe['volume']
spare_stock = (materials_info['stock-volume'] % recipe['volume']).nonzero?
scrap = spare_stock || (quantity % items_per_stock).nonzero?

# Example: stock-volume = 10, recipe volume = 3
# items_per_stock = 3 (can make 3 items per stock)
# spare_stock = 1 (1 volume leftover per stock)

Known Issues and Pain Points

1. Error Handling

Current State: Inconsistent error handling across scripts.

Issues:

Location Problem Impact
forge.lic:416 Generic "ERROR TRYING TO CRAFT" exit No recovery, unclear cause
remedy.lic:394-400 magic_cleanup() assumes @training_spells exists Potential nil error
sew.lic:334-340 magic_cleanup() references @settings outside class Scope issue
enchant.lic:240-241 Imbue backlash sends to safe-room and exits No retry option
workorders.lic:852-854 500 iteration loop exits silently No indication of why
carve.lic:135-136 "You cannot figure out" triggers finish() May exit prematurely on actual errors
carve.lic:160-161 "ITEM NOT FOUND" exit without cleanup No stowing, no magic release
tinker.lic:239-241 "ERROR TRYING TO CRAFT" uses DRCI.stow_hands Different cleanup pattern than other scripts
tinker.lic:260-267 magic_cleanup() prepares then releases symbiosis Unique pattern, inconsistent with others

Pattern Problems:

# Common anti-pattern: Exit without cleanup
when 'I could not find what you were referring to'
  echo '*** ERROR TRYING TO CRAFT, EXITING ***'
  exit  # No stowing, no magic release, no state save

Recommendation: Create standardized error handling:

def craft_error(message, cleanup: true, exit_script: true)
  DRC.message("CRAFT ERROR: #{message}")
  if cleanup
    DRCC.stow_crafting_item(DRC.right_hand, @bag, @belt)
    DRCC.stow_crafting_item(DRC.left_hand, @bag, @belt)
    magic_cleanup
  end
  exit if exit_script
end

2. Material Management

Current State: Complex material counting with edge cases.

Issues:

Script Issue Code Location
workorders.lic Herb counting fails with players named "In*" :484-488
remedy.lic Herb stacking logic complex and fragile :193-227
workorders.lic count_combine_rem() has 75+ lines :461-538
forge.lic Ingot restow flag can miss edge cases :255-264

Herb Counting Bug (workorders.lic:484-488):

# Bug: "tap first flower in my haversack" matches "Inkin"
/You tap (.*) inside your|I could not find|You lightly tap/ =~
  DRC.bput("tap #{stack_descriptor} #{herb_for_tapping} in my #{@bag}", ...)
# "You lightly tap Inkin on the shoulder" triggers wrong branch

Material Volume Edge Cases:

  1. Bone carving stacks vs stone deeds
  2. Cloth/yarn combining when partially used
  3. Own ingot + deed management complexity

3. Tool Belt Logic

Current State: Adjustable tongs have complex state management.

Location: common-crafting.rb:366-425

Issues:

# State tracking via instance variable @tongs_status
# Problem 1: Not persistent across script restarts
# Problem 2: Can get out of sync with actual game state

case DRC.bput("adjust my tongs", ...)
when 'You lock the tongs'     # Now shovel
when 'With a yank you fold'   # Now tongs
when 'You cannot adjust'      # Not adjustable!
when 'You have no idea how'   # Not adjustable!

Race Condition:

# forge.lic uses @adjustable_tongs at script start
@adjustable_tongs = DRCC.get_adjust_tongs?('reset tongs', @bag, @bag_items, @forging_belt)
# But if script crashes, @tongs_status in DRCC may be wrong on restart

Tool Swap Inconsistency:

  • forge.lic:swap_tool() - custom implementation with adjustable tongs
  • shape.lic:swap_tool() - simpler implementation, no tongs logic
  • sew.lic:swap_tool() - checks if already holding tool
  • carve.lic - no swap_tool(), uses inline DRCC calls
  • tinker.lic:swap_tool() - includes tinkering_tools lookup + adjustable tongs

4. Flag Management

Current State: Flags cleaned up in before_dying blocks.

Issues:

# forge.lic
before_dying do
  Flags.delete('forge-assembly')
  Flags.delete('hone-done')      # 'hone-done' never created!
  Flags.delete('ingot-restow')
end

Orphan Flags: Some flags created but never deleted.

Flag Name Collision Risk: Similar names across scripts could interfere.


Improvement Opportunities

1. Centralized Error Handler

# Proposed: lib/dragonrealms/commons/common-crafting-errors.rb
module DRCC
  class CraftError < StandardError
    attr_reader :recoverable, :context

    def initialize(message, recoverable: false, context: {})
      @recoverable = recoverable
      @context = context
      super(message)
    end
  end

  def handle_craft_error(error, bag:, belt:)
    DRC.message("CRAFT: #{error.message}")
    cleanup_hands(bag, belt)
    raise unless error.recoverable
  end
end

2. Tool State Machine

# Proposed: Unified tool management
class CraftingToolManager
  def initialize(bag:, belt:, tools:)
    @bag = bag
    @belt = belt
    @tools = tools
    @current_tool = nil
  end

  def swap_to(tool_name, consumable: false)
    return if @current_tool == tool_name
    stow_current
    get_tool(tool_name, consumable: consumable)
    @current_tool = tool_name
  end

  def stow_current
    return unless @current_tool
    DRCC.stow_crafting_item(@current_tool, @bag, @belt)
    @current_tool = nil
  end
end

3. Material Calculator

# Proposed: Material planning before crafting
class MaterialCalculator
  def calculate_needs(recipe, quantity, inventory)
    {
      stock_needed: calculate_stock(recipe, quantity, inventory[:stock]),
      parts_needed: calculate_parts(recipe, quantity, inventory[:parts]),
      consumables_needed: calculate_consumables(quantity, inventory[:consumables]),
      total_cost: calculate_cost(...)
    }
  end
end

4. Debug Mode Enhancement

# Current: @debug = args.debug || settings.debug_mode
# Proposed: Structured logging
module DRCC
  def debug_log(category, message, data = {})
    return unless @debug
    timestamp = Time.now.strftime('%H:%M:%S')
    echo "[#{timestamp}][#{category}] #{message} #{data.inspect}"
  end
end

Feature Gap Analysis

Missing Features

Feature Benefit Complexity
Dry-run mode Preview materials needed without crafting Low
Progress persistence Resume after disconnect Medium
Multi-item batching Craft same item multiple times efficiently Low
Quality tracking Track item quality for work orders Medium
Skill requirements Warn if skill too low for recipe Low
Alternative recipes Fallback if primary unavailable Medium
Consumable forecasting Warn before running out Low

Missing Discipline Support

Discipline Current Support Gap
Weaving Minimal No weave.lic
Tanning None No tan.lic
Jewelry Making None No jewelry.lic (Outfitting sub-discipline)
Artistry None No artistry.lic (Outfitting sub-discipline)

Note: Spinning (spin.lic), Carving (carve.lic), and Tinkering (tinker.lic) are fully implemented.

Recipe Data Gaps

# Some recipes lack full metadata
- work_order: false  # Many recipes excluded from work orders
- material: nil      # Missing material type for some
- part: nil          # Missing part requirements

Refactoring Recommendations

Priority 1: Critical Fixes

  1. Fix Herb Counting Bug

    • Use explicit item matching, not player name collision
    • Add guard against "You lightly tap" responses
  2. Standardize Error Handling

    • Create CraftError exception class
    • Implement cleanup on all error paths
    • Add retry logic for recoverable errors
  3. Fix Orphan Flags

    • Audit all Flags.add() and Flags.delete() calls
    • Ensure matching pairs

Priority 2: Code Quality

  1. Unify Tool Swap Methods

    • Create single swap_tool() in DRCC
    • Remove duplicate implementations
  2. Extract Magic Cleanup

    • Move to DRCC module
    • Fix scope issues in sew.lic
  3. Document Data Schemas

    • Add YAML schema validation
    • Document required vs optional fields

Priority 3: Architecture

  1. Introduce State Machine Pattern

    • Formalize craft state transitions
    • Enable persistence for resume
  2. Create Material Tracker

    • Centralized inventory tracking
    • Pre-craft validation
  3. Add Observability

    • Structured logging
    • Craft statistics
    • Error telemetry

Priority 4: Features

  1. Dry-Run Mode
  2. Progress Persistence
  3. Quality Tracking
  4. Consumable Forecasting

Appendix A: File Quick Reference

File Type Primary Function
base-crafting.yaml Data Town infrastructure, stock info
base-recipes.yaml Data Recipe catalog
base-ingredients.yaml Data Foraging locations
base.yaml Config User settings template
craft.lic Training Skill training automation
workorders.lic Orchestrator Work order automation
smith.lic Wrapper Forging with enhancements
forge.lic Engine Core Forging logic (Blacksmithing/Weaponsmithing/Armorsmithing)
sew.lic Engine Tailoring (sewing/knitting/leather)
shape.lic Engine Shaping (lumber, bows)
carve.lic Engine Carving (stone/bone)
tinker.lic Engine Tinkering (crossbows, mechanisms)
remedy.lic Engine Remedies (potions, salves)
enchant.lic Engine Artificing (magic items)
spin.lic Utility Fiber spinning (thread/yarn production)
alchemy.lic Utility Ingredient prep (forage/process herbs)
smelt.lic Utility Metal combining in crucible
common-crafting.rb Library Shared functions (DRCC module)

Appendix B: Key Settings Reference

# Essential crafting settings
crafting_container: backpack
crafting_items_in_container: []
hometown: Crossing
force_crafting_town: null

# Tool belts (by skill)
forging_belt: { name: "forging belt", items: [tongs, hammer] }
outfitting_belt: null
engineering_belt: null
alchemy_belt: null
enchanting_belt: null

# Tools (by skill/discipline)
forging_tools: [tongs, hammer, bellows, shovel]
shaping_tools: [drawknife, shaper, carving knife, rasp, clamps]
carving_tools: [chisel, saw, rifflers, rasp, polish]
tinkering_tools: [drawknife, shaper, carving knife, rasp, clamps, pliers, tinker tools]
outfitting_tools: [scissors, sewing needles, pins, yardstick, slickstone]
alchemy_tools: [mortar, pestle, sieve]
enchanting_tools: [brazier, fount, burin, aug loop, imbue rod]

# Adjustable tools
adjustable_tongs: false

# Work orders (workorders.lic)
workorder_diff: challenging
workorder_min_items: 1
workorder_max_items: 6
craft_max_mindstate: 32

# Materials (workorders.lic)
workorders_materials:
  metal_type: bronze
  fabric_type: burlap
  wood_type: balsa
  stone_type:ite
  bone_type: animal
  knit_type: wool

# Skill training (craft.lic)
craft_max_mindstate: 32
craft_overrides:
  Forging: { item: "custom item" }
  Outfitting: { type: sew, chapter: 3, item: "item name", volumes: 10 }
  Engineering: { chapter: 7, item: "item name" }
yarn_quantity: 100
worn_trashcan: bucket
worn_trashcan_verb: put

# Ingredient preparation (alchemy.lic)
alchemy_herb_quantity: 25
alchemy_herb_storage: haversack
herb_container: mortar
alchemy_prep_quantity: 75
alchemy_forage_type: careful
forage_override_room: null
forage_override_town: null

Appendix C: Crafting Type Matrix

Sub-discipline Script Skill Logbook Stock Type
Blacksmithing forge.lic Forging forging ingot
Weaponsmithing forge.lic Forging forging ingot
Armorsmithing forge.lic Forging forging ingot
Tailoring (sew) sew.lic Outfitting outfitting cloth
Tailoring (knit) sew.lic Outfitting outfitting yarn
Tailoring (leather) sew.lic Outfitting outfitting leather
Spinning (material) spin.lic Outfitting N/A fibers
Shaping shape.lic Engineering engineering lumber
Carving (stone) carve.lic Engineering engineering deed/stone
Carving (bone) carve.lic Engineering engineering stack
Tinkering (crossbow) tinker.lic Engineering engineering lumber
Tinkering (bolts) tinker.lic Engineering engineering bolt shafts
Tinkering (mechanisms) tinker.lic Engineering N/A ingot
Remedies remedy.lic Alchemy alchemy herbs
Artificing enchant.lic Enchanting enchanting sigils + items

Appendix D: Script Invocation Quick Reference

Script Basic Usage Common Options
craft.lic ;craft <skill> forging, outfitting, engineering, alchemy, enchanting
workorders.lic ;workorders <discipline> blacksmithing, weaponsmithing, tailoring, shaping, carving, remedies, artificing
smith.lic ;smith <metal> <item> [buy] buy = purchase ingot
forge.lic ;forge <chapter> <item> <noun> Also: resume, temper, hone, balance, lighten, reinforce
sew.lic ;sew <mode> <chapter> <item> <material> <noun> mode: sewing, knitting, leather
shape.lic ;shape <mode> <chapter> <item> <wood> <noun> mode: trash, normal; Also: laminate, lighten, cable
carve.lic ;carve <chapter> <item> <material> <type> <noun> type: stack, rock, stone, boulder, deed
tinker.lic ;tinker <chapter> <item> <material> <noun> Also: mechanisms [count], resume, laminate, lighten, cable
remedy.lic ;remedy <discipline> <chapter> <item> <herb1> <herb2> <catalyst> <container> <noun> discipline: remedies
enchant.lic ;enchant <chapter> <item> <noun>
spin.lic ;spin <material> [weight] material: silk, cotton, linen, wool, burlap; weight: fine, thin, average, thick, heavy, yarn
alchemy.lic ;alchemy <ingredient> [forage] [prepare] [quantity] forage = gather, prepare = process
smelt.lic ;smelt <metal> Combines ingots in crucible

Document generated for script contributor reference. Please update as changes are made. Reference: Elanthipedia Crafting

⚠️ **GitHub.com Fallback** ⚠️