aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/behaviors/mine_clay.yaml14
-rw-r--r--data/behaviors/shear_sheep.yaml20
-rw-r--r--data/behaviors/tanner_talk.yaml46
-rw-r--r--data/items/amulet_mould.yaml5
-rw-r--r--data/items/ball_of_wool.yaml6
-rw-r--r--data/items/bracelet_mould.yaml5
-rw-r--r--data/items/bread_dough.yaml4
-rw-r--r--data/items/coif.yaml8
-rw-r--r--data/items/cowhide.yaml6
-rw-r--r--data/items/diamond.yaml6
-rw-r--r--data/items/diamond_amulet_u.yaml5
-rw-r--r--data/items/diamond_bracelet.yaml6
-rw-r--r--data/items/diamond_necklace.yaml6
-rw-r--r--data/items/diamond_ring.yaml6
-rw-r--r--data/items/emerald.yaml6
-rw-r--r--data/items/emerald_amulet_u.yaml5
-rw-r--r--data/items/emerald_bracelet.yaml6
-rw-r--r--data/items/emerald_necklace.yaml6
-rw-r--r--data/items/emerald_ring.yaml6
-rw-r--r--data/items/empty_jug.yaml6
-rw-r--r--data/items/empty_pitcher.yaml6
-rw-r--r--data/items/flax.yaml6
-rw-r--r--data/items/gold_amulet_u.yaml5
-rw-r--r--data/items/gold_bracelet.yaml6
-rw-r--r--data/items/gold_necklace.yaml6
-rw-r--r--data/items/gold_ring.yaml6
-rw-r--r--data/items/hard_leather.yaml6
-rw-r--r--data/items/hard_leather_body.yaml8
-rw-r--r--data/items/hard_leather_shield.yaml8
-rw-r--r--data/items/jug_of_water.yaml6
-rw-r--r--data/items/leather.yaml6
-rw-r--r--data/items/leather_body.yaml8
-rw-r--r--data/items/leather_boots.yaml8
-rw-r--r--data/items/leather_chaps.yaml8
-rw-r--r--data/items/leather_cowl.yaml8
-rw-r--r--data/items/leather_gloves.yaml8
-rw-r--r--data/items/leather_vambraces.yaml8
-rw-r--r--data/items/necklace_mould.yaml5
-rw-r--r--data/items/needle.yaml6
-rw-r--r--data/items/pie_dish.yaml5
-rw-r--r--data/items/pitcher_of_water.yaml6
-rw-r--r--data/items/plant_pot.yaml5
-rw-r--r--data/items/raw_beef.yaml6
-rw-r--r--data/items/ring_mould.yaml5
-rw-r--r--data/items/ruby.yaml6
-rw-r--r--data/items/ruby_amulet_u.yaml5
-rw-r--r--data/items/ruby_bracelet.yaml6
-rw-r--r--data/items/ruby_necklace.yaml6
-rw-r--r--data/items/ruby_ring.yaml6
-rw-r--r--data/items/sapphire.yaml6
-rw-r--r--data/items/sapphire_amulet_u.yaml5
-rw-r--r--data/items/sapphire_bracelet.yaml6
-rw-r--r--data/items/sapphire_necklace.yaml6
-rw-r--r--data/items/sapphire_ring.yaml6
-rw-r--r--data/items/shears.yaml6
-rw-r--r--data/items/soft_clay.yaml13
-rw-r--r--data/items/thread.yaml6
-rw-r--r--data/items/uncut_diamond.yaml2
-rw-r--r--data/items/uncut_emerald.yaml2
-rw-r--r--data/items/uncut_ruby.yaml2
-rw-r--r--data/items/uncut_sapphire.yaml2
-rw-r--r--data/items/unfired_pie_dish.yaml5
-rw-r--r--data/items/unfired_plant_pot.yaml5
-rw-r--r--data/items/unfired_pot.yaml5
-rw-r--r--data/items/wool.yaml6
-rw-r--r--data/mobs/cow.yaml22
-rw-r--r--data/mobs/tanner.yaml18
-rw-r--r--data/objects/clay_rock.yaml3
-rw-r--r--data/objects/pottery_oven.yaml4
-rw-r--r--data/objects/pottery_wheel.yaml4
-rw-r--r--data/objects/sheep.yaml6
-rw-r--r--data/objects/spinning_wheel.yaml4
-rw-r--r--data/recipes/cook_anchovies.yaml1
-rw-r--r--data/recipes/cook_bread.yaml1
-rw-r--r--data/recipes/cook_herring.yaml1
-rw-r--r--data/recipes/cook_salmon.yaml1
-rw-r--r--data/recipes/cook_sardine.yaml1
-rw-r--r--data/recipes/cook_shrimps.yaml1
-rw-r--r--data/recipes/cook_trout.yaml1
-rw-r--r--data/recipes/craft_ball_of_wool.yaml11
-rw-r--r--data/recipes/craft_bowstring.yaml11
-rw-r--r--data/recipes/craft_coif.yaml13
-rw-r--r--data/recipes/craft_cut_diamond.yaml11
-rw-r--r--data/recipes/craft_cut_emerald.yaml11
-rw-r--r--data/recipes/craft_cut_ruby.yaml11
-rw-r--r--data/recipes/craft_cut_sapphire.yaml11
-rw-r--r--data/recipes/craft_diamond_amulet_u.yaml16
-rw-r--r--data/recipes/craft_diamond_bracelet.yaml16
-rw-r--r--data/recipes/craft_diamond_necklace.yaml16
-rw-r--r--data/recipes/craft_diamond_ring.yaml16
-rw-r--r--data/recipes/craft_emerald_amulet_u.yaml16
-rw-r--r--data/recipes/craft_emerald_bracelet.yaml16
-rw-r--r--data/recipes/craft_emerald_necklace.yaml16
-rw-r--r--data/recipes/craft_emerald_ring.yaml16
-rw-r--r--data/recipes/craft_gold_amulet_u.yaml14
-rw-r--r--data/recipes/craft_gold_bracelet.yaml14
-rw-r--r--data/recipes/craft_gold_necklace.yaml14
-rw-r--r--data/recipes/craft_gold_ring.yaml14
-rw-r--r--data/recipes/craft_hard_leather_body.yaml13
-rw-r--r--data/recipes/craft_hard_leather_shield.yaml13
-rw-r--r--data/recipes/craft_leather_body.yaml13
-rw-r--r--data/recipes/craft_leather_boots.yaml13
-rw-r--r--data/recipes/craft_leather_chaps.yaml13
-rw-r--r--data/recipes/craft_leather_cowl.yaml13
-rw-r--r--data/recipes/craft_leather_gloves.yaml13
-rw-r--r--data/recipes/craft_leather_vambraces.yaml13
-rw-r--r--data/recipes/craft_pie_dish.yaml16
-rw-r--r--data/recipes/craft_plant_pot.yaml16
-rw-r--r--data/recipes/craft_pot.yaml16
-rw-r--r--data/recipes/craft_ruby_amulet_u.yaml16
-rw-r--r--data/recipes/craft_ruby_bracelet.yaml16
-rw-r--r--data/recipes/craft_ruby_necklace.yaml16
-rw-r--r--data/recipes/craft_ruby_ring.yaml16
-rw-r--r--data/recipes/craft_sapphire_amulet_u.yaml16
-rw-r--r--data/recipes/craft_sapphire_bracelet.yaml16
-rw-r--r--data/recipes/craft_sapphire_necklace.yaml16
-rw-r--r--data/recipes/craft_sapphire_ring.yaml16
-rw-r--r--data/recipes/craft_unfired_pie_dish.yaml11
-rw-r--r--data/recipes/craft_unfired_plant_pot.yaml11
-rw-r--r--data/recipes/craft_unfired_pot.yaml11
-rw-r--r--data/recipes/fletch_adamant_arrow.yaml1
-rw-r--r--data/recipes/fletch_adamant_bolts.yaml1
-rw-r--r--data/recipes/fletch_arrow_shaft.yaml2
-rw-r--r--data/recipes/fletch_arrow_shaft_magic.yaml2
-rw-r--r--data/recipes/fletch_arrow_shaft_maple.yaml2
-rw-r--r--data/recipes/fletch_arrow_shaft_oak.yaml2
-rw-r--r--data/recipes/fletch_arrow_shaft_willow.yaml2
-rw-r--r--data/recipes/fletch_arrow_shaft_yew.yaml2
-rw-r--r--data/recipes/fletch_bronze_arrow.yaml1
-rw-r--r--data/recipes/fletch_bronze_bolts.yaml1
-rw-r--r--data/recipes/fletch_diamond_bolt_tips.yaml2
-rw-r--r--data/recipes/fletch_diamond_bolts.yaml1
-rw-r--r--data/recipes/fletch_emerald_bolt_tips.yaml2
-rw-r--r--data/recipes/fletch_emerald_bolts.yaml1
-rw-r--r--data/recipes/fletch_headless_arrow.yaml1
-rw-r--r--data/recipes/fletch_iron_arrow.yaml1
-rw-r--r--data/recipes/fletch_iron_bolts.yaml1
-rw-r--r--data/recipes/fletch_longbow.yaml1
-rw-r--r--data/recipes/fletch_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_magic_longbow.yaml1
-rw-r--r--data/recipes/fletch_magic_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_magic_shortbow.yaml1
-rw-r--r--data/recipes/fletch_magic_shortbow_u.yaml2
-rw-r--r--data/recipes/fletch_maple_longbow.yaml1
-rw-r--r--data/recipes/fletch_maple_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_maple_shortbow.yaml1
-rw-r--r--data/recipes/fletch_maple_shortbow_u.yaml2
-rw-r--r--data/recipes/fletch_mithril_arrow.yaml1
-rw-r--r--data/recipes/fletch_mithril_bolts.yaml1
-rw-r--r--data/recipes/fletch_oak_longbow.yaml1
-rw-r--r--data/recipes/fletch_oak_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_oak_shortbow.yaml1
-rw-r--r--data/recipes/fletch_oak_shortbow_u.yaml2
-rw-r--r--data/recipes/fletch_ruby_bolt_tips.yaml2
-rw-r--r--data/recipes/fletch_ruby_bolts.yaml1
-rw-r--r--data/recipes/fletch_rune_arrow.yaml1
-rw-r--r--data/recipes/fletch_rune_bolts.yaml1
-rw-r--r--data/recipes/fletch_sapphire_bolt_tips.yaml2
-rw-r--r--data/recipes/fletch_sapphire_bolts.yaml1
-rw-r--r--data/recipes/fletch_shortbow.yaml1
-rw-r--r--data/recipes/fletch_shortbow_u.yaml2
-rw-r--r--data/recipes/fletch_steel_arrow.yaml1
-rw-r--r--data/recipes/fletch_steel_bolts.yaml1
-rw-r--r--data/recipes/fletch_willow_longbow.yaml1
-rw-r--r--data/recipes/fletch_willow_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_willow_shortbow.yaml1
-rw-r--r--data/recipes/fletch_willow_shortbow_u.yaml2
-rw-r--r--data/recipes/fletch_yew_longbow.yaml1
-rw-r--r--data/recipes/fletch_yew_longbow_u.yaml2
-rw-r--r--data/recipes/fletch_yew_shortbow.yaml1
-rw-r--r--data/recipes/fletch_yew_shortbow_u.yaml2
-rw-r--r--data/recipes/smith_adamant_arrowtips.yaml1
-rw-r--r--data/recipes/smith_adamant_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_adamant_dagger.yaml1
-rw-r--r--data/recipes/smith_adamant_full_helm.yaml1
-rw-r--r--data/recipes/smith_adamant_med_helm.yaml1
-rw-r--r--data/recipes/smith_adamant_nails.yaml1
-rw-r--r--data/recipes/smith_adamant_platebody.yaml1
-rw-r--r--data/recipes/smith_adamant_sword.yaml1
-rw-r--r--data/recipes/smith_bronze_arrowtips.yaml1
-rw-r--r--data/recipes/smith_bronze_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_bronze_dagger.yaml1
-rw-r--r--data/recipes/smith_bronze_full_helm.yaml1
-rw-r--r--data/recipes/smith_bronze_med_helm.yaml1
-rw-r--r--data/recipes/smith_bronze_nails.yaml1
-rw-r--r--data/recipes/smith_bronze_platebody.yaml1
-rw-r--r--data/recipes/smith_bronze_sword.yaml1
-rw-r--r--data/recipes/smith_iron_arrowtips.yaml1
-rw-r--r--data/recipes/smith_iron_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_iron_dagger.yaml1
-rw-r--r--data/recipes/smith_iron_full_helm.yaml1
-rw-r--r--data/recipes/smith_iron_med_helm.yaml1
-rw-r--r--data/recipes/smith_iron_nails.yaml1
-rw-r--r--data/recipes/smith_iron_platebody.yaml1
-rw-r--r--data/recipes/smith_iron_sword.yaml1
-rw-r--r--data/recipes/smith_mithril_arrowtips.yaml1
-rw-r--r--data/recipes/smith_mithril_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_mithril_dagger.yaml1
-rw-r--r--data/recipes/smith_mithril_full_helm.yaml1
-rw-r--r--data/recipes/smith_mithril_med_helm.yaml1
-rw-r--r--data/recipes/smith_mithril_nails.yaml1
-rw-r--r--data/recipes/smith_mithril_platebody.yaml1
-rw-r--r--data/recipes/smith_mithril_sword.yaml1
-rw-r--r--data/recipes/smith_rune_arrowtips.yaml1
-rw-r--r--data/recipes/smith_rune_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_rune_dagger.yaml1
-rw-r--r--data/recipes/smith_rune_full_helm.yaml1
-rw-r--r--data/recipes/smith_rune_med_helm.yaml1
-rw-r--r--data/recipes/smith_rune_nails.yaml1
-rw-r--r--data/recipes/smith_rune_platebody.yaml1
-rw-r--r--data/recipes/smith_rune_sword.yaml1
-rw-r--r--data/recipes/smith_steel_arrowtips.yaml1
-rw-r--r--data/recipes/smith_steel_bolts_unf.yaml1
-rw-r--r--data/recipes/smith_steel_dagger.yaml1
-rw-r--r--data/recipes/smith_steel_full_helm.yaml1
-rw-r--r--data/recipes/smith_steel_med_helm.yaml1
-rw-r--r--data/recipes/smith_steel_nails.yaml1
-rw-r--r--data/recipes/smith_steel_platebody.yaml1
-rw-r--r--data/recipes/smith_steel_sword.yaml1
-rw-r--r--data/rooms/13.yaml44
-rw-r--r--internal/action/behavior.go2
-rw-r--r--internal/action/recipe.go8
-rw-r--r--internal/game/action.go29
-rw-r--r--internal/game/action_fletch.go15
-rw-r--r--internal/game/action_gather.go5
-rw-r--r--internal/game/action_production.go299
-rw-r--r--internal/game/action_talk.go6
-rw-r--r--internal/game/cmd_attack.go8
-rw-r--r--internal/game/cmd_craft.go190
-rw-r--r--internal/game/cmd_fletch.go175
-rw-r--r--internal/game/cmd_smelt.go4
-rw-r--r--internal/game/cmd_smith.go173
-rw-r--r--internal/game/cmd_use.go50
-rw-r--r--internal/game/game.go11
-rw-r--r--internal/net/server.go5
235 files changed, 1707 insertions, 527 deletions
diff --git a/data/behaviors/mine_clay.yaml b/data/behaviors/mine_clay.yaml
index ff477ca..69e1ccf 100644
--- a/data/behaviors/mine_clay.yaml
+++ b/data/behaviors/mine_clay.yaml
@@ -3,18 +3,18 @@ type: gather
skill: mining
level: 1
xp: 5
-base_wait: 10
+base_wait: 4
tools: [pickaxe]
success:
- base: 0.55
+ base: 0.60
per_level: 0.01
cap: 0.95
-gather_message: "You dig at the soft clay..."
-fail_message: "You fail to get any clay."
+gather_message: "You swing your pickaxe at the clay rock..."
+fail_message: "You chip away but get nothing useful."
drops:
- item_id: clay
weight: 100
depletes: true
- message: "You manage to get some {173}clay{/}."
-respawn_timer: 50
-respawn_broadcast: "A deposit of clay softens."
+ message: "You manage to mine some clay."
+respawn_timer: 10
+respawn_broadcast: "Some clay fills in a nearby rock."
diff --git a/data/behaviors/shear_sheep.yaml b/data/behaviors/shear_sheep.yaml
new file mode 100644
index 0000000..a7061c3
--- /dev/null
+++ b/data/behaviors/shear_sheep.yaml
@@ -0,0 +1,20 @@
+id: shear_sheep
+type: gather
+skill: crafting
+level: 1
+xp: 0
+base_wait: 3
+tools: [shears]
+success:
+ base: 0.95
+ per_level: 0
+ cap: 0.95
+gather_message: "You hold the sheep still and begin shearing..."
+fail_message: "The sheep wriggles free!"
+drops:
+ - item_id: wool
+ weight: 100
+ depletes: true
+ message: "You shear some wool from the sheep."
+respawn_timer: 100
+respawn_broadcast: "A sheep grows a fresh coat of wool."
diff --git a/data/behaviors/tanner_talk.yaml b/data/behaviors/tanner_talk.yaml
new file mode 100644
index 0000000..edc0387
--- /dev/null
+++ b/data/behaviors/tanner_talk.yaml
@@ -0,0 +1,46 @@
+id: tanner_talk
+type: talk
+nodes:
+ start:
+ message: "\"Bring me some cowhides and I'll tan them for you. Leather is 10 credits, hard leather is 50.\""
+ options:
+ - text: "\"Tan a cowhide into leather (10 credits).\""
+ goto: tan_leather
+ condition:
+ all_of:
+ - has_item: cowhide
+ - min_credits: 10
+ - text: "\"Tan a cowhide into hard leather (50 credits).\""
+ goto: tan_hard_leather
+ condition:
+ all_of:
+ - has_item: cowhide
+ - min_credits: 50
+ - text: "\"Never mind.\""
+ end: true
+ tan_leather:
+ message: "The tanner takes your cowhide and works it skillfully. \"Here's your leather.\""
+ action:
+ take_item: cowhide
+ give_item: leather
+ cost: 10
+ options:
+ - text: "\"Tan another.\""
+ goto: start
+ condition:
+ has_item: cowhide
+ - text: "\"Thanks.\""
+ end: true
+ tan_hard_leather:
+ message: "The tanner takes your cowhide and subjects it to an intense curing process. \"Here's your hard leather.\""
+ action:
+ take_item: cowhide
+ give_item: hard_leather
+ cost: 50
+ options:
+ - text: "\"Tan another.\""
+ goto: start
+ condition:
+ has_item: cowhide
+ - text: "\"Thanks.\""
+ end: true
diff --git a/data/items/amulet_mould.yaml b/data/items/amulet_mould.yaml
new file mode 100644
index 0000000..a8153cb
--- /dev/null
+++ b/data/items/amulet_mould.yaml
@@ -0,0 +1,5 @@
+id: amulet_mould
+name: amulet mould
+color: "250"
+description: "A mould for casting amulets."
+value: 5
diff --git a/data/items/ball_of_wool.yaml b/data/items/ball_of_wool.yaml
new file mode 100644
index 0000000..1a680a4
--- /dev/null
+++ b/data/items/ball_of_wool.yaml
@@ -0,0 +1,6 @@
+id: ball_of_wool
+name: ball of wool
+color: "255"
+description: "A ball of spun wool."
+value: 5
+stackable: false
diff --git a/data/items/bracelet_mould.yaml b/data/items/bracelet_mould.yaml
new file mode 100644
index 0000000..78bc099
--- /dev/null
+++ b/data/items/bracelet_mould.yaml
@@ -0,0 +1,5 @@
+id: bracelet_mould
+name: bracelet mould
+color: "250"
+description: "A mould for casting bracelets."
+value: 5
diff --git a/data/items/bread_dough.yaml b/data/items/bread_dough.yaml
index c40d0e0..98ab297 100644
--- a/data/items/bread_dough.yaml
+++ b/data/items/bread_dough.yaml
@@ -9,6 +9,6 @@ made_from:
- items: [pot_of_flour]
qty: 1
byproducts: [empty_pot]
- - items: [bucket_of_water, pitcher_of_water]
+ - items: [bucket_of_water, jug_of_water]
qty: 1
- byproducts: [empty_bucket, empty_pitcher]
+ byproducts: [empty_bucket, empty_jug]
diff --git a/data/items/coif.yaml b/data/items/coif.yaml
new file mode 100644
index 0000000..d789fc1
--- /dev/null
+++ b/data/items/coif.yaml
@@ -0,0 +1,8 @@
+id: coif
+name: coif
+color: "94"
+description: "A hard leather coif."
+value: 45
+equip_slot: head
+stats:
+ defense_bonus: 6
diff --git a/data/items/cowhide.yaml b/data/items/cowhide.yaml
new file mode 100644
index 0000000..2cb192e
--- /dev/null
+++ b/data/items/cowhide.yaml
@@ -0,0 +1,6 @@
+id: cowhide
+name: cowhide
+color: "130"
+description: "A fresh cowhide. A tanner can turn this into leather."
+value: 5
+stackable: false
diff --git a/data/items/diamond.yaml b/data/items/diamond.yaml
new file mode 100644
index 0000000..2ec703f
--- /dev/null
+++ b/data/items/diamond.yaml
@@ -0,0 +1,6 @@
+id: diamond
+name: diamond
+color: "255"
+description: "A beautifully cut diamond."
+value: 400
+stackable: false
diff --git a/data/items/diamond_amulet_u.yaml b/data/items/diamond_amulet_u.yaml
new file mode 100644
index 0000000..55eaf45
--- /dev/null
+++ b/data/items/diamond_amulet_u.yaml
@@ -0,0 +1,5 @@
+id: diamond_amulet_u
+name: diamond amulet (u)
+color: "255"
+description: "An unstrung gold amulet set with a diamond."
+value: 200
diff --git a/data/items/diamond_bracelet.yaml b/data/items/diamond_bracelet.yaml
new file mode 100644
index 0000000..c4fcb85
--- /dev/null
+++ b/data/items/diamond_bracelet.yaml
@@ -0,0 +1,6 @@
+id: diamond_bracelet
+name: diamond bracelet
+color: "255"
+description: "A gold bracelet set with a diamond."
+value: 190
+equip_slot: hands
diff --git a/data/items/diamond_necklace.yaml b/data/items/diamond_necklace.yaml
new file mode 100644
index 0000000..e900756
--- /dev/null
+++ b/data/items/diamond_necklace.yaml
@@ -0,0 +1,6 @@
+id: diamond_necklace
+name: diamond necklace
+color: "255"
+description: "A gold necklace set with a diamond."
+value: 180
+equip_slot: neck
diff --git a/data/items/diamond_ring.yaml b/data/items/diamond_ring.yaml
new file mode 100644
index 0000000..7980d2a
--- /dev/null
+++ b/data/items/diamond_ring.yaml
@@ -0,0 +1,6 @@
+id: diamond_ring
+name: diamond ring
+color: "255"
+description: "A gold ring set with a diamond."
+value: 170
+equip_slot: ring
diff --git a/data/items/emerald.yaml b/data/items/emerald.yaml
new file mode 100644
index 0000000..9a0c71d
--- /dev/null
+++ b/data/items/emerald.yaml
@@ -0,0 +1,6 @@
+id: emerald
+name: emerald
+color: "83"
+description: "A beautifully cut emerald."
+value: 100
+stackable: false
diff --git a/data/items/emerald_amulet_u.yaml b/data/items/emerald_amulet_u.yaml
new file mode 100644
index 0000000..87261d4
--- /dev/null
+++ b/data/items/emerald_amulet_u.yaml
@@ -0,0 +1,5 @@
+id: emerald_amulet_u
+name: emerald amulet (u)
+color: "83"
+description: "An unstrung gold amulet set with a emerald."
+value: 110
diff --git a/data/items/emerald_bracelet.yaml b/data/items/emerald_bracelet.yaml
new file mode 100644
index 0000000..91fa223
--- /dev/null
+++ b/data/items/emerald_bracelet.yaml
@@ -0,0 +1,6 @@
+id: emerald_bracelet
+name: emerald bracelet
+color: "83"
+description: "A gold bracelet set with a emerald."
+value: 105
+equip_slot: hands
diff --git a/data/items/emerald_necklace.yaml b/data/items/emerald_necklace.yaml
new file mode 100644
index 0000000..2f87002
--- /dev/null
+++ b/data/items/emerald_necklace.yaml
@@ -0,0 +1,6 @@
+id: emerald_necklace
+name: emerald necklace
+color: "83"
+description: "A gold necklace set with a emerald."
+value: 100
+equip_slot: neck
diff --git a/data/items/emerald_ring.yaml b/data/items/emerald_ring.yaml
new file mode 100644
index 0000000..f70a059
--- /dev/null
+++ b/data/items/emerald_ring.yaml
@@ -0,0 +1,6 @@
+id: emerald_ring
+name: emerald ring
+color: "83"
+description: "A gold ring set with a emerald."
+value: 95
+equip_slot: ring
diff --git a/data/items/empty_jug.yaml b/data/items/empty_jug.yaml
new file mode 100644
index 0000000..c6774a5
--- /dev/null
+++ b/data/items/empty_jug.yaml
@@ -0,0 +1,6 @@
+id: empty_jug
+name: empty jug
+color: "137"
+description: "An empty ceramic jug."
+value: 1
+stackable: false
diff --git a/data/items/empty_pitcher.yaml b/data/items/empty_pitcher.yaml
deleted file mode 100644
index d1fbb49..0000000
--- a/data/items/empty_pitcher.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-id: empty_pitcher
-name: empty pitcher
-color: "137"
-description: "An empty ceramic pitcher."
-value: 1
-stackable: false
diff --git a/data/items/flax.yaml b/data/items/flax.yaml
new file mode 100644
index 0000000..36f7082
--- /dev/null
+++ b/data/items/flax.yaml
@@ -0,0 +1,6 @@
+id: flax
+name: flax
+color: "113"
+description: "A bundle of flax. Can be spun into a bowstring."
+value: 5
+stackable: false
diff --git a/data/items/gold_amulet_u.yaml b/data/items/gold_amulet_u.yaml
new file mode 100644
index 0000000..8671941
--- /dev/null
+++ b/data/items/gold_amulet_u.yaml
@@ -0,0 +1,5 @@
+id: gold_amulet_u
+name: gold amulet (u)
+color: "220"
+description: "An unstrung gold amulet."
+value: 70
diff --git a/data/items/gold_bracelet.yaml b/data/items/gold_bracelet.yaml
new file mode 100644
index 0000000..2c4534f
--- /dev/null
+++ b/data/items/gold_bracelet.yaml
@@ -0,0 +1,6 @@
+id: gold_bracelet
+name: gold bracelet
+color: "220"
+description: "A gold bracelet."
+value: 65
+equip_slot: hands
diff --git a/data/items/gold_necklace.yaml b/data/items/gold_necklace.yaml
new file mode 100644
index 0000000..4a22ac1
--- /dev/null
+++ b/data/items/gold_necklace.yaml
@@ -0,0 +1,6 @@
+id: gold_necklace
+name: gold necklace
+color: "220"
+description: "A gold necklace."
+value: 60
+equip_slot: neck
diff --git a/data/items/gold_ring.yaml b/data/items/gold_ring.yaml
new file mode 100644
index 0000000..1a39165
--- /dev/null
+++ b/data/items/gold_ring.yaml
@@ -0,0 +1,6 @@
+id: gold_ring
+name: gold ring
+color: "220"
+description: "A simple gold ring."
+value: 50
+equip_slot: ring
diff --git a/data/items/hard_leather.yaml b/data/items/hard_leather.yaml
new file mode 100644
index 0000000..e04030c
--- /dev/null
+++ b/data/items/hard_leather.yaml
@@ -0,0 +1,6 @@
+id: hard_leather
+name: hard leather
+color: "94"
+description: "A piece of hardened leather, suitable for sturdy armour."
+value: 55
+stackable: false
diff --git a/data/items/hard_leather_body.yaml b/data/items/hard_leather_body.yaml
new file mode 100644
index 0000000..ef05226
--- /dev/null
+++ b/data/items/hard_leather_body.yaml
@@ -0,0 +1,8 @@
+id: hard_leather_body
+name: hard leather body
+color: "94"
+description: "A hardened leather body armour."
+value: 60
+equip_slot: torso
+stats:
+ defense_bonus: 12
diff --git a/data/items/hard_leather_shield.yaml b/data/items/hard_leather_shield.yaml
new file mode 100644
index 0000000..3dc0f30
--- /dev/null
+++ b/data/items/hard_leather_shield.yaml
@@ -0,0 +1,8 @@
+id: hard_leather_shield
+name: hard leather shield
+color: "94"
+description: "A shield made of hardened leather."
+value: 55
+equip_slot: off_hand
+stats:
+ defense_bonus: 8
diff --git a/data/items/jug_of_water.yaml b/data/items/jug_of_water.yaml
new file mode 100644
index 0000000..04d3b8f
--- /dev/null
+++ b/data/items/jug_of_water.yaml
@@ -0,0 +1,6 @@
+id: jug_of_water
+name: jug of water
+color: "81"
+description: "A ceramic jug filled with fresh water."
+value: 5
+stackable: false
diff --git a/data/items/leather.yaml b/data/items/leather.yaml
new file mode 100644
index 0000000..82d0696
--- /dev/null
+++ b/data/items/leather.yaml
@@ -0,0 +1,6 @@
+id: leather
+name: leather
+color: "130"
+description: "A piece of tanned leather, ready for crafting."
+value: 15
+stackable: false
diff --git a/data/items/leather_body.yaml b/data/items/leather_body.yaml
new file mode 100644
index 0000000..78dcdf4
--- /dev/null
+++ b/data/items/leather_body.yaml
@@ -0,0 +1,8 @@
+id: leather_body
+name: leather body
+color: "130"
+description: "A leather body armour."
+value: 25
+equip_slot: torso
+stats:
+ defense_bonus: 8
diff --git a/data/items/leather_boots.yaml b/data/items/leather_boots.yaml
new file mode 100644
index 0000000..296d9c7
--- /dev/null
+++ b/data/items/leather_boots.yaml
@@ -0,0 +1,8 @@
+id: leather_boots
+name: leather boots
+color: "130"
+description: "A pair of leather boots."
+value: 12
+equip_slot: feet
+stats:
+ defense_bonus: 2
diff --git a/data/items/leather_chaps.yaml b/data/items/leather_chaps.yaml
new file mode 100644
index 0000000..38301f9
--- /dev/null
+++ b/data/items/leather_chaps.yaml
@@ -0,0 +1,8 @@
+id: leather_chaps
+name: leather chaps
+color: "130"
+description: "A pair of leather chaps."
+value: 20
+equip_slot: legs
+stats:
+ defense_bonus: 6
diff --git a/data/items/leather_cowl.yaml b/data/items/leather_cowl.yaml
new file mode 100644
index 0000000..e8fe399
--- /dev/null
+++ b/data/items/leather_cowl.yaml
@@ -0,0 +1,8 @@
+id: leather_cowl
+name: leather cowl
+color: "130"
+description: "A leather cowl."
+value: 15
+equip_slot: head
+stats:
+ defense_bonus: 3
diff --git a/data/items/leather_gloves.yaml b/data/items/leather_gloves.yaml
new file mode 100644
index 0000000..1924954
--- /dev/null
+++ b/data/items/leather_gloves.yaml
@@ -0,0 +1,8 @@
+id: leather_gloves
+name: leather gloves
+color: "130"
+description: "A pair of leather gloves."
+value: 10
+equip_slot: hands
+stats:
+ defense_bonus: 2
diff --git a/data/items/leather_vambraces.yaml b/data/items/leather_vambraces.yaml
new file mode 100644
index 0000000..4edfddc
--- /dev/null
+++ b/data/items/leather_vambraces.yaml
@@ -0,0 +1,8 @@
+id: leather_vambraces
+name: leather vambraces
+color: "130"
+description: "A pair of leather vambraces."
+value: 18
+equip_slot: hands
+stats:
+ defense_bonus: 4
diff --git a/data/items/necklace_mould.yaml b/data/items/necklace_mould.yaml
new file mode 100644
index 0000000..bc4df45
--- /dev/null
+++ b/data/items/necklace_mould.yaml
@@ -0,0 +1,5 @@
+id: necklace_mould
+name: necklace mould
+color: "250"
+description: "A mould for casting necklaces."
+value: 5
diff --git a/data/items/needle.yaml b/data/items/needle.yaml
new file mode 100644
index 0000000..5f53bf3
--- /dev/null
+++ b/data/items/needle.yaml
@@ -0,0 +1,6 @@
+id: needle
+name: needle
+color: "250"
+description: "A needle for crafting leather goods."
+value: 5
+tool_type: needle
diff --git a/data/items/pie_dish.yaml b/data/items/pie_dish.yaml
new file mode 100644
index 0000000..bd6100b
--- /dev/null
+++ b/data/items/pie_dish.yaml
@@ -0,0 +1,5 @@
+id: pie_dish
+name: pie dish
+color: "130"
+description: "A clay pie dish for baking pies."
+value: 5
diff --git a/data/items/pitcher_of_water.yaml b/data/items/pitcher_of_water.yaml
deleted file mode 100644
index a258411..0000000
--- a/data/items/pitcher_of_water.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-id: pitcher_of_water
-name: pitcher of water
-color: "81"
-description: "A ceramic pitcher filled with fresh water."
-value: 5
-stackable: false
diff --git a/data/items/plant_pot.yaml b/data/items/plant_pot.yaml
new file mode 100644
index 0000000..2f81e08
--- /dev/null
+++ b/data/items/plant_pot.yaml
@@ -0,0 +1,5 @@
+id: plant_pot
+name: plant pot
+color: "130"
+description: "A clay plant pot for growing plants."
+value: 5
diff --git a/data/items/raw_beef.yaml b/data/items/raw_beef.yaml
new file mode 100644
index 0000000..59695b0
--- /dev/null
+++ b/data/items/raw_beef.yaml
@@ -0,0 +1,6 @@
+id: raw_beef
+name: raw beef
+color: "196"
+description: "A slab of raw beef."
+value: 2
+stackable: false
diff --git a/data/items/ring_mould.yaml b/data/items/ring_mould.yaml
new file mode 100644
index 0000000..d7846c8
--- /dev/null
+++ b/data/items/ring_mould.yaml
@@ -0,0 +1,5 @@
+id: ring_mould
+name: ring mould
+color: "250"
+description: "A mould for casting rings."
+value: 5
diff --git a/data/items/ruby.yaml b/data/items/ruby.yaml
new file mode 100644
index 0000000..644e1bf
--- /dev/null
+++ b/data/items/ruby.yaml
@@ -0,0 +1,6 @@
+id: ruby
+name: ruby
+color: "196"
+description: "A beautifully cut ruby."
+value: 200
+stackable: false
diff --git a/data/items/ruby_amulet_u.yaml b/data/items/ruby_amulet_u.yaml
new file mode 100644
index 0000000..031bf8b
--- /dev/null
+++ b/data/items/ruby_amulet_u.yaml
@@ -0,0 +1,5 @@
+id: ruby_amulet_u
+name: ruby amulet (u)
+color: "196"
+description: "An unstrung gold amulet set with a ruby."
+value: 145
diff --git a/data/items/ruby_bracelet.yaml b/data/items/ruby_bracelet.yaml
new file mode 100644
index 0000000..4a9a509
--- /dev/null
+++ b/data/items/ruby_bracelet.yaml
@@ -0,0 +1,6 @@
+id: ruby_bracelet
+name: ruby bracelet
+color: "196"
+description: "A gold bracelet set with a ruby."
+value: 140
+equip_slot: hands
diff --git a/data/items/ruby_necklace.yaml b/data/items/ruby_necklace.yaml
new file mode 100644
index 0000000..2c1315d
--- /dev/null
+++ b/data/items/ruby_necklace.yaml
@@ -0,0 +1,6 @@
+id: ruby_necklace
+name: ruby necklace
+color: "196"
+description: "A gold necklace set with a ruby."
+value: 135
+equip_slot: neck
diff --git a/data/items/ruby_ring.yaml b/data/items/ruby_ring.yaml
new file mode 100644
index 0000000..9582c0a
--- /dev/null
+++ b/data/items/ruby_ring.yaml
@@ -0,0 +1,6 @@
+id: ruby_ring
+name: ruby ring
+color: "196"
+description: "A gold ring set with a ruby."
+value: 130
+equip_slot: ring
diff --git a/data/items/sapphire.yaml b/data/items/sapphire.yaml
new file mode 100644
index 0000000..9710d45
--- /dev/null
+++ b/data/items/sapphire.yaml
@@ -0,0 +1,6 @@
+id: sapphire
+name: sapphire
+color: "69"
+description: "A beautifully cut sapphire."
+value: 50
+stackable: false
diff --git a/data/items/sapphire_amulet_u.yaml b/data/items/sapphire_amulet_u.yaml
new file mode 100644
index 0000000..22ef39c
--- /dev/null
+++ b/data/items/sapphire_amulet_u.yaml
@@ -0,0 +1,5 @@
+id: sapphire_amulet_u
+name: sapphire amulet (u)
+color: "69"
+description: "An unstrung gold amulet set with a sapphire."
+value: 100
diff --git a/data/items/sapphire_bracelet.yaml b/data/items/sapphire_bracelet.yaml
new file mode 100644
index 0000000..54d7c45
--- /dev/null
+++ b/data/items/sapphire_bracelet.yaml
@@ -0,0 +1,6 @@
+id: sapphire_bracelet
+name: sapphire bracelet
+color: "69"
+description: "A gold bracelet set with a sapphire."
+value: 95
+equip_slot: hands
diff --git a/data/items/sapphire_necklace.yaml b/data/items/sapphire_necklace.yaml
new file mode 100644
index 0000000..80deb37
--- /dev/null
+++ b/data/items/sapphire_necklace.yaml
@@ -0,0 +1,6 @@
+id: sapphire_necklace
+name: sapphire necklace
+color: "69"
+description: "A gold necklace set with a sapphire."
+value: 90
+equip_slot: neck
diff --git a/data/items/sapphire_ring.yaml b/data/items/sapphire_ring.yaml
new file mode 100644
index 0000000..013a730
--- /dev/null
+++ b/data/items/sapphire_ring.yaml
@@ -0,0 +1,6 @@
+id: sapphire_ring
+name: sapphire ring
+color: "69"
+description: "A gold ring set with a sapphire."
+value: 80
+equip_slot: ring
diff --git a/data/items/shears.yaml b/data/items/shears.yaml
new file mode 100644
index 0000000..4166be3
--- /dev/null
+++ b/data/items/shears.yaml
@@ -0,0 +1,6 @@
+id: shears
+name: shears
+color: "250"
+description: "A pair of shears for shearing sheep."
+value: 5
+tool_type: shears
diff --git a/data/items/soft_clay.yaml b/data/items/soft_clay.yaml
new file mode 100644
index 0000000..1ba07e3
--- /dev/null
+++ b/data/items/soft_clay.yaml
@@ -0,0 +1,13 @@
+id: soft_clay
+name: soft clay
+color: "173"
+description: "Soft, workable clay ready for shaping on a pottery wheel."
+value: 2
+stackable: false
+ticks: 2
+made_from:
+ - items: [clay]
+ qty: 1
+ - items: [bucket_of_water, jug_of_water]
+ qty: 1
+ byproducts: [empty_bucket, empty_jug]
diff --git a/data/items/thread.yaml b/data/items/thread.yaml
new file mode 100644
index 0000000..3a9a4f7
--- /dev/null
+++ b/data/items/thread.yaml
@@ -0,0 +1,6 @@
+id: thread
+name: thread
+color: "230"
+description: "A spool of thread used for leatherworking."
+value: 1
+stackable: true
diff --git a/data/items/uncut_diamond.yaml b/data/items/uncut_diamond.yaml
index 48d8e6f..cf41d70 100644
--- a/data/items/uncut_diamond.yaml
+++ b/data/items/uncut_diamond.yaml
@@ -1,6 +1,6 @@
id: uncut_diamond
name: uncut diamond
color: "255"
-description: "An uncut diamond. Can be cut into bolt tips with a chisel."
+description: "An uncut diamond. Can be cut with a chisel."
value: 200
stackable: false
diff --git a/data/items/uncut_emerald.yaml b/data/items/uncut_emerald.yaml
index 5fd5015..1ea217a 100644
--- a/data/items/uncut_emerald.yaml
+++ b/data/items/uncut_emerald.yaml
@@ -1,6 +1,6 @@
id: uncut_emerald
name: uncut emerald
color: "83"
-description: "An uncut emerald. Can be cut into bolt tips with a chisel."
+description: "An uncut emerald. Can be cut with a chisel."
value: 50
stackable: false
diff --git a/data/items/uncut_ruby.yaml b/data/items/uncut_ruby.yaml
index b4912b8..dfa8188 100644
--- a/data/items/uncut_ruby.yaml
+++ b/data/items/uncut_ruby.yaml
@@ -1,6 +1,6 @@
id: uncut_ruby
name: uncut ruby
color: "196"
-description: "An uncut ruby. Can be cut into bolt tips with a chisel."
+description: "An uncut ruby. Can be cut with a chisel."
value: 100
stackable: false
diff --git a/data/items/uncut_sapphire.yaml b/data/items/uncut_sapphire.yaml
index eb0e51d..bf073fa 100644
--- a/data/items/uncut_sapphire.yaml
+++ b/data/items/uncut_sapphire.yaml
@@ -1,6 +1,6 @@
id: uncut_sapphire
name: uncut sapphire
color: "69"
-description: "An uncut sapphire. Can be cut into bolt tips with a chisel."
+description: "An uncut sapphire. Can be cut with a chisel."
value: 25
stackable: false
diff --git a/data/items/unfired_pie_dish.yaml b/data/items/unfired_pie_dish.yaml
new file mode 100644
index 0000000..fddc4d1
--- /dev/null
+++ b/data/items/unfired_pie_dish.yaml
@@ -0,0 +1,5 @@
+id: unfired_pie_dish
+name: unfired pie dish
+color: "173"
+description: "An unfired clay pie dish. It needs to be fired in a pottery oven."
+value: 1
diff --git a/data/items/unfired_plant_pot.yaml b/data/items/unfired_plant_pot.yaml
new file mode 100644
index 0000000..c088242
--- /dev/null
+++ b/data/items/unfired_plant_pot.yaml
@@ -0,0 +1,5 @@
+id: unfired_plant_pot
+name: unfired plant pot
+color: "173"
+description: "An unfired clay plant pot. It needs to be fired in a pottery oven."
+value: 1
diff --git a/data/items/unfired_pot.yaml b/data/items/unfired_pot.yaml
new file mode 100644
index 0000000..265a19f
--- /dev/null
+++ b/data/items/unfired_pot.yaml
@@ -0,0 +1,5 @@
+id: unfired_pot
+name: unfired pot
+color: "173"
+description: "An unfired clay pot. It needs to be fired in a pottery oven."
+value: 1
diff --git a/data/items/wool.yaml b/data/items/wool.yaml
new file mode 100644
index 0000000..f557aaf
--- /dev/null
+++ b/data/items/wool.yaml
@@ -0,0 +1,6 @@
+id: wool
+name: wool
+color: "255"
+description: "A tuft of sheep's wool. Can be spun into a ball of wool."
+value: 1
+stackable: false
diff --git a/data/mobs/cow.yaml b/data/mobs/cow.yaml
new file mode 100644
index 0000000..2873a57
--- /dev/null
+++ b/data/mobs/cow.yaml
@@ -0,0 +1,22 @@
+id: cow
+name: cow
+description: "A placid dairy cow, chewing cud."
+attack: 1
+strength: 1
+defense: 1
+hp: 8
+speed: 5
+aggressive: false
+respawn_ticks: 30
+idle_descriptions:
+ - "moos softly"
+ - "chews on some grass"
+ - "swishes its tail lazily"
+ - "stares at you with big brown eyes"
+drops:
+ remains: bones
+ loot:
+ - item_id: cowhide
+ weight: 100
+ - item_id: raw_beef
+ weight: 100
diff --git a/data/mobs/tanner.yaml b/data/mobs/tanner.yaml
new file mode 100644
index 0000000..d28fb41
--- /dev/null
+++ b/data/mobs/tanner.yaml
@@ -0,0 +1,18 @@
+id: tanner
+name: Tanner
+description: "A weathered craftsman with stained hands and a leather apron."
+behavior: tanner_talk
+unique: true
+protected: true
+hp: 50
+attack: 1
+strength: 1
+defense: 1
+speed: 5
+aggressive: false
+respawn_ticks: 30
+idle_descriptions:
+ - "scrapes at a piece of hide"
+ - "examines a stack of leathers"
+ - "sharpens a tanning knife"
+ - "wipes sweat from his brow"
diff --git a/data/objects/clay_rock.yaml b/data/objects/clay_rock.yaml
index dd87eba..8a69d3b 100644
--- a/data/objects/clay_rock.yaml
+++ b/data/objects/clay_rock.yaml
@@ -1,4 +1,5 @@
id: clay_rock
-name: clay deposit
+name: clay rock
color: "173"
behavior: mine_clay
+description: "A soft rock of clay."
diff --git a/data/objects/pottery_oven.yaml b/data/objects/pottery_oven.yaml
new file mode 100644
index 0000000..c86e409
--- /dev/null
+++ b/data/objects/pottery_oven.yaml
@@ -0,0 +1,4 @@
+id: pottery_oven
+name: pottery oven
+color: "196"
+description: "A kiln for firing pottery."
diff --git a/data/objects/pottery_wheel.yaml b/data/objects/pottery_wheel.yaml
new file mode 100644
index 0000000..cc2e225
--- /dev/null
+++ b/data/objects/pottery_wheel.yaml
@@ -0,0 +1,4 @@
+id: pottery_wheel
+name: pottery wheel
+color: "173"
+description: "A foot-powered pottery wheel for shaping clay."
diff --git a/data/objects/sheep.yaml b/data/objects/sheep.yaml
new file mode 100644
index 0000000..2739c9c
--- /dev/null
+++ b/data/objects/sheep.yaml
@@ -0,0 +1,6 @@
+id: sheep
+name: sheep
+color: "255"
+behavior: shear_sheep
+description: "A fluffy sheep, ready to be shorn."
+inroom_description: "A fluffy sheep is wandering around here."
diff --git a/data/objects/spinning_wheel.yaml b/data/objects/spinning_wheel.yaml
new file mode 100644
index 0000000..683f0b6
--- /dev/null
+++ b/data/objects/spinning_wheel.yaml
@@ -0,0 +1,4 @@
+id: spinning_wheel
+name: spinning wheel
+color: "130"
+description: "A wooden spinning wheel for spinning wool and flax."
diff --git a/data/recipes/cook_anchovies.yaml b/data/recipes/cook_anchovies.yaml
index df04d01..07d3f62 100644
--- a/data/recipes/cook_anchovies.yaml
+++ b/data/recipes/cook_anchovies.yaml
@@ -1,6 +1,5 @@
id: cook_anchovies
type: cooking
-skill: cooking
level: 1
xp: 30
wait: 6
diff --git a/data/recipes/cook_bread.yaml b/data/recipes/cook_bread.yaml
index 650525f..c76cedc 100644
--- a/data/recipes/cook_bread.yaml
+++ b/data/recipes/cook_bread.yaml
@@ -1,6 +1,5 @@
id: cook_bread
type: cooking
-skill: cooking
level: 1
xp: 40
wait: 6
diff --git a/data/recipes/cook_herring.yaml b/data/recipes/cook_herring.yaml
index 7779ef0..05d10eb 100644
--- a/data/recipes/cook_herring.yaml
+++ b/data/recipes/cook_herring.yaml
@@ -1,6 +1,5 @@
id: cook_herring
type: cooking
-skill: cooking
level: 5
xp: 50
wait: 6
diff --git a/data/recipes/cook_salmon.yaml b/data/recipes/cook_salmon.yaml
index 04ee40c..ab086fb 100644
--- a/data/recipes/cook_salmon.yaml
+++ b/data/recipes/cook_salmon.yaml
@@ -1,6 +1,5 @@
id: cook_salmon
type: cooking
-skill: cooking
level: 25
xp: 90
wait: 6
diff --git a/data/recipes/cook_sardine.yaml b/data/recipes/cook_sardine.yaml
index 0ad6901..f7e8389 100644
--- a/data/recipes/cook_sardine.yaml
+++ b/data/recipes/cook_sardine.yaml
@@ -1,6 +1,5 @@
id: cook_sardine
type: cooking
-skill: cooking
level: 1
xp: 40
wait: 6
diff --git a/data/recipes/cook_shrimps.yaml b/data/recipes/cook_shrimps.yaml
index f38c1cd..8755b68 100644
--- a/data/recipes/cook_shrimps.yaml
+++ b/data/recipes/cook_shrimps.yaml
@@ -1,6 +1,5 @@
id: cook_shrimps
type: cooking
-skill: cooking
level: 1
xp: 30
wait: 6
diff --git a/data/recipes/cook_trout.yaml b/data/recipes/cook_trout.yaml
index 79df193..a392e3d 100644
--- a/data/recipes/cook_trout.yaml
+++ b/data/recipes/cook_trout.yaml
@@ -1,6 +1,5 @@
id: cook_trout
type: cooking
-skill: cooking
level: 15
xp: 70
wait: 6
diff --git a/data/recipes/craft_ball_of_wool.yaml b/data/recipes/craft_ball_of_wool.yaml
new file mode 100644
index 0000000..2f8f4f9
--- /dev/null
+++ b/data/recipes/craft_ball_of_wool.yaml
@@ -0,0 +1,11 @@
+id: craft_ball_of_wool
+type: crafting
+level: 1
+xp: 3
+wait: 3
+station: [spinning_wheel]
+consume:
+ - items: [wool]
+ qty: 1
+output: ball_of_wool
+message: "You spin the wool into a ball."
diff --git a/data/recipes/craft_bowstring.yaml b/data/recipes/craft_bowstring.yaml
new file mode 100644
index 0000000..1df6aba
--- /dev/null
+++ b/data/recipes/craft_bowstring.yaml
@@ -0,0 +1,11 @@
+id: craft_bowstring
+type: crafting
+level: 1
+xp: 15
+wait: 3
+station: [spinning_wheel]
+consume:
+ - items: [flax]
+ qty: 1
+output: bowstring
+message: "You spin the flax into a bowstring."
diff --git a/data/recipes/craft_coif.yaml b/data/recipes/craft_coif.yaml
new file mode 100644
index 0000000..49fc4c3
--- /dev/null
+++ b/data/recipes/craft_coif.yaml
@@ -0,0 +1,13 @@
+id: craft_coif
+type: crafting
+level: 38
+xp: 37
+wait: 4
+tool: needle
+consume:
+ - items: [hard_leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: coif
+message: "You craft a coif."
diff --git a/data/recipes/craft_cut_diamond.yaml b/data/recipes/craft_cut_diamond.yaml
new file mode 100644
index 0000000..b0187a8
--- /dev/null
+++ b/data/recipes/craft_cut_diamond.yaml
@@ -0,0 +1,11 @@
+id: craft_cut_diamond
+type: crafting
+level: 43
+xp: 108
+wait: 3
+tool: chisel
+consume:
+ - items: [uncut_diamond]
+ qty: 1
+output: diamond
+message: "You cut the diamond into a beautiful gem."
diff --git a/data/recipes/craft_cut_emerald.yaml b/data/recipes/craft_cut_emerald.yaml
new file mode 100644
index 0000000..69fdd19
--- /dev/null
+++ b/data/recipes/craft_cut_emerald.yaml
@@ -0,0 +1,11 @@
+id: craft_cut_emerald
+type: crafting
+level: 27
+xp: 68
+wait: 3
+tool: chisel
+consume:
+ - items: [uncut_emerald]
+ qty: 1
+output: emerald
+message: "You cut the emerald into a beautiful gem."
diff --git a/data/recipes/craft_cut_ruby.yaml b/data/recipes/craft_cut_ruby.yaml
new file mode 100644
index 0000000..6cc402c
--- /dev/null
+++ b/data/recipes/craft_cut_ruby.yaml
@@ -0,0 +1,11 @@
+id: craft_cut_ruby
+type: crafting
+level: 63
+xp: 85
+wait: 3
+tool: chisel
+consume:
+ - items: [uncut_ruby]
+ qty: 1
+output: ruby
+message: "You cut the ruby into a beautiful gem."
diff --git a/data/recipes/craft_cut_sapphire.yaml b/data/recipes/craft_cut_sapphire.yaml
new file mode 100644
index 0000000..6f3bb65
--- /dev/null
+++ b/data/recipes/craft_cut_sapphire.yaml
@@ -0,0 +1,11 @@
+id: craft_cut_sapphire
+type: crafting
+level: 20
+xp: 50
+wait: 3
+tool: chisel
+consume:
+ - items: [uncut_sapphire]
+ qty: 1
+output: sapphire
+message: "You cut the sapphire into a beautiful gem."
diff --git a/data/recipes/craft_diamond_amulet_u.yaml b/data/recipes/craft_diamond_amulet_u.yaml
new file mode 100644
index 0000000..053c409
--- /dev/null
+++ b/data/recipes/craft_diamond_amulet_u.yaml
@@ -0,0 +1,16 @@
+id: craft_diamond_amulet_u
+type: crafting
+level: 70
+xp: 100
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [diamond]
+ qty: 1
+ - items: [amulet_mould]
+ qty: 1
+ byproducts: [amulet_mould]
+output: diamond_amulet_u
+message: "You cast a diamond amulet."
diff --git a/data/recipes/craft_diamond_bracelet.yaml b/data/recipes/craft_diamond_bracelet.yaml
new file mode 100644
index 0000000..17ac23e
--- /dev/null
+++ b/data/recipes/craft_diamond_bracelet.yaml
@@ -0,0 +1,16 @@
+id: craft_diamond_bracelet
+type: crafting
+level: 58
+xp: 95
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [diamond]
+ qty: 1
+ - items: [bracelet_mould]
+ qty: 1
+ byproducts: [bracelet_mould]
+output: diamond_bracelet
+message: "You cast a diamond bracelet."
diff --git a/data/recipes/craft_diamond_necklace.yaml b/data/recipes/craft_diamond_necklace.yaml
new file mode 100644
index 0000000..cebbec1
--- /dev/null
+++ b/data/recipes/craft_diamond_necklace.yaml
@@ -0,0 +1,16 @@
+id: craft_diamond_necklace
+type: crafting
+level: 56
+xp: 90
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [diamond]
+ qty: 1
+ - items: [necklace_mould]
+ qty: 1
+ byproducts: [necklace_mould]
+output: diamond_necklace
+message: "You cast a diamond necklace."
diff --git a/data/recipes/craft_diamond_ring.yaml b/data/recipes/craft_diamond_ring.yaml
new file mode 100644
index 0000000..aacce0e
--- /dev/null
+++ b/data/recipes/craft_diamond_ring.yaml
@@ -0,0 +1,16 @@
+id: craft_diamond_ring
+type: crafting
+level: 43
+xp: 85
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [diamond]
+ qty: 1
+ - items: [ring_mould]
+ qty: 1
+ byproducts: [ring_mould]
+output: diamond_ring
+message: "You cast a diamond ring."
diff --git a/data/recipes/craft_emerald_amulet_u.yaml b/data/recipes/craft_emerald_amulet_u.yaml
new file mode 100644
index 0000000..dbf8b8a
--- /dev/null
+++ b/data/recipes/craft_emerald_amulet_u.yaml
@@ -0,0 +1,16 @@
+id: craft_emerald_amulet_u
+type: crafting
+level: 31
+xp: 70
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [emerald]
+ qty: 1
+ - items: [amulet_mould]
+ qty: 1
+ byproducts: [amulet_mould]
+output: emerald_amulet_u
+message: "You cast a emerald amulet."
diff --git a/data/recipes/craft_emerald_bracelet.yaml b/data/recipes/craft_emerald_bracelet.yaml
new file mode 100644
index 0000000..b3dd83e
--- /dev/null
+++ b/data/recipes/craft_emerald_bracelet.yaml
@@ -0,0 +1,16 @@
+id: craft_emerald_bracelet
+type: crafting
+level: 30
+xp: 65
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [emerald]
+ qty: 1
+ - items: [bracelet_mould]
+ qty: 1
+ byproducts: [bracelet_mould]
+output: emerald_bracelet
+message: "You cast a emerald bracelet."
diff --git a/data/recipes/craft_emerald_necklace.yaml b/data/recipes/craft_emerald_necklace.yaml
new file mode 100644
index 0000000..cd0a94b
--- /dev/null
+++ b/data/recipes/craft_emerald_necklace.yaml
@@ -0,0 +1,16 @@
+id: craft_emerald_necklace
+type: crafting
+level: 29
+xp: 60
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [emerald]
+ qty: 1
+ - items: [necklace_mould]
+ qty: 1
+ byproducts: [necklace_mould]
+output: emerald_necklace
+message: "You cast a emerald necklace."
diff --git a/data/recipes/craft_emerald_ring.yaml b/data/recipes/craft_emerald_ring.yaml
new file mode 100644
index 0000000..ebbe473
--- /dev/null
+++ b/data/recipes/craft_emerald_ring.yaml
@@ -0,0 +1,16 @@
+id: craft_emerald_ring
+type: crafting
+level: 27
+xp: 55
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [emerald]
+ qty: 1
+ - items: [ring_mould]
+ qty: 1
+ byproducts: [ring_mould]
+output: emerald_ring
+message: "You cast a emerald ring."
diff --git a/data/recipes/craft_gold_amulet_u.yaml b/data/recipes/craft_gold_amulet_u.yaml
new file mode 100644
index 0000000..3701320
--- /dev/null
+++ b/data/recipes/craft_gold_amulet_u.yaml
@@ -0,0 +1,14 @@
+id: craft_gold_amulet_u
+type: crafting
+level: 8
+xp: 30
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [amulet_mould]
+ qty: 1
+ byproducts: [amulet_mould]
+output: gold_amulet_u
+message: "You cast a gold amulet."
diff --git a/data/recipes/craft_gold_bracelet.yaml b/data/recipes/craft_gold_bracelet.yaml
new file mode 100644
index 0000000..630b8de
--- /dev/null
+++ b/data/recipes/craft_gold_bracelet.yaml
@@ -0,0 +1,14 @@
+id: craft_gold_bracelet
+type: crafting
+level: 7
+xp: 25
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [bracelet_mould]
+ qty: 1
+ byproducts: [bracelet_mould]
+output: gold_bracelet
+message: "You cast a gold bracelet."
diff --git a/data/recipes/craft_gold_necklace.yaml b/data/recipes/craft_gold_necklace.yaml
new file mode 100644
index 0000000..6879338
--- /dev/null
+++ b/data/recipes/craft_gold_necklace.yaml
@@ -0,0 +1,14 @@
+id: craft_gold_necklace
+type: crafting
+level: 6
+xp: 20
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [necklace_mould]
+ qty: 1
+ byproducts: [necklace_mould]
+output: gold_necklace
+message: "You cast a gold necklace."
diff --git a/data/recipes/craft_gold_ring.yaml b/data/recipes/craft_gold_ring.yaml
new file mode 100644
index 0000000..4e2c13f
--- /dev/null
+++ b/data/recipes/craft_gold_ring.yaml
@@ -0,0 +1,14 @@
+id: craft_gold_ring
+type: crafting
+level: 5
+xp: 15
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [ring_mould]
+ qty: 1
+ byproducts: [ring_mould]
+output: gold_ring
+message: "You cast a gold ring."
diff --git a/data/recipes/craft_hard_leather_body.yaml b/data/recipes/craft_hard_leather_body.yaml
new file mode 100644
index 0000000..088553e
--- /dev/null
+++ b/data/recipes/craft_hard_leather_body.yaml
@@ -0,0 +1,13 @@
+id: craft_hard_leather_body
+type: crafting
+level: 28
+xp: 35
+wait: 4
+tool: needle
+consume:
+ - items: [hard_leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: hard_leather_body
+message: "You craft a hard leather body."
diff --git a/data/recipes/craft_hard_leather_shield.yaml b/data/recipes/craft_hard_leather_shield.yaml
new file mode 100644
index 0000000..b41e5b4
--- /dev/null
+++ b/data/recipes/craft_hard_leather_shield.yaml
@@ -0,0 +1,13 @@
+id: craft_hard_leather_shield
+type: crafting
+level: 41
+xp: 40
+wait: 4
+tool: needle
+consume:
+ - items: [hard_leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: hard_leather_shield
+message: "You craft a hard leather shield."
diff --git a/data/recipes/craft_leather_body.yaml b/data/recipes/craft_leather_body.yaml
new file mode 100644
index 0000000..b01eefa
--- /dev/null
+++ b/data/recipes/craft_leather_body.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_body
+type: crafting
+level: 14
+xp: 25
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_body
+message: "You craft a leather body."
diff --git a/data/recipes/craft_leather_boots.yaml b/data/recipes/craft_leather_boots.yaml
new file mode 100644
index 0000000..df86ae9
--- /dev/null
+++ b/data/recipes/craft_leather_boots.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_boots
+type: crafting
+level: 7
+xp: 16
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_boots
+message: "You craft a pair of leather boots."
diff --git a/data/recipes/craft_leather_chaps.yaml b/data/recipes/craft_leather_chaps.yaml
new file mode 100644
index 0000000..bfbb832
--- /dev/null
+++ b/data/recipes/craft_leather_chaps.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_chaps
+type: crafting
+level: 18
+xp: 27
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_chaps
+message: "You craft a pair of leather chaps."
diff --git a/data/recipes/craft_leather_cowl.yaml b/data/recipes/craft_leather_cowl.yaml
new file mode 100644
index 0000000..7f018bf
--- /dev/null
+++ b/data/recipes/craft_leather_cowl.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_cowl
+type: crafting
+level: 9
+xp: 19
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_cowl
+message: "You craft a leather cowl."
diff --git a/data/recipes/craft_leather_gloves.yaml b/data/recipes/craft_leather_gloves.yaml
new file mode 100644
index 0000000..4f6b27c
--- /dev/null
+++ b/data/recipes/craft_leather_gloves.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_gloves
+type: crafting
+level: 1
+xp: 14
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_gloves
+message: "You craft a pair of leather gloves."
diff --git a/data/recipes/craft_leather_vambraces.yaml b/data/recipes/craft_leather_vambraces.yaml
new file mode 100644
index 0000000..44624c9
--- /dev/null
+++ b/data/recipes/craft_leather_vambraces.yaml
@@ -0,0 +1,13 @@
+id: craft_leather_vambraces
+type: crafting
+level: 11
+xp: 22
+wait: 4
+tool: needle
+consume:
+ - items: [leather]
+ qty: 1
+ - items: [thread]
+ qty: 1
+output: leather_vambraces
+message: "You craft a pair of leather vambraces."
diff --git a/data/recipes/craft_pie_dish.yaml b/data/recipes/craft_pie_dish.yaml
new file mode 100644
index 0000000..0648dd5
--- /dev/null
+++ b/data/recipes/craft_pie_dish.yaml
@@ -0,0 +1,16 @@
+id: craft_pie_dish
+type: crafting
+level: 7
+xp: 10
+wait: 4
+station: [pottery_oven]
+consume:
+ - items: [unfired_pie_dish]
+ qty: 1
+output: pie_dish
+message: "You fire the pie dish in the oven successfully."
+fail_message: "The pie dish cracks in the oven and is ruined."
+success:
+ base: 0.40
+ per_level: 0.02
+ cap: 0.95
diff --git a/data/recipes/craft_plant_pot.yaml b/data/recipes/craft_plant_pot.yaml
new file mode 100644
index 0000000..efa353c
--- /dev/null
+++ b/data/recipes/craft_plant_pot.yaml
@@ -0,0 +1,16 @@
+id: craft_plant_pot
+type: crafting
+level: 19
+xp: 18
+wait: 4
+station: [pottery_oven]
+consume:
+ - items: [unfired_plant_pot]
+ qty: 1
+output: plant_pot
+message: "You fire the plant pot in the oven successfully."
+fail_message: "The plant pot cracks in the oven and is ruined."
+success:
+ base: 0.30
+ per_level: 0.02
+ cap: 0.95
diff --git a/data/recipes/craft_pot.yaml b/data/recipes/craft_pot.yaml
new file mode 100644
index 0000000..4e7a5ce
--- /dev/null
+++ b/data/recipes/craft_pot.yaml
@@ -0,0 +1,16 @@
+id: craft_pot
+type: crafting
+level: 1
+xp: 6
+wait: 4
+station: [pottery_oven]
+consume:
+ - items: [unfired_pot]
+ qty: 1
+output: empty_pot
+message: "You fire the pot in the oven successfully."
+fail_message: "The pot cracks in the oven and is ruined."
+success:
+ base: 0.50
+ per_level: 0.02
+ cap: 0.95
diff --git a/data/recipes/craft_ruby_amulet_u.yaml b/data/recipes/craft_ruby_amulet_u.yaml
new file mode 100644
index 0000000..4f1fbea
--- /dev/null
+++ b/data/recipes/craft_ruby_amulet_u.yaml
@@ -0,0 +1,16 @@
+id: craft_ruby_amulet_u
+type: crafting
+level: 50
+xp: 85
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [ruby]
+ qty: 1
+ - items: [amulet_mould]
+ qty: 1
+ byproducts: [amulet_mould]
+output: ruby_amulet_u
+message: "You cast a ruby amulet."
diff --git a/data/recipes/craft_ruby_bracelet.yaml b/data/recipes/craft_ruby_bracelet.yaml
new file mode 100644
index 0000000..c5e0027
--- /dev/null
+++ b/data/recipes/craft_ruby_bracelet.yaml
@@ -0,0 +1,16 @@
+id: craft_ruby_bracelet
+type: crafting
+level: 42
+xp: 80
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [ruby]
+ qty: 1
+ - items: [bracelet_mould]
+ qty: 1
+ byproducts: [bracelet_mould]
+output: ruby_bracelet
+message: "You cast a ruby bracelet."
diff --git a/data/recipes/craft_ruby_necklace.yaml b/data/recipes/craft_ruby_necklace.yaml
new file mode 100644
index 0000000..4504f7b
--- /dev/null
+++ b/data/recipes/craft_ruby_necklace.yaml
@@ -0,0 +1,16 @@
+id: craft_ruby_necklace
+type: crafting
+level: 40
+xp: 75
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [ruby]
+ qty: 1
+ - items: [necklace_mould]
+ qty: 1
+ byproducts: [necklace_mould]
+output: ruby_necklace
+message: "You cast a ruby necklace."
diff --git a/data/recipes/craft_ruby_ring.yaml b/data/recipes/craft_ruby_ring.yaml
new file mode 100644
index 0000000..e38a490
--- /dev/null
+++ b/data/recipes/craft_ruby_ring.yaml
@@ -0,0 +1,16 @@
+id: craft_ruby_ring
+type: crafting
+level: 63
+xp: 70
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [ruby]
+ qty: 1
+ - items: [ring_mould]
+ qty: 1
+ byproducts: [ring_mould]
+output: ruby_ring
+message: "You cast a ruby ring."
diff --git a/data/recipes/craft_sapphire_amulet_u.yaml b/data/recipes/craft_sapphire_amulet_u.yaml
new file mode 100644
index 0000000..a15a484
--- /dev/null
+++ b/data/recipes/craft_sapphire_amulet_u.yaml
@@ -0,0 +1,16 @@
+id: craft_sapphire_amulet_u
+type: crafting
+level: 24
+xp: 65
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [sapphire]
+ qty: 1
+ - items: [amulet_mould]
+ qty: 1
+ byproducts: [amulet_mould]
+output: sapphire_amulet_u
+message: "You cast a sapphire amulet."
diff --git a/data/recipes/craft_sapphire_bracelet.yaml b/data/recipes/craft_sapphire_bracelet.yaml
new file mode 100644
index 0000000..ee5d1a7
--- /dev/null
+++ b/data/recipes/craft_sapphire_bracelet.yaml
@@ -0,0 +1,16 @@
+id: craft_sapphire_bracelet
+type: crafting
+level: 23
+xp: 60
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [sapphire]
+ qty: 1
+ - items: [bracelet_mould]
+ qty: 1
+ byproducts: [bracelet_mould]
+output: sapphire_bracelet
+message: "You cast a sapphire bracelet."
diff --git a/data/recipes/craft_sapphire_necklace.yaml b/data/recipes/craft_sapphire_necklace.yaml
new file mode 100644
index 0000000..1dfd112
--- /dev/null
+++ b/data/recipes/craft_sapphire_necklace.yaml
@@ -0,0 +1,16 @@
+id: craft_sapphire_necklace
+type: crafting
+level: 22
+xp: 55
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [sapphire]
+ qty: 1
+ - items: [necklace_mould]
+ qty: 1
+ byproducts: [necklace_mould]
+output: sapphire_necklace
+message: "You cast a sapphire necklace."
diff --git a/data/recipes/craft_sapphire_ring.yaml b/data/recipes/craft_sapphire_ring.yaml
new file mode 100644
index 0000000..dd793ac
--- /dev/null
+++ b/data/recipes/craft_sapphire_ring.yaml
@@ -0,0 +1,16 @@
+id: craft_sapphire_ring
+type: crafting
+level: 20
+xp: 40
+wait: 4
+station: [furnace]
+consume:
+ - items: [gold_bar]
+ qty: 1
+ - items: [sapphire]
+ qty: 1
+ - items: [ring_mould]
+ qty: 1
+ byproducts: [ring_mould]
+output: sapphire_ring
+message: "You cast a sapphire ring."
diff --git a/data/recipes/craft_unfired_pie_dish.yaml b/data/recipes/craft_unfired_pie_dish.yaml
new file mode 100644
index 0000000..e55d47e
--- /dev/null
+++ b/data/recipes/craft_unfired_pie_dish.yaml
@@ -0,0 +1,11 @@
+id: craft_unfired_pie_dish
+type: crafting
+level: 7
+xp: 15
+wait: 4
+station: [pottery_wheel]
+consume:
+ - items: [soft_clay]
+ qty: 1
+output: unfired_pie_dish
+message: "You shape the clay into a pie dish."
diff --git a/data/recipes/craft_unfired_plant_pot.yaml b/data/recipes/craft_unfired_plant_pot.yaml
new file mode 100644
index 0000000..6dbd8ef
--- /dev/null
+++ b/data/recipes/craft_unfired_plant_pot.yaml
@@ -0,0 +1,11 @@
+id: craft_unfired_plant_pot
+type: crafting
+level: 19
+xp: 18
+wait: 4
+station: [pottery_wheel]
+consume:
+ - items: [soft_clay]
+ qty: 1
+output: unfired_plant_pot
+message: "You shape the clay into a plant pot."
diff --git a/data/recipes/craft_unfired_pot.yaml b/data/recipes/craft_unfired_pot.yaml
new file mode 100644
index 0000000..8d72be0
--- /dev/null
+++ b/data/recipes/craft_unfired_pot.yaml
@@ -0,0 +1,11 @@
+id: craft_unfired_pot
+type: crafting
+level: 1
+xp: 6
+wait: 4
+station: [pottery_wheel]
+consume:
+ - items: [soft_clay]
+ qty: 1
+output: unfired_pot
+message: "You shape the clay into a pot."
diff --git a/data/recipes/fletch_adamant_arrow.yaml b/data/recipes/fletch_adamant_arrow.yaml
index a43a9b9..0166c99 100644
--- a/data/recipes/fletch_adamant_arrow.yaml
+++ b/data/recipes/fletch_adamant_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_adamant_arrow
type: fletching
-skill: fletching
level: 60
xp: 10
wait: 2
diff --git a/data/recipes/fletch_adamant_bolts.yaml b/data/recipes/fletch_adamant_bolts.yaml
index c924fe8..46aa57f 100644
--- a/data/recipes/fletch_adamant_bolts.yaml
+++ b/data/recipes/fletch_adamant_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_adamant_bolts
type: fletching
-skill: fletching
level: 61
xp: 70
wait: 0
diff --git a/data/recipes/fletch_arrow_shaft.yaml b/data/recipes/fletch_arrow_shaft.yaml
index fb211b8..b2d3c81 100644
--- a/data/recipes/fletch_arrow_shaft.yaml
+++ b/data/recipes/fletch_arrow_shaft.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft
type: fletching
-skill: fletching
+tool: knife
level: 1
xp: 5
wait: 5
diff --git a/data/recipes/fletch_arrow_shaft_magic.yaml b/data/recipes/fletch_arrow_shaft_magic.yaml
index a6a8214..b72c4b8 100644
--- a/data/recipes/fletch_arrow_shaft_magic.yaml
+++ b/data/recipes/fletch_arrow_shaft_magic.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft_magic
type: fletching
-skill: fletching
+tool: knife
level: 75
xp: 30
wait: 5
diff --git a/data/recipes/fletch_arrow_shaft_maple.yaml b/data/recipes/fletch_arrow_shaft_maple.yaml
index 5bdcdb2..aa9fea6 100644
--- a/data/recipes/fletch_arrow_shaft_maple.yaml
+++ b/data/recipes/fletch_arrow_shaft_maple.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft_maple
type: fletching
-skill: fletching
+tool: knife
level: 45
xp: 20
wait: 5
diff --git a/data/recipes/fletch_arrow_shaft_oak.yaml b/data/recipes/fletch_arrow_shaft_oak.yaml
index b72ed13..1940e87 100644
--- a/data/recipes/fletch_arrow_shaft_oak.yaml
+++ b/data/recipes/fletch_arrow_shaft_oak.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft_oak
type: fletching
-skill: fletching
+tool: knife
level: 15
xp: 10
wait: 5
diff --git a/data/recipes/fletch_arrow_shaft_willow.yaml b/data/recipes/fletch_arrow_shaft_willow.yaml
index fe1ded6..986ffae 100644
--- a/data/recipes/fletch_arrow_shaft_willow.yaml
+++ b/data/recipes/fletch_arrow_shaft_willow.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft_willow
type: fletching
-skill: fletching
+tool: knife
level: 30
xp: 15
wait: 5
diff --git a/data/recipes/fletch_arrow_shaft_yew.yaml b/data/recipes/fletch_arrow_shaft_yew.yaml
index c946c76..bc7775e 100644
--- a/data/recipes/fletch_arrow_shaft_yew.yaml
+++ b/data/recipes/fletch_arrow_shaft_yew.yaml
@@ -1,6 +1,6 @@
id: fletch_arrow_shaft_yew
type: fletching
-skill: fletching
+tool: knife
level: 60
xp: 25
wait: 5
diff --git a/data/recipes/fletch_bronze_arrow.yaml b/data/recipes/fletch_bronze_arrow.yaml
index 51922a8..4cc7aca 100644
--- a/data/recipes/fletch_bronze_arrow.yaml
+++ b/data/recipes/fletch_bronze_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_bronze_arrow
type: fletching
-skill: fletching
level: 1
xp: 1
wait: 2
diff --git a/data/recipes/fletch_bronze_bolts.yaml b/data/recipes/fletch_bronze_bolts.yaml
index c48602f..f10595a 100644
--- a/data/recipes/fletch_bronze_bolts.yaml
+++ b/data/recipes/fletch_bronze_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_bronze_bolts
type: fletching
-skill: fletching
level: 9
xp: 5
wait: 0
diff --git a/data/recipes/fletch_diamond_bolt_tips.yaml b/data/recipes/fletch_diamond_bolt_tips.yaml
index 961aec0..dc57964 100644
--- a/data/recipes/fletch_diamond_bolt_tips.yaml
+++ b/data/recipes/fletch_diamond_bolt_tips.yaml
@@ -1,6 +1,6 @@
id: fletch_diamond_bolt_tips
type: fletching
-skill: fletching
+tool: chisel
level: 65
xp: 7
wait: 5
diff --git a/data/recipes/fletch_diamond_bolts.yaml b/data/recipes/fletch_diamond_bolts.yaml
index 2b47268..7b0a460 100644
--- a/data/recipes/fletch_diamond_bolts.yaml
+++ b/data/recipes/fletch_diamond_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_diamond_bolts
type: fletching
-skill: fletching
level: 65
xp: 7
wait: 2
diff --git a/data/recipes/fletch_emerald_bolt_tips.yaml b/data/recipes/fletch_emerald_bolt_tips.yaml
index d2f58a0..b7d78a5 100644
--- a/data/recipes/fletch_emerald_bolt_tips.yaml
+++ b/data/recipes/fletch_emerald_bolt_tips.yaml
@@ -1,6 +1,6 @@
id: fletch_emerald_bolt_tips
type: fletching
-skill: fletching
+tool: chisel
level: 66
xp: 5
wait: 5
diff --git a/data/recipes/fletch_emerald_bolts.yaml b/data/recipes/fletch_emerald_bolts.yaml
index cf80e64..353432a 100644
--- a/data/recipes/fletch_emerald_bolts.yaml
+++ b/data/recipes/fletch_emerald_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_emerald_bolts
type: fletching
-skill: fletching
level: 66
xp: 5
wait: 2
diff --git a/data/recipes/fletch_headless_arrow.yaml b/data/recipes/fletch_headless_arrow.yaml
index 8229369..3016430 100644
--- a/data/recipes/fletch_headless_arrow.yaml
+++ b/data/recipes/fletch_headless_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_headless_arrow
type: fletching
-skill: fletching
level: 1
xp: 1
wait: 2
diff --git a/data/recipes/fletch_iron_arrow.yaml b/data/recipes/fletch_iron_arrow.yaml
index 0e2f81b..2727ca1 100644
--- a/data/recipes/fletch_iron_arrow.yaml
+++ b/data/recipes/fletch_iron_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_iron_arrow
type: fletching
-skill: fletching
level: 15
xp: 2
wait: 2
diff --git a/data/recipes/fletch_iron_bolts.yaml b/data/recipes/fletch_iron_bolts.yaml
index d06ecd5..44a623f 100644
--- a/data/recipes/fletch_iron_bolts.yaml
+++ b/data/recipes/fletch_iron_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_iron_bolts
type: fletching
-skill: fletching
level: 39
xp: 15
wait: 0
diff --git a/data/recipes/fletch_longbow.yaml b/data/recipes/fletch_longbow.yaml
index 8507dc9..392ccfb 100644
--- a/data/recipes/fletch_longbow.yaml
+++ b/data/recipes/fletch_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_longbow
type: fletching
-skill: fletching
level: 10
xp: 10
wait: 2
diff --git a/data/recipes/fletch_longbow_u.yaml b/data/recipes/fletch_longbow_u.yaml
index 1aeeaa9..e836a9e 100644
--- a/data/recipes/fletch_longbow_u.yaml
+++ b/data/recipes/fletch_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 10
xp: 10
wait: 3
diff --git a/data/recipes/fletch_magic_longbow.yaml b/data/recipes/fletch_magic_longbow.yaml
index b8a0cb6..c8cc0d4 100644
--- a/data/recipes/fletch_magic_longbow.yaml
+++ b/data/recipes/fletch_magic_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_magic_longbow
type: fletching
-skill: fletching
level: 85
xp: 91
wait: 2
diff --git a/data/recipes/fletch_magic_longbow_u.yaml b/data/recipes/fletch_magic_longbow_u.yaml
index 9b4662b..19eddc8 100644
--- a/data/recipes/fletch_magic_longbow_u.yaml
+++ b/data/recipes/fletch_magic_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_magic_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 85
xp: 91
wait: 3
diff --git a/data/recipes/fletch_magic_shortbow.yaml b/data/recipes/fletch_magic_shortbow.yaml
index 9d6a94f..b9b3bb2 100644
--- a/data/recipes/fletch_magic_shortbow.yaml
+++ b/data/recipes/fletch_magic_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_magic_shortbow
type: fletching
-skill: fletching
level: 80
xp: 83
wait: 2
diff --git a/data/recipes/fletch_magic_shortbow_u.yaml b/data/recipes/fletch_magic_shortbow_u.yaml
index dabfaf7..e9f2e38 100644
--- a/data/recipes/fletch_magic_shortbow_u.yaml
+++ b/data/recipes/fletch_magic_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_magic_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 80
xp: 83
wait: 3
diff --git a/data/recipes/fletch_maple_longbow.yaml b/data/recipes/fletch_maple_longbow.yaml
index b90a4fd..1ecfb74 100644
--- a/data/recipes/fletch_maple_longbow.yaml
+++ b/data/recipes/fletch_maple_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_maple_longbow
type: fletching
-skill: fletching
level: 55
xp: 58
wait: 2
diff --git a/data/recipes/fletch_maple_longbow_u.yaml b/data/recipes/fletch_maple_longbow_u.yaml
index 8e34a4d..981c6e0 100644
--- a/data/recipes/fletch_maple_longbow_u.yaml
+++ b/data/recipes/fletch_maple_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_maple_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 55
xp: 58
wait: 3
diff --git a/data/recipes/fletch_maple_shortbow.yaml b/data/recipes/fletch_maple_shortbow.yaml
index d623cc6..844a080 100644
--- a/data/recipes/fletch_maple_shortbow.yaml
+++ b/data/recipes/fletch_maple_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_maple_shortbow
type: fletching
-skill: fletching
level: 50
xp: 50
wait: 2
diff --git a/data/recipes/fletch_maple_shortbow_u.yaml b/data/recipes/fletch_maple_shortbow_u.yaml
index 9a44d9a..56dc15c 100644
--- a/data/recipes/fletch_maple_shortbow_u.yaml
+++ b/data/recipes/fletch_maple_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_maple_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 50
xp: 50
wait: 3
diff --git a/data/recipes/fletch_mithril_arrow.yaml b/data/recipes/fletch_mithril_arrow.yaml
index 5c948b8..1d03823 100644
--- a/data/recipes/fletch_mithril_arrow.yaml
+++ b/data/recipes/fletch_mithril_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_mithril_arrow
type: fletching
-skill: fletching
level: 45
xp: 7
wait: 2
diff --git a/data/recipes/fletch_mithril_bolts.yaml b/data/recipes/fletch_mithril_bolts.yaml
index f695a90..90e85a8 100644
--- a/data/recipes/fletch_mithril_bolts.yaml
+++ b/data/recipes/fletch_mithril_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_mithril_bolts
type: fletching
-skill: fletching
level: 54
xp: 50
wait: 0
diff --git a/data/recipes/fletch_oak_longbow.yaml b/data/recipes/fletch_oak_longbow.yaml
index 3e48fe5..39b72d8 100644
--- a/data/recipes/fletch_oak_longbow.yaml
+++ b/data/recipes/fletch_oak_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_oak_longbow
type: fletching
-skill: fletching
level: 25
xp: 25
wait: 2
diff --git a/data/recipes/fletch_oak_longbow_u.yaml b/data/recipes/fletch_oak_longbow_u.yaml
index 9127fff..733c227 100644
--- a/data/recipes/fletch_oak_longbow_u.yaml
+++ b/data/recipes/fletch_oak_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_oak_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 25
xp: 25
wait: 3
diff --git a/data/recipes/fletch_oak_shortbow.yaml b/data/recipes/fletch_oak_shortbow.yaml
index 96f70b0..ade20ff 100644
--- a/data/recipes/fletch_oak_shortbow.yaml
+++ b/data/recipes/fletch_oak_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_oak_shortbow
type: fletching
-skill: fletching
level: 20
xp: 16
wait: 2
diff --git a/data/recipes/fletch_oak_shortbow_u.yaml b/data/recipes/fletch_oak_shortbow_u.yaml
index 03cffb3..d994a77 100644
--- a/data/recipes/fletch_oak_shortbow_u.yaml
+++ b/data/recipes/fletch_oak_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_oak_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 20
xp: 16
wait: 3
diff --git a/data/recipes/fletch_ruby_bolt_tips.yaml b/data/recipes/fletch_ruby_bolt_tips.yaml
index 976bc3a..293a840 100644
--- a/data/recipes/fletch_ruby_bolt_tips.yaml
+++ b/data/recipes/fletch_ruby_bolt_tips.yaml
@@ -1,6 +1,6 @@
id: fletch_ruby_bolt_tips
type: fletching
-skill: fletching
+tool: chisel
level: 73
xp: 6
wait: 5
diff --git a/data/recipes/fletch_ruby_bolts.yaml b/data/recipes/fletch_ruby_bolts.yaml
index fe1b987..1fdac70 100644
--- a/data/recipes/fletch_ruby_bolts.yaml
+++ b/data/recipes/fletch_ruby_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_ruby_bolts
type: fletching
-skill: fletching
level: 73
xp: 6
wait: 2
diff --git a/data/recipes/fletch_rune_arrow.yaml b/data/recipes/fletch_rune_arrow.yaml
index 61a6bab..a208bce 100644
--- a/data/recipes/fletch_rune_arrow.yaml
+++ b/data/recipes/fletch_rune_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_rune_arrow
type: fletching
-skill: fletching
level: 75
xp: 12
wait: 2
diff --git a/data/recipes/fletch_rune_bolts.yaml b/data/recipes/fletch_rune_bolts.yaml
index 9d016a6..6073d7f 100644
--- a/data/recipes/fletch_rune_bolts.yaml
+++ b/data/recipes/fletch_rune_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_rune_bolts
type: fletching
-skill: fletching
level: 69
xp: 100
wait: 0
diff --git a/data/recipes/fletch_sapphire_bolt_tips.yaml b/data/recipes/fletch_sapphire_bolt_tips.yaml
index f78db3e..353d1de 100644
--- a/data/recipes/fletch_sapphire_bolt_tips.yaml
+++ b/data/recipes/fletch_sapphire_bolt_tips.yaml
@@ -1,6 +1,6 @@
id: fletch_sapphire_bolt_tips
type: fletching
-skill: fletching
+tool: chisel
level: 63
xp: 4
wait: 5
diff --git a/data/recipes/fletch_sapphire_bolts.yaml b/data/recipes/fletch_sapphire_bolts.yaml
index b678d5a..503809a 100644
--- a/data/recipes/fletch_sapphire_bolts.yaml
+++ b/data/recipes/fletch_sapphire_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_sapphire_bolts
type: fletching
-skill: fletching
level: 63
xp: 4
wait: 2
diff --git a/data/recipes/fletch_shortbow.yaml b/data/recipes/fletch_shortbow.yaml
index ae5e196..0911aa2 100644
--- a/data/recipes/fletch_shortbow.yaml
+++ b/data/recipes/fletch_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_shortbow
type: fletching
-skill: fletching
level: 5
xp: 5
wait: 2
diff --git a/data/recipes/fletch_shortbow_u.yaml b/data/recipes/fletch_shortbow_u.yaml
index b8f3654..bda2a93 100644
--- a/data/recipes/fletch_shortbow_u.yaml
+++ b/data/recipes/fletch_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 5
xp: 5
wait: 3
diff --git a/data/recipes/fletch_steel_arrow.yaml b/data/recipes/fletch_steel_arrow.yaml
index 98a4d70..fc28d21 100644
--- a/data/recipes/fletch_steel_arrow.yaml
+++ b/data/recipes/fletch_steel_arrow.yaml
@@ -1,6 +1,5 @@
id: fletch_steel_arrow
type: fletching
-skill: fletching
level: 30
xp: 5
wait: 2
diff --git a/data/recipes/fletch_steel_bolts.yaml b/data/recipes/fletch_steel_bolts.yaml
index ed4d4c2..156b6e0 100644
--- a/data/recipes/fletch_steel_bolts.yaml
+++ b/data/recipes/fletch_steel_bolts.yaml
@@ -1,6 +1,5 @@
id: fletch_steel_bolts
type: fletching
-skill: fletching
level: 46
xp: 35
wait: 0
diff --git a/data/recipes/fletch_willow_longbow.yaml b/data/recipes/fletch_willow_longbow.yaml
index 6015c00..6f4a9c0 100644
--- a/data/recipes/fletch_willow_longbow.yaml
+++ b/data/recipes/fletch_willow_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_willow_longbow
type: fletching
-skill: fletching
level: 40
xp: 41
wait: 2
diff --git a/data/recipes/fletch_willow_longbow_u.yaml b/data/recipes/fletch_willow_longbow_u.yaml
index 336ae51..5afbe89 100644
--- a/data/recipes/fletch_willow_longbow_u.yaml
+++ b/data/recipes/fletch_willow_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_willow_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 40
xp: 41
wait: 3
diff --git a/data/recipes/fletch_willow_shortbow.yaml b/data/recipes/fletch_willow_shortbow.yaml
index 028132f..e6d044f 100644
--- a/data/recipes/fletch_willow_shortbow.yaml
+++ b/data/recipes/fletch_willow_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_willow_shortbow
type: fletching
-skill: fletching
level: 35
xp: 33
wait: 2
diff --git a/data/recipes/fletch_willow_shortbow_u.yaml b/data/recipes/fletch_willow_shortbow_u.yaml
index 2eb7499..b0fb490 100644
--- a/data/recipes/fletch_willow_shortbow_u.yaml
+++ b/data/recipes/fletch_willow_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_willow_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 35
xp: 33
wait: 3
diff --git a/data/recipes/fletch_yew_longbow.yaml b/data/recipes/fletch_yew_longbow.yaml
index 26df51b..34b6a79 100644
--- a/data/recipes/fletch_yew_longbow.yaml
+++ b/data/recipes/fletch_yew_longbow.yaml
@@ -1,6 +1,5 @@
id: fletch_yew_longbow
type: fletching
-skill: fletching
level: 65
xp: 75
wait: 2
diff --git a/data/recipes/fletch_yew_longbow_u.yaml b/data/recipes/fletch_yew_longbow_u.yaml
index fa7b3b0..c5abe34 100644
--- a/data/recipes/fletch_yew_longbow_u.yaml
+++ b/data/recipes/fletch_yew_longbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_yew_longbow_u
type: fletching
-skill: fletching
+tool: knife
level: 65
xp: 75
wait: 3
diff --git a/data/recipes/fletch_yew_shortbow.yaml b/data/recipes/fletch_yew_shortbow.yaml
index c54bba0..2dac064 100644
--- a/data/recipes/fletch_yew_shortbow.yaml
+++ b/data/recipes/fletch_yew_shortbow.yaml
@@ -1,6 +1,5 @@
id: fletch_yew_shortbow
type: fletching
-skill: fletching
level: 60
xp: 67
wait: 2
diff --git a/data/recipes/fletch_yew_shortbow_u.yaml b/data/recipes/fletch_yew_shortbow_u.yaml
index 48877de..4b61a38 100644
--- a/data/recipes/fletch_yew_shortbow_u.yaml
+++ b/data/recipes/fletch_yew_shortbow_u.yaml
@@ -1,6 +1,6 @@
id: fletch_yew_shortbow_u
type: fletching
-skill: fletching
+tool: knife
level: 60
xp: 67
wait: 3
diff --git a/data/recipes/smith_adamant_arrowtips.yaml b/data/recipes/smith_adamant_arrowtips.yaml
index 464feae..6ad49d7 100644
--- a/data/recipes/smith_adamant_arrowtips.yaml
+++ b/data/recipes/smith_adamant_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_arrowtips
type: smithing
-skill: smithing
level: 75
xp: 62
wait: 4
diff --git a/data/recipes/smith_adamant_bolts_unf.yaml b/data/recipes/smith_adamant_bolts_unf.yaml
index 4bf30bf..9e71a5c 100644
--- a/data/recipes/smith_adamant_bolts_unf.yaml
+++ b/data/recipes/smith_adamant_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_bolts_unf
type: smithing
-skill: smithing
level: 76
xp: 62
wait: 4
diff --git a/data/recipes/smith_adamant_dagger.yaml b/data/recipes/smith_adamant_dagger.yaml
index 38692b8..8d5f6d2 100644
--- a/data/recipes/smith_adamant_dagger.yaml
+++ b/data/recipes/smith_adamant_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_dagger
type: smithing
-skill: smithing
level: 70
xp: 62
wait: 4
diff --git a/data/recipes/smith_adamant_full_helm.yaml b/data/recipes/smith_adamant_full_helm.yaml
index b478da2..61a79b0 100644
--- a/data/recipes/smith_adamant_full_helm.yaml
+++ b/data/recipes/smith_adamant_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_full_helm
type: smithing
-skill: smithing
level: 77
xp: 125
wait: 4
diff --git a/data/recipes/smith_adamant_med_helm.yaml b/data/recipes/smith_adamant_med_helm.yaml
index 064064f..275adaf 100644
--- a/data/recipes/smith_adamant_med_helm.yaml
+++ b/data/recipes/smith_adamant_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_med_helm
type: smithing
-skill: smithing
level: 73
xp: 62
wait: 4
diff --git a/data/recipes/smith_adamant_nails.yaml b/data/recipes/smith_adamant_nails.yaml
index 418c277..195cbb1 100644
--- a/data/recipes/smith_adamant_nails.yaml
+++ b/data/recipes/smith_adamant_nails.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_nails
type: smithing
-skill: smithing
level: 74
xp: 62
wait: 4
diff --git a/data/recipes/smith_adamant_platebody.yaml b/data/recipes/smith_adamant_platebody.yaml
index 81ad87d..abd5284 100644
--- a/data/recipes/smith_adamant_platebody.yaml
+++ b/data/recipes/smith_adamant_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_platebody
type: smithing
-skill: smithing
level: 88
xp: 312
wait: 4
diff --git a/data/recipes/smith_adamant_sword.yaml b/data/recipes/smith_adamant_sword.yaml
index 1071623..c973310 100644
--- a/data/recipes/smith_adamant_sword.yaml
+++ b/data/recipes/smith_adamant_sword.yaml
@@ -1,6 +1,5 @@
id: smith_adamant_sword
type: smithing
-skill: smithing
level: 74
xp: 62
wait: 4
diff --git a/data/recipes/smith_bronze_arrowtips.yaml b/data/recipes/smith_bronze_arrowtips.yaml
index 1f29a33..4b74869 100644
--- a/data/recipes/smith_bronze_arrowtips.yaml
+++ b/data/recipes/smith_bronze_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_arrowtips
type: smithing
-skill: smithing
level: 5
xp: 12
wait: 4
diff --git a/data/recipes/smith_bronze_bolts_unf.yaml b/data/recipes/smith_bronze_bolts_unf.yaml
index f43218a..349be84 100644
--- a/data/recipes/smith_bronze_bolts_unf.yaml
+++ b/data/recipes/smith_bronze_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_bolts_unf
type: smithing
-skill: smithing
level: 6
xp: 12
wait: 4
diff --git a/data/recipes/smith_bronze_dagger.yaml b/data/recipes/smith_bronze_dagger.yaml
index 4c6bfa9..fc458c8 100644
--- a/data/recipes/smith_bronze_dagger.yaml
+++ b/data/recipes/smith_bronze_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_dagger
type: smithing
-skill: smithing
level: 1
xp: 12
wait: 4
diff --git a/data/recipes/smith_bronze_full_helm.yaml b/data/recipes/smith_bronze_full_helm.yaml
index 159efdb..cd689fd 100644
--- a/data/recipes/smith_bronze_full_helm.yaml
+++ b/data/recipes/smith_bronze_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_full_helm
type: smithing
-skill: smithing
level: 7
xp: 25
wait: 4
diff --git a/data/recipes/smith_bronze_med_helm.yaml b/data/recipes/smith_bronze_med_helm.yaml
index 7b6f248..60e1353 100644
--- a/data/recipes/smith_bronze_med_helm.yaml
+++ b/data/recipes/smith_bronze_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_med_helm
type: smithing
-skill: smithing
level: 3
xp: 12
wait: 4
diff --git a/data/recipes/smith_bronze_nails.yaml b/data/recipes/smith_bronze_nails.yaml
index 5b0180b..fa3286b 100644
--- a/data/recipes/smith_bronze_nails.yaml
+++ b/data/recipes/smith_bronze_nails.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_nails
type: smithing
-skill: smithing
level: 4
xp: 12
wait: 4
diff --git a/data/recipes/smith_bronze_platebody.yaml b/data/recipes/smith_bronze_platebody.yaml
index 70ba050..5e49649 100644
--- a/data/recipes/smith_bronze_platebody.yaml
+++ b/data/recipes/smith_bronze_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_platebody
type: smithing
-skill: smithing
level: 18
xp: 62
wait: 4
diff --git a/data/recipes/smith_bronze_sword.yaml b/data/recipes/smith_bronze_sword.yaml
index 75179fd..23d3237 100644
--- a/data/recipes/smith_bronze_sword.yaml
+++ b/data/recipes/smith_bronze_sword.yaml
@@ -1,6 +1,5 @@
id: smith_bronze_sword
type: smithing
-skill: smithing
level: 4
xp: 12
wait: 4
diff --git a/data/recipes/smith_iron_arrowtips.yaml b/data/recipes/smith_iron_arrowtips.yaml
index dab4309..9b773ee 100644
--- a/data/recipes/smith_iron_arrowtips.yaml
+++ b/data/recipes/smith_iron_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_iron_arrowtips
type: smithing
-skill: smithing
level: 25
xp: 25
wait: 4
diff --git a/data/recipes/smith_iron_bolts_unf.yaml b/data/recipes/smith_iron_bolts_unf.yaml
index 670c873..564daab 100644
--- a/data/recipes/smith_iron_bolts_unf.yaml
+++ b/data/recipes/smith_iron_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_iron_bolts_unf
type: smithing
-skill: smithing
level: 26
xp: 25
wait: 4
diff --git a/data/recipes/smith_iron_dagger.yaml b/data/recipes/smith_iron_dagger.yaml
index 7d1e55c..d885717 100644
--- a/data/recipes/smith_iron_dagger.yaml
+++ b/data/recipes/smith_iron_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_iron_dagger
type: smithing
-skill: smithing
level: 20
xp: 25
wait: 4
diff --git a/data/recipes/smith_iron_full_helm.yaml b/data/recipes/smith_iron_full_helm.yaml
index 28bddc3..afcd56a 100644
--- a/data/recipes/smith_iron_full_helm.yaml
+++ b/data/recipes/smith_iron_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_iron_full_helm
type: smithing
-skill: smithing
level: 27
xp: 50
wait: 4
diff --git a/data/recipes/smith_iron_med_helm.yaml b/data/recipes/smith_iron_med_helm.yaml
index a2340fc..5aabb9e 100644
--- a/data/recipes/smith_iron_med_helm.yaml
+++ b/data/recipes/smith_iron_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_iron_med_helm
type: smithing
-skill: smithing
level: 22
xp: 25
wait: 4
diff --git a/data/recipes/smith_iron_nails.yaml b/data/recipes/smith_iron_nails.yaml
index 85fb039..2e6e59f 100644
--- a/data/recipes/smith_iron_nails.yaml
+++ b/data/recipes/smith_iron_nails.yaml
@@ -1,6 +1,5 @@
id: smith_iron_nails
type: smithing
-skill: smithing
level: 24
xp: 25
wait: 4
diff --git a/data/recipes/smith_iron_platebody.yaml b/data/recipes/smith_iron_platebody.yaml
index 8050868..c1fd795 100644
--- a/data/recipes/smith_iron_platebody.yaml
+++ b/data/recipes/smith_iron_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_iron_platebody
type: smithing
-skill: smithing
level: 33
xp: 125
wait: 4
diff --git a/data/recipes/smith_iron_sword.yaml b/data/recipes/smith_iron_sword.yaml
index 9eb3b50..ab87fdc 100644
--- a/data/recipes/smith_iron_sword.yaml
+++ b/data/recipes/smith_iron_sword.yaml
@@ -1,6 +1,5 @@
id: smith_iron_sword
type: smithing
-skill: smithing
level: 24
xp: 25
wait: 4
diff --git a/data/recipes/smith_mithril_arrowtips.yaml b/data/recipes/smith_mithril_arrowtips.yaml
index dd0edf4..a61e5f1 100644
--- a/data/recipes/smith_mithril_arrowtips.yaml
+++ b/data/recipes/smith_mithril_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_arrowtips
type: smithing
-skill: smithing
level: 55
xp: 50
wait: 4
diff --git a/data/recipes/smith_mithril_bolts_unf.yaml b/data/recipes/smith_mithril_bolts_unf.yaml
index 75a931c..eb6da91 100644
--- a/data/recipes/smith_mithril_bolts_unf.yaml
+++ b/data/recipes/smith_mithril_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_bolts_unf
type: smithing
-skill: smithing
level: 56
xp: 50
wait: 4
diff --git a/data/recipes/smith_mithril_dagger.yaml b/data/recipes/smith_mithril_dagger.yaml
index 416776f..f8aea86 100644
--- a/data/recipes/smith_mithril_dagger.yaml
+++ b/data/recipes/smith_mithril_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_dagger
type: smithing
-skill: smithing
level: 50
xp: 50
wait: 4
diff --git a/data/recipes/smith_mithril_full_helm.yaml b/data/recipes/smith_mithril_full_helm.yaml
index bef5645..64b78c4 100644
--- a/data/recipes/smith_mithril_full_helm.yaml
+++ b/data/recipes/smith_mithril_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_full_helm
type: smithing
-skill: smithing
level: 57
xp: 100
wait: 4
diff --git a/data/recipes/smith_mithril_med_helm.yaml b/data/recipes/smith_mithril_med_helm.yaml
index 57ef304..d8cc14e 100644
--- a/data/recipes/smith_mithril_med_helm.yaml
+++ b/data/recipes/smith_mithril_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_med_helm
type: smithing
-skill: smithing
level: 53
xp: 50
wait: 4
diff --git a/data/recipes/smith_mithril_nails.yaml b/data/recipes/smith_mithril_nails.yaml
index ddda12f..5f33c62 100644
--- a/data/recipes/smith_mithril_nails.yaml
+++ b/data/recipes/smith_mithril_nails.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_nails
type: smithing
-skill: smithing
level: 54
xp: 50
wait: 4
diff --git a/data/recipes/smith_mithril_platebody.yaml b/data/recipes/smith_mithril_platebody.yaml
index 94048cc..43efb1d 100644
--- a/data/recipes/smith_mithril_platebody.yaml
+++ b/data/recipes/smith_mithril_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_platebody
type: smithing
-skill: smithing
level: 68
xp: 250
wait: 4
diff --git a/data/recipes/smith_mithril_sword.yaml b/data/recipes/smith_mithril_sword.yaml
index ccc687d..98cf6dc 100644
--- a/data/recipes/smith_mithril_sword.yaml
+++ b/data/recipes/smith_mithril_sword.yaml
@@ -1,6 +1,5 @@
id: smith_mithril_sword
type: smithing
-skill: smithing
level: 54
xp: 50
wait: 4
diff --git a/data/recipes/smith_rune_arrowtips.yaml b/data/recipes/smith_rune_arrowtips.yaml
index a484371..4d2731e 100644
--- a/data/recipes/smith_rune_arrowtips.yaml
+++ b/data/recipes/smith_rune_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_rune_arrowtips
type: smithing
-skill: smithing
level: 90
xp: 75
wait: 4
diff --git a/data/recipes/smith_rune_bolts_unf.yaml b/data/recipes/smith_rune_bolts_unf.yaml
index f69fb82..088871b 100644
--- a/data/recipes/smith_rune_bolts_unf.yaml
+++ b/data/recipes/smith_rune_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_rune_bolts_unf
type: smithing
-skill: smithing
level: 91
xp: 75
wait: 4
diff --git a/data/recipes/smith_rune_dagger.yaml b/data/recipes/smith_rune_dagger.yaml
index e24c381..3b76cae 100644
--- a/data/recipes/smith_rune_dagger.yaml
+++ b/data/recipes/smith_rune_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_rune_dagger
type: smithing
-skill: smithing
level: 85
xp: 75
wait: 4
diff --git a/data/recipes/smith_rune_full_helm.yaml b/data/recipes/smith_rune_full_helm.yaml
index 6b69cb1..1714afa 100644
--- a/data/recipes/smith_rune_full_helm.yaml
+++ b/data/recipes/smith_rune_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_rune_full_helm
type: smithing
-skill: smithing
level: 92
xp: 150
wait: 4
diff --git a/data/recipes/smith_rune_med_helm.yaml b/data/recipes/smith_rune_med_helm.yaml
index 137c78f..0c58be5 100644
--- a/data/recipes/smith_rune_med_helm.yaml
+++ b/data/recipes/smith_rune_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_rune_med_helm
type: smithing
-skill: smithing
level: 88
xp: 75
wait: 4
diff --git a/data/recipes/smith_rune_nails.yaml b/data/recipes/smith_rune_nails.yaml
index 320e376..ad99d41 100644
--- a/data/recipes/smith_rune_nails.yaml
+++ b/data/recipes/smith_rune_nails.yaml
@@ -1,6 +1,5 @@
id: smith_rune_nails
type: smithing
-skill: smithing
level: 89
xp: 75
wait: 4
diff --git a/data/recipes/smith_rune_platebody.yaml b/data/recipes/smith_rune_platebody.yaml
index 7886afc..7f27292 100644
--- a/data/recipes/smith_rune_platebody.yaml
+++ b/data/recipes/smith_rune_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_rune_platebody
type: smithing
-skill: smithing
level: 99
xp: 375
wait: 4
diff --git a/data/recipes/smith_rune_sword.yaml b/data/recipes/smith_rune_sword.yaml
index 5ff3302..c329102 100644
--- a/data/recipes/smith_rune_sword.yaml
+++ b/data/recipes/smith_rune_sword.yaml
@@ -1,6 +1,5 @@
id: smith_rune_sword
type: smithing
-skill: smithing
level: 89
xp: 75
wait: 4
diff --git a/data/recipes/smith_steel_arrowtips.yaml b/data/recipes/smith_steel_arrowtips.yaml
index 5acb5c5..0f97327 100644
--- a/data/recipes/smith_steel_arrowtips.yaml
+++ b/data/recipes/smith_steel_arrowtips.yaml
@@ -1,6 +1,5 @@
id: smith_steel_arrowtips
type: smithing
-skill: smithing
level: 35
xp: 37
wait: 4
diff --git a/data/recipes/smith_steel_bolts_unf.yaml b/data/recipes/smith_steel_bolts_unf.yaml
index c4acbcf..550dd5e 100644
--- a/data/recipes/smith_steel_bolts_unf.yaml
+++ b/data/recipes/smith_steel_bolts_unf.yaml
@@ -1,6 +1,5 @@
id: smith_steel_bolts_unf
type: smithing
-skill: smithing
level: 36
xp: 37
wait: 4
diff --git a/data/recipes/smith_steel_dagger.yaml b/data/recipes/smith_steel_dagger.yaml
index 92be7b1..e569065 100644
--- a/data/recipes/smith_steel_dagger.yaml
+++ b/data/recipes/smith_steel_dagger.yaml
@@ -1,6 +1,5 @@
id: smith_steel_dagger
type: smithing
-skill: smithing
level: 30
xp: 37
wait: 4
diff --git a/data/recipes/smith_steel_full_helm.yaml b/data/recipes/smith_steel_full_helm.yaml
index faa872a..a23b110 100644
--- a/data/recipes/smith_steel_full_helm.yaml
+++ b/data/recipes/smith_steel_full_helm.yaml
@@ -1,6 +1,5 @@
id: smith_steel_full_helm
type: smithing
-skill: smithing
level: 37
xp: 75
wait: 4
diff --git a/data/recipes/smith_steel_med_helm.yaml b/data/recipes/smith_steel_med_helm.yaml
index bc1666f..264b487 100644
--- a/data/recipes/smith_steel_med_helm.yaml
+++ b/data/recipes/smith_steel_med_helm.yaml
@@ -1,6 +1,5 @@
id: smith_steel_med_helm
type: smithing
-skill: smithing
level: 33
xp: 37
wait: 4
diff --git a/data/recipes/smith_steel_nails.yaml b/data/recipes/smith_steel_nails.yaml
index 29a4caf..63a5881 100644
--- a/data/recipes/smith_steel_nails.yaml
+++ b/data/recipes/smith_steel_nails.yaml
@@ -1,6 +1,5 @@
id: smith_steel_nails
type: smithing
-skill: smithing
level: 34
xp: 37
wait: 4
diff --git a/data/recipes/smith_steel_platebody.yaml b/data/recipes/smith_steel_platebody.yaml
index d4f2647..5d001b0 100644
--- a/data/recipes/smith_steel_platebody.yaml
+++ b/data/recipes/smith_steel_platebody.yaml
@@ -1,6 +1,5 @@
id: smith_steel_platebody
type: smithing
-skill: smithing
level: 48
xp: 187
wait: 4
diff --git a/data/recipes/smith_steel_sword.yaml b/data/recipes/smith_steel_sword.yaml
index 66898fb..b8c18bd 100644
--- a/data/recipes/smith_steel_sword.yaml
+++ b/data/recipes/smith_steel_sword.yaml
@@ -1,6 +1,5 @@
id: smith_steel_sword
type: smithing
-skill: smithing
level: 34
xp: 37
wait: 4
diff --git a/data/rooms/13.yaml b/data/rooms/13.yaml
index 3b394af..939e751 100644
--- a/data/rooms/13.yaml
+++ b/data/rooms/13.yaml
@@ -1,6 +1,46 @@
id: 13
-name: "Workshop"
-description: "A well-equipped workshop with crafting tables and tool racks. This area is not yet accessible."
+name: "Crafting Workshop"
+description: "A bustling workshop filled with crafting stations. A {130}spinning wheel{/} sits in one corner, a {173}pottery wheel{/} and {196}pottery oven{/} in another. Racks of tools and raw materials line the walls. The forge is just to the west."
exits:
east: 14
west: 12
+objects:
+ - id: spinning_wheel
+ - id: pottery_wheel
+ - id: pottery_oven
+ - id: sheep
+ - id: clay_rock
+ - id: clay_rock
+mobs:
+ - id: tanner
+ - id: cow
+ - id: cow
+ - id: cow
+spawns:
+ - item_id: flax
+ quantity: 5
+ respawn_ticks: 60
+ - item_id: thread
+ quantity: 10
+ respawn_ticks: 60
+ - item_id: shears
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: needle
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: chisel
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: ring_mould
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: necklace_mould
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: amulet_mould
+ quantity: 1
+ respawn_ticks: 60
+ - item_id: bracelet_mould
+ quantity: 1
+ respawn_ticks: 60
diff --git a/internal/action/behavior.go b/internal/action/behavior.go
index 67baab0..ccd95bf 100644
--- a/internal/action/behavior.go
+++ b/internal/action/behavior.go
@@ -49,6 +49,7 @@ type NodeAction struct {
TakeItem string `yaml:"take_item"`
Teleport int `yaml:"teleport"`
Heal int `yaml:"heal"`
+ Cost int `yaml:"cost"`
}
type Condition struct {
@@ -57,6 +58,7 @@ type Condition struct {
Not bool `yaml:"not"`
PlayerFlag string `yaml:"player_flag"`
HasItem string `yaml:"has_item"`
+ MinCredits int `yaml:"min_credits"`
AllOf []Condition `yaml:"all_of"`
AnyOf []Condition `yaml:"any_of"`
}
diff --git a/internal/action/recipe.go b/internal/action/recipe.go
index 2e93c06..fee3434 100644
--- a/internal/action/recipe.go
+++ b/internal/action/recipe.go
@@ -21,6 +21,7 @@ type RecipeDef struct {
Level int `yaml:"level"`
XP int `yaml:"xp"`
Station []string `yaml:"station"`
+ Tool string `yaml:"tool"`
Consume []ConsumeEntry `yaml:"consume"`
Output string `yaml:"output"`
OutputQty int `yaml:"output_qty"`
@@ -153,6 +154,13 @@ func (r *RecipeDef) DisplayName() string {
return r.Output
}
+func (r *RecipeDef) EffectiveSkill() string {
+ if r.Skill != "" {
+ return r.Skill
+ }
+ return r.Type
+}
+
func (s *RecipeStore) FindByNameOrID(query string, recipeType string) (*RecipeDef, error) {
all, err := s.LoadAll()
if err != nil {
diff --git a/internal/game/action.go b/internal/game/action.go
index 3d0223a..ca8506a 100644
--- a/internal/game/action.go
+++ b/internal/game/action.go
@@ -19,6 +19,7 @@ var verbAliases = map[string]string{
"chop": "gather",
"fish": "gather",
"cut": "gather",
+ "shear": "gather",
"talk": "talk",
"speak": "talk",
"ask": "talk",
@@ -27,10 +28,11 @@ var verbAliases = map[string]string{
}
var verbSkill = map[string]string{
- "mine": "mining",
- "chop": "woodcutting",
- "cut": "woodcutting",
- "fish": "fishing",
+ "mine": "mining",
+ "chop": "woodcutting",
+ "cut": "woodcutting",
+ "fish": "fishing",
+ "shear": "crafting",
}
func normalizeVerb(v string) string {
@@ -231,14 +233,10 @@ func (g *Game) AdvanceActions() {
g.advanceStoke(sess, p)
case "search":
g.advanceSearch(sess, p)
- case "cook":
- g.advanceProduction(sess, p)
- case "smelt":
- g.advanceProduction(sess, p)
- case "smith":
- g.advanceProduction(sess, p)
- case "combine":
- g.advanceProduction(sess, p)
+ default:
+ if productionActionTypes[p.Action.Type] {
+ g.advanceProduction(sess, p)
+ }
}
if p.Action == nil {
g.writePrompt(sess)
@@ -308,5 +306,12 @@ func (g *Game) checkCondition(sess *net.Session, c *action.Condition) bool {
}
return has
}
+ if c.MinCredits > 0 {
+ has := p != nil && p.Credits >= c.MinCredits
+ if c.Not {
+ return !has
+ }
+ return has
+ }
return true
}
diff --git a/internal/game/action_fletch.go b/internal/game/action_fletch.go
index 734453b..25f2966 100644
--- a/internal/game/action_fletch.go
+++ b/internal/game/action_fletch.go
@@ -33,6 +33,7 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, recipe *acti
batches := 0
totalOutput := 0
+ skill := player.SkillName(recipe.EffectiveSkill())
for {
if !g.canDoFletchRecipe(p, recipe) {
break
@@ -60,8 +61,8 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, recipe *acti
}
if recipe.XP > 0 {
- if newLevel := p.AddSkillXP(player.Fletching, recipe.XP); newLevel > 0 {
- sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d fletching! ***", newLevel)))
+ if newLevel := p.AddSkillXP(skill, recipe.XP); newLevel > 0 {
+ sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, recipe.EffectiveSkill())))
}
}
@@ -91,7 +92,7 @@ func (g *Game) doInstantFletch(sess *net.Session, p *player.Player, recipe *acti
msg := fmt.Sprintf("You fletch %d %s.", totalOutput, outputName)
if p.OptionBool("xp_drops") && recipe.XP > 0 {
totalXP := recipe.XP * batches
- abbr := player.SkillAbbr[player.Fletching]
+ abbr := player.SkillAbbr[skill]
msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", totalXP, abbr))
}
sess.WriteLine(msg)
@@ -151,6 +152,8 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
outputQty = 1
}
+ skill := player.SkillName(recipe.EffectiveSkill())
+
placed := false
if outDef != nil && outDef.Stackable {
for i := 0; i < 28; i++ {
@@ -175,8 +178,8 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
}
if recipe.XP > 0 {
- if newLevel := p.AddSkillXP(player.Fletching, recipe.XP); newLevel > 0 {
- sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d fletching! ***", newLevel)))
+ if newLevel := p.AddSkillXP(skill, recipe.XP); newLevel > 0 {
+ sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, recipe.EffectiveSkill())))
}
}
g.AccountStore.SaveCharacter(p)
@@ -190,7 +193,7 @@ func (g *Game) advanceFletch(sess *net.Session, p *player.Player) {
msg = fmt.Sprintf("You fletch %s.", outputName)
}
if p.OptionBool("xp_drops") && recipe.XP > 0 {
- abbr := player.SkillAbbr[player.Fletching]
+ abbr := player.SkillAbbr[skill]
msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr))
}
sess.WriteLine(msg)
diff --git a/internal/game/action_gather.go b/internal/game/action_gather.go
index ffd30e1..8b45129 100644
--- a/internal/game/action_gather.go
+++ b/internal/game/action_gather.go
@@ -180,6 +180,11 @@ func (g *Game) advanceGather(sess *net.Session, p *player.Player) {
_, shared := p.Action.Data["deplete_timer"]
if step == 0 {
+ if p.FirstFreeSlot() == -1 {
+ sess.WriteLine(g.colorize(sess, "error", "Your inventory is too full!"))
+ g.CancelAction(p)
+ return
+ }
if cfg.Bait != "" {
if !p.HasItem(cfg.Bait) {
baitName := cfg.Bait
diff --git a/internal/game/action_production.go b/internal/game/action_production.go
index d4e2274..df23198 100644
--- a/internal/game/action_production.go
+++ b/internal/game/action_production.go
@@ -3,10 +3,12 @@ package game
import (
"fmt"
"math/rand"
+ "sort"
"strconv"
"strings"
"thehouseoficarus/internal/action"
+ "thehouseoficarus/internal/color"
"thehouseoficarus/internal/engine"
"thehouseoficarus/internal/net"
"thehouseoficarus/internal/object"
@@ -19,6 +21,29 @@ type recipeEntry struct {
Recipe action.RecipeDef
}
+type productionTypeInfo struct {
+ ActionType string
+ DisplayVerb string
+}
+
+var productionTypes = map[string]productionTypeInfo{
+ "cooking": {"cook", "cooking"},
+ "smelting": {"smelt", "smelting"},
+ "smithing": {"smith", "smithing"},
+ "crafting": {"craft", "crafting"},
+ "combine": {"combine", "combining"},
+ "fletching": {"fletch", "fletching"},
+}
+
+var productionActionTypes map[string]bool
+
+func init() {
+ productionActionTypes = make(map[string]bool)
+ for _, pt := range productionTypes {
+ productionActionTypes[pt.ActionType] = true
+ }
+}
+
func recipeMenuData(recipes []action.RecipeDef) []map[string]string {
out := make([]map[string]string, len(recipes))
for i, r := range recipes {
@@ -183,10 +208,11 @@ func (g *Game) startProduction(sess *net.Session, p *player.Player, recipe *acti
g.CancelAction(p)
g.CancelBackgroundAction(p)
- if recipe.Skill != "" {
- skillLevel := p.Level(player.SkillName(recipe.Skill))
+ skill := recipe.EffectiveSkill()
+ if skill != "" {
+ skillLevel := p.Level(player.SkillName(skill))
if skillLevel < recipe.Level {
- sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", recipe.Level, recipe.Skill))
+ sess.WriteLine(fmt.Sprintf("You need level %d %s to do that.", recipe.Level, skill))
g.reprompt(sess)
return
}
@@ -242,38 +268,20 @@ func (g *Game) startProductionFromRecipe(sess *net.Session, p *player.Player, re
return def.Name, true
})
- var actionType, displayVerb, startMsg, endMsg string
- switch recipe.Type {
- case "cooking":
- actionType = "cook"
- displayVerb = "cooking"
- if stationName != "inventory" {
- startMsg = fmt.Sprintf("You start cooking %s on the %s.", firstItem, stationName)
- } else {
- startMsg = fmt.Sprintf("You start making %s.", firstItem)
- }
- endMsg = "You've cooked everything you can."
- case "smelting":
- actionType = "smelt"
- displayVerb = "smelting"
- startMsg = fmt.Sprintf("You begin to process %s in the furnace.", firstItem)
- endMsg = "You've processed all the ore in your inventory."
- case "smithing":
- actionType = "smith"
- displayVerb = "smithing"
- startMsg = fmt.Sprintf("You hammer the %s on the anvil...", firstItem)
- endMsg = "You've used all the bars you can."
- case "combine":
- actionType = "combine"
- displayVerb = "combining"
- startMsg = fmt.Sprintf("You start combining %s.", firstItem)
- endMsg = "You've run out of materials."
- default:
- actionType = "craft"
- displayVerb = "crafting"
- startMsg = fmt.Sprintf("You start crafting with %s.", firstItem)
- endMsg = "You've run out of materials."
+ info, ok := productionTypes[recipe.Type]
+ if !ok {
+ info = productionTypeInfo{recipe.Type, recipe.Type}
+ }
+ actionType := info.ActionType
+ displayVerb := info.DisplayVerb
+
+ var startMsg, endMsg string
+ if stationName != "inventory" {
+ startMsg = fmt.Sprintf("You start %s %s on the %s.", displayVerb, firstItem, stationName)
+ } else {
+ startMsg = fmt.Sprintf("You start %s %s.", displayVerb, firstItem)
}
+ endMsg = fmt.Sprintf("You've finished %s.", displayVerb)
g.startProduction(sess, p, recipe, actionType, displayVerb, startMsg, endMsg, count)
}
@@ -319,7 +327,8 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool {
return true
}
- skillLevel := p.Level(player.SkillName(recipe.Skill))
+ skill := recipe.EffectiveSkill()
+ skillLevel := p.Level(player.SkillName(skill))
chance := 1.0
if recipe.Success != nil {
chance = action.SuccessChance(*recipe.Success, skillLevel, recipe.Level)
@@ -364,8 +373,8 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool {
}
if recipe.XP > 0 {
- if newLevel := p.AddSkillXP(player.SkillName(recipe.Skill), recipe.XP); newLevel > 0 {
- sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, recipe.Skill)))
+ if newLevel := p.AddSkillXP(player.SkillName(skill), recipe.XP); newLevel > 0 {
+ sess.WriteLine(g.colorize(sess, "level_up", fmt.Sprintf("*** You are now level %d %s! ***", newLevel, skill)))
}
}
g.AccountStore.SaveCharacter(p)
@@ -379,7 +388,7 @@ func (g *Game) advanceProduction(sess *net.Session, p *player.Player) bool {
msg = fmt.Sprintf("You produce %s.", outputName)
}
if p.OptionBool("xp_drops") && recipe.XP > 0 {
- abbr := player.SkillAbbr[player.SkillName(recipe.Skill)]
+ abbr := player.SkillAbbr[player.SkillName(skill)]
msg += g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp %s)", recipe.XP, abbr))
}
sess.WriteLine(msg)
@@ -531,6 +540,17 @@ func (g *Game) menuEntryName(entry map[string]string) string {
}
}
}
+ if rid, ok := entry["fletch_recipe_id"]; ok {
+ all, _ := g.RecipeStore.LoadAll()
+ for _, r := range all {
+ if r.ID == rid {
+ if def, err := g.ItemStore.Load(r.Output); err == nil {
+ return def.Name
+ }
+ return r.Output
+ }
+ }
+ }
if barID, ok := entry["bar_id"]; ok {
if def, _ := g.ItemStore.Load(barID); def != nil {
return def.Name
@@ -557,9 +577,212 @@ func (g *Game) dispatchMenuEntry(sess *net.Session, entry map[string]string) {
g.showSmithTable(sess, p, barID, allRecipes)
return
}
+ if rid, ok := entry["fletch_recipe_id"]; ok {
+ p := sess.Player.(*player.Player)
+ allRecipes, _ := g.RecipeStore.LoadAll()
+ for _, r := range allRecipes {
+ if r.ID == rid {
+ g.startFletchAction(sess, p, &r, 0)
+ return
+ }
+ }
+ g.reprompt(sess)
+ return
+ }
if rid, ok := entry["recipe_id"]; ok {
g.promptHowMany(sess, rid)
return
}
g.reprompt(sess)
}
+
+func (g *Game) formatRecipeMaterials(r *action.RecipeDef) string {
+ var parts []string
+ for _, e := range r.Consume {
+ itemName := e.Items[0]
+ if def, err := g.ItemStore.Load(e.Items[0]); err == nil {
+ itemName = def.Name
+ }
+ if e.Qty > 1 {
+ parts = append(parts, fmt.Sprintf("%s x%d", itemName, e.Qty))
+ } else {
+ parts = append(parts, itemName)
+ }
+ }
+ return strings.Join(parts, ", ")
+}
+
+func (g *Game) showProductionTable(sess *net.Session, p *player.Player, recipes []action.RecipeDef, title, skill, lastFlagKey, promptVerb string, background bool) {
+ sort.Slice(recipes, func(i, j int) bool {
+ return recipes[i].Level < recipes[j].Level
+ })
+
+ mode := g.colorMode(sess)
+ skillLevel := p.Level(player.SkillName(skill))
+ dimSpec := color.Parse("240")
+
+ tbl := &Table{
+ Title: title,
+ Columns: []string{"#", "Product", "Materials", "Level"},
+ }
+
+ for i, r := range recipes {
+ outDef, _ := g.ItemStore.Load(r.Output)
+ productName := r.Output
+ if outDef != nil {
+ productName = outDef.Name
+ }
+
+ outputQty := r.OutputQty
+ if outputQty <= 0 {
+ outputQty = 1
+ }
+ if outDef != nil && outDef.Stackable && outputQty > 1 {
+ productName = fmt.Sprintf("%s x%d", productName, outputQty)
+ }
+
+ matStr := g.formatRecipeMaterials(&r)
+ levelStr := fmt.Sprint(r.Level)
+ numStr := fmt.Sprintf("%d", i+1)
+
+ canMake := skillLevel >= r.Level && r.HasAllItemsQty(p.CountItem)
+ if canMake {
+ productName = g.itemColorize(sess, outDef, productName)
+ } else {
+ productName = color.Render(mode, dimSpec, productName)
+ matStr = color.Render(mode, dimSpec, matStr)
+ levelStr = color.Render(mode, dimSpec, levelStr)
+ numStr = color.Render(mode, dimSpec, numStr)
+ }
+
+ tbl.Rows = append(tbl.Rows, []string{numStr, productName, matStr, levelStr})
+ }
+
+ unicode := p.OptionBool("unicode")
+ sess.WriteLine("")
+ for _, line := range tbl.Render(unicode) {
+ sess.WriteLine(line)
+ }
+
+ lastRecipeID, _ := p.Flags[lastFlagKey].(string)
+ hint := ""
+ if lastRecipeID != "" {
+ for _, r := range recipes {
+ if r.ID == lastRecipeID {
+ if outDef, err := g.ItemStore.Load(r.Output); err == nil {
+ hint = outDef.Name
+ }
+ break
+ }
+ }
+ }
+
+ if hint != "" {
+ sess.Write(fmt.Sprintf("%s what (enter for all %s): ", promptVerb, hint))
+ } else {
+ sess.Write(fmt.Sprintf("%s what: ", promptVerb))
+ }
+
+ sess.PendingMenu = recipeMenuData(recipes)
+ sess.PendingSkill = skill
+ sess.PendingLastFlag = lastFlagKey
+ sess.PendingBackground = background
+ sess.State = net.StateProductChoice
+}
+
+func (g *Game) handleProductChoice(sess *net.Session, input string) {
+ p := sess.Player.(*player.Player)
+ menuData := sess.PendingMenu
+ skill := sess.PendingSkill
+ lastFlagKey := sess.PendingLastFlag
+ background := sess.PendingBackground
+ sess.PendingMenu = nil
+ sess.PendingSkill = ""
+ sess.PendingLastFlag = ""
+ sess.PendingBackground = false
+ sess.State = net.StateGame
+
+ input = strings.TrimSpace(input)
+
+ allRecipes, err := g.RecipeStore.LoadAll()
+ if err != nil {
+ g.reprompt(sess)
+ return
+ }
+
+ var recipes []action.RecipeDef
+ for _, entry := range menuData {
+ rid := entry["recipe_id"]
+ for _, r := range allRecipes {
+ if r.ID == rid {
+ recipes = append(recipes, r)
+ break
+ }
+ }
+ }
+
+ if len(recipes) == 0 {
+ g.reprompt(sess)
+ return
+ }
+
+ sort.Slice(recipes, func(i, j int) bool {
+ return recipes[i].Level < recipes[j].Level
+ })
+
+ lastRecipeID, _ := p.Flags[lastFlagKey].(string)
+
+ sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID)
+ switch errMsg {
+ case "ambiguous":
+ sess.WriteLine("That's ambiguous.")
+ g.reprompt(sess)
+ return
+ case "never_mind":
+ sess.WriteLine("Never mind.")
+ g.reprompt(sess)
+ return
+ }
+
+ skillLevel := p.Level(player.SkillName(skill))
+ if skillLevel < sel.Recipe.Level {
+ sess.WriteLine(fmt.Sprintf("You need level %d %s to make that.", sel.Recipe.Level, skill))
+ g.reprompt(sess)
+ return
+ }
+ if !sel.Recipe.HasAllItemsQty(p.CountItem) {
+ sess.WriteLine("You don't have the materials for that.")
+ g.reprompt(sess)
+ return
+ }
+
+ if p.Flags == nil {
+ p.Flags = make(map[string]any)
+ }
+ p.Flags[lastFlagKey] = sel.Recipe.ID
+ g.AccountStore.SaveCharacter(p)
+
+ if background {
+ g.startFletchAction(sess, p, sel.Recipe, sel.Count)
+ } else {
+ g.startProductionFromRecipe(sess, p, sel.Recipe, sel.Count)
+ }
+}
+
+func (g *Game) hasToolType(p *player.Player, toolType string) bool {
+ if itemID, ok := p.Equipment[object.SlotMainHand]; ok {
+ if def, err := g.ItemStore.Load(itemID); err == nil && def.ToolType == toolType {
+ return true
+ }
+ }
+ for i := 0; i < 28; i++ {
+ slot := p.InvSlot(i)
+ if slot == nil {
+ continue
+ }
+ if def, err := g.ItemStore.Load(slot.ItemID); err == nil && def.ToolType == toolType {
+ return true
+ }
+ }
+ return false
+}
diff --git a/internal/game/action_talk.go b/internal/game/action_talk.go
index 30bf206..2d4a814 100644
--- a/internal/game/action_talk.go
+++ b/internal/game/action_talk.go
@@ -210,4 +210,10 @@ func (g *Game) applyNodeAction(sess *net.Session, na *action.NodeAction) {
g.AccountStore.SaveCharacter(p)
sess.WriteLine(fmt.Sprintf("You regain %d hitpoints.", na.Heal))
}
+ if na.Cost > 0 {
+ if p.Credits >= na.Cost {
+ p.Credits -= na.Cost
+ g.AccountStore.SaveCharacter(p)
+ }
+ }
}
diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go
index 51ac54a..4c6941a 100644
--- a/internal/game/cmd_attack.go
+++ b/internal/game/cmd_attack.go
@@ -332,7 +332,8 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst
if !mob.Unique {
dropper = "The " + mob.Name
}
- sess.WriteLine(g.colorize(sess, "drop_message", fmt.Sprintf(" %s drops: %s", dropper, name)))
+ coloredName := g.itemColorize(sess, def, name)
+ sess.WriteLine(fmt.Sprintf(" %s %s", g.colorize(sess, "drop_message", dropper+" drops:"), coloredName))
}
if len(mob.Drops.Loot) > 0 {
@@ -352,10 +353,11 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst
if !mob.Unique {
dropper = "The " + mob.Name
}
+ coloredName := g.itemColorize(sess, def, name)
if qty > 1 {
- sess.WriteLine(g.colorize(sess, "drop_message", fmt.Sprintf(" %s drops: %d x %s", dropper, qty, name)))
+ sess.WriteLine(fmt.Sprintf(" %s %d x %s", g.colorize(sess, "drop_message", dropper+" drops:"), qty, coloredName))
} else {
- sess.WriteLine(g.colorize(sess, "drop_message", fmt.Sprintf(" %s drops: %s", dropper, name)))
+ sess.WriteLine(fmt.Sprintf(" %s %s", g.colorize(sess, "drop_message", dropper+" drops:"), coloredName))
}
}
}
diff --git a/internal/game/cmd_craft.go b/internal/game/cmd_craft.go
new file mode 100644
index 0000000..50a99e0
--- /dev/null
+++ b/internal/game/cmd_craft.go
@@ -0,0 +1,190 @@
+package game
+
+import (
+ "strings"
+
+ "thehouseoficarus/internal/action"
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+ "thehouseoficarus/internal/world"
+)
+
+func (g *Game) doCraft(sess *net.Session, input string) {
+ p := sess.Player.(*player.Player)
+ g.CancelAction(p)
+
+ allRecipes, err := g.RecipeStore.LoadAll()
+ if err != nil {
+ sess.WriteLine("Error loading recipes.")
+ return
+ }
+
+ var craftRecipes []action.RecipeDef
+ for _, r := range allRecipes {
+ if r.Type != "crafting" {
+ continue
+ }
+ if !g.craftRecipeVisible(p, &r) {
+ continue
+ }
+ craftRecipes = append(craftRecipes, r)
+ }
+
+ if input != "" {
+ g.doCraftWithInput(sess, p, craftRecipes, input)
+ return
+ }
+
+ lastRecipeID, _ := p.Flags["last_craft"].(string)
+ if lastRecipeID != "" {
+ for i := range craftRecipes {
+ if craftRecipes[i].ID == lastRecipeID {
+ r := &craftRecipes[i]
+ if g.canDoCraftRecipe(p, r) {
+ g.startCraftRecipe(sess, p, r, 0)
+ return
+ }
+ break
+ }
+ }
+ }
+
+ available := g.availableCraftRecipes(p, craftRecipes)
+ if len(available) == 0 {
+ sess.WriteLine("You don't have any materials to craft.")
+ return
+ }
+
+ if p.OptionBool("craft_all") && len(available) == 1 {
+ g.startCraftRecipe(sess, p, &available[0], 0)
+ return
+ }
+
+ g.showProductionTable(sess, p, available, "Crafting", "crafting", "last_craft", "Craft", false)
+}
+
+func (g *Game) doCraftWithInput(sess *net.Session, p *player.Player, craftRecipes []action.RecipeDef, input string) {
+ qty, productName := parseQty(input)
+ productName = strings.TrimSpace(productName)
+
+ var matched []action.RecipeDef
+ for _, r := range craftRecipes {
+ outDef, _ := g.ItemStore.Load(r.Output)
+ name := r.Output
+ if outDef != nil {
+ name = outDef.Name
+ }
+ if world.WordPrefixMatch(productName, name) {
+ matched = append(matched, r)
+ }
+ }
+
+ if len(matched) == 0 {
+ sess.WriteLine("You can't craft that.")
+ return
+ }
+
+ var available []action.RecipeDef
+ for _, r := range matched {
+ if g.canDoCraftRecipe(p, &r) {
+ available = append(available, r)
+ }
+ }
+
+ if len(available) == 0 {
+ sess.WriteLine("You don't have the materials or level for that.")
+ return
+ }
+
+ if len(available) == 1 {
+ g.startCraftRecipe(sess, p, &available[0], qty)
+ return
+ }
+
+ g.showProductionTable(sess, p, available, "Crafting", "crafting", "last_craft", "Craft", false)
+}
+
+func (g *Game) craftRecipeVisible(p *player.Player, r *action.RecipeDef) bool {
+ if len(r.Station) > 0 {
+ stID, _ := g.findStation(p.RoomID, r.Station)
+ if stID == "" {
+ return false
+ }
+ }
+ if r.Tool != "" && !g.hasToolType(p, r.Tool) {
+ return false
+ }
+ return true
+}
+
+func (g *Game) canDoCraftRecipe(p *player.Player, r *action.RecipeDef) bool {
+ if p.Level(player.Crafting) < r.Level {
+ return false
+ }
+ if !r.HasAllItemsQty(p.CountItem) {
+ return false
+ }
+ if len(r.Station) > 0 {
+ stID, _ := g.findStation(p.RoomID, r.Station)
+ if stID == "" {
+ return false
+ }
+ }
+ if r.Tool != "" && !g.hasToolType(p, r.Tool) {
+ return false
+ }
+ return true
+}
+
+func (g *Game) availableCraftRecipes(p *player.Player, allCraft []action.RecipeDef) []action.RecipeDef {
+ var result []action.RecipeDef
+ for _, r := range allCraft {
+ if r.HasAllItemsQty(p.CountItem) {
+ result = append(result, r)
+ }
+ }
+ return result
+}
+
+func (g *Game) startCraftRecipe(sess *net.Session, p *player.Player, recipe *action.RecipeDef, count int) {
+ if p.Flags == nil {
+ p.Flags = make(map[string]any)
+ }
+ p.Flags["last_craft"] = recipe.ID
+ g.AccountStore.SaveCharacter(p)
+
+ g.startProductionFromRecipe(sess, p, recipe, count)
+}
+
+func (g *Game) findCraftRecipesForItems(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
+ allRecipes, err := g.RecipeStore.LoadAll()
+ if err != nil {
+ return nil
+ }
+
+ toolTypeA := ""
+ toolTypeB := ""
+ if defA, _ := g.ItemStore.Load(itemAID); defA != nil {
+ toolTypeA = defA.ToolType
+ }
+ if defB, _ := g.ItemStore.Load(itemBID); defB != nil {
+ toolTypeB = defB.ToolType
+ }
+
+ var matched []action.RecipeDef
+ for _, r := range allRecipes {
+ if r.Type != "crafting" {
+ continue
+ }
+ if r.Tool == "" {
+ continue
+ }
+
+ if r.Tool == toolTypeA && r.MatchesEntry(itemBID) {
+ matched = append(matched, r)
+ } else if r.Tool == toolTypeB && r.MatchesEntry(itemAID) {
+ matched = append(matched, r)
+ }
+ }
+ return matched
+}
diff --git a/internal/game/cmd_fletch.go b/internal/game/cmd_fletch.go
index fe8c0b3..60acb92 100644
--- a/internal/game/cmd_fletch.go
+++ b/internal/game/cmd_fletch.go
@@ -1,12 +1,9 @@
package game
import (
- "fmt"
- "sort"
"strings"
"thehouseoficarus/internal/action"
- "thehouseoficarus/internal/color"
"thehouseoficarus/internal/combat"
"thehouseoficarus/internal/net"
"thehouseoficarus/internal/player"
@@ -24,6 +21,9 @@ var fletchGemItems = map[string]bool{
}
func fletchNeedsKnife(r *action.RecipeDef) bool {
+ if r.Tool == "knife" {
+ return true
+ }
for _, e := range r.Consume {
for _, id := range e.Items {
if fletchLogItems[id] {
@@ -37,6 +37,9 @@ func fletchNeedsKnife(r *action.RecipeDef) bool {
}
func fletchNeedsChisel(r *action.RecipeDef) bool {
+ if r.Tool == "chisel" {
+ return true
+ }
for _, e := range r.Consume {
for _, id := range e.Items {
if fletchGemItems[id] {
@@ -104,7 +107,7 @@ func (g *Game) doFletch(sess *net.Session, input string) {
return
}
- g.showFletchTable(sess, p, available)
+ g.showProductionTable(sess, p, available, "Fletching", "fletching", "last_fletch", "Fletch", true)
}
func (g *Game) doFletchWithInput(sess *net.Session, p *player.Player, fletchRecipes []action.RecipeDef, input string) {
@@ -146,10 +149,13 @@ func (g *Game) doFletchWithInput(sess *net.Session, p *player.Player, fletchReci
return
}
- g.showFletchTable(sess, p, available)
+ g.showProductionTable(sess, p, available, "Fletching", "fletching", "last_fletch", "Fletch", true)
}
func (g *Game) hasFletchTools(p *player.Player, r *action.RecipeDef) bool {
+ if r.Tool != "" {
+ return g.hasToolType(p, r.Tool)
+ }
if fletchNeedsKnife(r) && !g.hasToolType(p, "knife") {
return false
}
@@ -175,154 +181,6 @@ func (g *Game) availableFletchRecipes(p *player.Player, allFletch []action.Recip
return result
}
-func (g *Game) showFletchTable(sess *net.Session, p *player.Player, available []action.RecipeDef) {
- sort.Slice(available, func(i, j int) bool {
- return available[i].Level < available[j].Level
- })
-
- mode := g.colorMode(sess)
- skillLevel := p.Level(player.Fletching)
- dimSpec := color.Parse("240")
-
- tbl := &Table{
- Title: "Fletching Actions",
- Columns: []string{"#", "Product", "Materials", "Level"},
- }
-
- for i, r := range available {
- outDef, _ := g.ItemStore.Load(r.Output)
- productName := r.Output
- if outDef != nil {
- productName = outDef.Name
- }
-
- outputQty := r.OutputQty
- if outputQty <= 0 {
- outputQty = 1
- }
- if outDef != nil && outDef.Stackable && outputQty > 1 {
- productName = fmt.Sprintf("%s x%d", productName, outputQty)
- }
-
- var matParts []string
- for _, e := range r.Consume {
- itemName := e.Items[0]
- if def, err := g.ItemStore.Load(e.Items[0]); err == nil {
- itemName = def.Name
- }
- if e.Qty > 1 {
- matParts = append(matParts, fmt.Sprintf("%s x%d", itemName, e.Qty))
- } else {
- matParts = append(matParts, itemName)
- }
- }
- matStr := strings.Join(matParts, ", ")
- levelStr := fmt.Sprint(r.Level)
- numStr := fmt.Sprintf("%d", i+1)
-
- canMake := skillLevel >= r.Level
- if canMake {
- productName = g.itemColorize(sess, outDef, productName)
- } else {
- productName = color.Render(mode, dimSpec, productName)
- matStr = color.Render(mode, dimSpec, matStr)
- levelStr = color.Render(mode, dimSpec, levelStr)
- numStr = color.Render(mode, dimSpec, numStr)
- }
-
- tbl.Rows = append(tbl.Rows, []string{numStr, productName, matStr, levelStr})
- }
-
- unicode := p.OptionBool("unicode")
- sess.WriteLine("")
- for _, line := range tbl.Render(unicode) {
- sess.WriteLine(line)
- }
-
- lastRecipeID, _ := p.Flags["last_fletch"].(string)
- hint := ""
- if lastRecipeID != "" {
- for _, r := range available {
- if r.ID == lastRecipeID {
- if outDef, err := g.ItemStore.Load(r.Output); err == nil {
- hint = outDef.Name
- }
- break
- }
- }
- }
-
- if hint != "" {
- sess.Write(fmt.Sprintf("Fletch what (enter for all %s): ", hint))
- } else {
- sess.Write("Fletch what: ")
- }
-
- sess.PendingMenu = recipeMenuData(available)
- sess.State = net.StateFletchProduct
-}
-
-func (g *Game) handleFletchProduct(sess *net.Session, input string) {
- p := sess.Player.(*player.Player)
- menuData := sess.PendingMenu
- sess.PendingMenu = nil
- sess.State = net.StateGame
-
- input = strings.TrimSpace(input)
-
- allRecipes, err := g.RecipeStore.LoadAll()
- if err != nil {
- g.reprompt(sess)
- return
- }
-
- var recipes []action.RecipeDef
- for _, entry := range menuData {
- rid := entry["recipe_id"]
- for _, r := range allRecipes {
- if r.ID == rid {
- recipes = append(recipes, r)
- break
- }
- }
- }
-
- if len(recipes) == 0 {
- g.reprompt(sess)
- return
- }
-
- sort.Slice(recipes, func(i, j int) bool {
- return recipes[i].Level < recipes[j].Level
- })
-
- lastRecipeID, _ := p.Flags["last_fletch"].(string)
-
- sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID)
- switch errMsg {
- case "ambiguous":
- sess.WriteLine("That's ambiguous.")
- g.reprompt(sess)
- return
- case "never_mind":
- sess.WriteLine("Never mind.")
- g.reprompt(sess)
- return
- }
-
- if !g.canDoFletchRecipe(p, sel.Recipe) {
- if p.Level(player.Fletching) < sel.Recipe.Level {
- sess.WriteLine(fmt.Sprintf("You need level %d fletching to make that.", sel.Recipe.Level))
- } else {
- sess.WriteLine("You don't have the materials for that.")
- }
- g.reprompt(sess)
- return
- }
-
- g.startFletchAction(sess, p, sel.Recipe, sel.Count)
-}
-
func (g *Game) findFletchRecipesForItems(p *player.Player, itemAID, itemBID string) []action.RecipeDef {
allRecipes, err := g.RecipeStore.LoadAll()
if err != nil {
@@ -346,6 +204,17 @@ func (g *Game) findFletchRecipesForItems(p *player.Player, itemAID, itemBID stri
continue
}
+ if r.Tool != "" {
+ if r.Tool == toolTypeA && r.MatchesEntry(itemBID) {
+ matched = append(matched, r)
+ continue
+ }
+ if r.Tool == toolTypeB && r.MatchesEntry(itemAID) {
+ matched = append(matched, r)
+ continue
+ }
+ }
+
aMatch := false
bMatch := false
for _, e := range r.Consume {
diff --git a/internal/game/cmd_smelt.go b/internal/game/cmd_smelt.go
index a5bbc06..46f2607 100644
--- a/internal/game/cmd_smelt.go
+++ b/internal/game/cmd_smelt.go
@@ -48,7 +48,7 @@ func (g *Game) doSmelt(sess *net.Session, input string) {
if r.Type != "smelting" || !stationMatch(stationDefID, r.Station) || !r.MatchesEntry(itemID) {
continue
}
- if !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.Skill)) < r.Level {
+ if !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
continue
}
recipes = append(recipes, r)
@@ -81,7 +81,7 @@ func (g *Game) showSmeltMenu(sess *net.Session, p *player.Player, allRecipes []a
if r.Type != "smelting" || !stationMatch(stationDefID, r.Station) {
continue
}
- if seen[r.ID] || !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.Skill)) < r.Level {
+ if seen[r.ID] || !r.HasAllItemsQty(p.CountItem) || p.Level(player.SkillName(r.EffectiveSkill())) < r.Level {
continue
}
seen[r.ID] = true
diff --git a/internal/game/cmd_smith.go b/internal/game/cmd_smith.go
index f2787a5..b539640 100644
--- a/internal/game/cmd_smith.go
+++ b/internal/game/cmd_smith.go
@@ -6,9 +6,7 @@ import (
"strings"
"thehouseoficarus/internal/action"
- "thehouseoficarus/internal/color"
"thehouseoficarus/internal/net"
- "thehouseoficarus/internal/object"
"thehouseoficarus/internal/player"
)
@@ -103,162 +101,8 @@ func (g *Game) showSmithTable(sess *net.Session, p *player.Player, barID string,
return
}
- sort.Slice(recipes, func(i, j int) bool {
- return recipes[i].Level < recipes[j].Level
- })
-
- mode := g.colorMode(sess)
- skillLevel := p.Level(player.Smithing)
- barCount := p.CountItem(barID)
- dimSpec := color.Parse("240")
-
- tbl := &Table{
- Title: titleCase(barName) + " Smithing",
- Columns: []string{"#", "Product", "Inputs", "Level Req."},
- }
-
- for i, r := range recipes {
- outDef, _ := g.ItemStore.Load(r.Output)
- productName := r.Output
- if outDef != nil {
- productName = outDef.Name
- }
-
- outputQty := r.OutputQty
- if outputQty <= 0 {
- outputQty = 1
- }
- if outDef != nil && outDef.Stackable && outputQty > 1 {
- productName = fmt.Sprintf("%s x%d", productName, outputQty)
- }
-
- bars := barsRequired(r, barID)
- inputStr := "1 bar"
- if bars > 1 {
- inputStr = fmt.Sprintf("%d bars", bars)
- }
- levelStr := fmt.Sprint(r.Level)
- numStr := fmt.Sprintf("%d", i+1)
-
- canMake := barCount >= bars && skillLevel >= r.Level
- if canMake {
- productName = g.itemColorize(sess, outDef, productName)
- } else {
- productName = color.Render(mode, dimSpec, productName)
- inputStr = color.Render(mode, dimSpec, inputStr)
- levelStr = color.Render(mode, dimSpec, levelStr)
- numStr = color.Render(mode, dimSpec, numStr)
- }
-
- tbl.Rows = append(tbl.Rows, []string{numStr, productName, inputStr, levelStr})
- }
-
- unicode := p.OptionBool("unicode")
- sess.WriteLine("")
- for _, line := range tbl.Render(unicode) {
- sess.WriteLine(line)
- }
-
lastFlag := fmt.Sprintf("last_smith_%s", barID)
- lastRecipeID, _ := p.Flags[lastFlag].(string)
- hint := ""
- if lastRecipeID != "" {
- for _, r := range recipes {
- if r.ID == lastRecipeID {
- if outDef, err := g.ItemStore.Load(r.Output); err == nil {
- hint = outDef.Name
- }
- break
- }
- }
- }
-
- if hint != "" {
- sess.Write(fmt.Sprintf("Produce what (enter for all %s): ", hint))
- } else {
- sess.Write("Produce what: ")
- }
-
- sess.PendingRecipeID = barID
- sess.State = net.StateSmithProduct
-}
-
-func (g *Game) handleSmithProduct(sess *net.Session, input string) {
- p := sess.Player.(*player.Player)
- barID := sess.PendingRecipeID
- sess.PendingRecipeID = ""
- sess.State = net.StateGame
-
- input = strings.TrimSpace(input)
-
- allRecipes, err := g.RecipeStore.LoadAll()
- if err != nil {
- g.reprompt(sess)
- return
- }
- var recipes []action.RecipeDef
- for _, r := range allRecipes {
- if r.Type == "smithing" && r.MatchesEntry(barID) {
- recipes = append(recipes, r)
- }
- }
-
- sort.Slice(recipes, func(i, j int) bool {
- return recipes[i].Level < recipes[j].Level
- })
-
- lastFlag := fmt.Sprintf("last_smith_%s", barID)
- lastRecipeID, _ := p.Flags[lastFlag].(string)
-
- sel, errMsg := g.resolveRecipeByInput(input, recipes, lastRecipeID)
- switch errMsg {
- case "ambiguous":
- sess.WriteLine("That's ambiguous.")
- g.reprompt(sess)
- return
- case "never_mind":
- sess.WriteLine("Never mind.")
- g.reprompt(sess)
- return
- }
-
- skillLevel := p.Level(player.Smithing)
- if skillLevel < sel.Recipe.Level {
- sess.WriteLine(fmt.Sprintf("You need level %d smithing to make that.", sel.Recipe.Level))
- g.reprompt(sess)
- return
- }
- if !sel.Recipe.HasAllItemsQty(p.CountItem) {
- sess.WriteLine("You don't have enough bars.")
- g.reprompt(sess)
- return
- }
-
- if p.Flags == nil {
- p.Flags = make(map[string]any)
- }
- p.Flags[lastFlag] = sel.Recipe.ID
- g.AccountStore.SaveCharacter(p)
-
- g.startProductionFromRecipe(sess, p, sel.Recipe, sel.Count)
-}
-
-func (g *Game) hasToolType(p *player.Player, toolType string) bool {
- if itemID, ok := p.Equipment[object.SlotMainHand]; ok {
- if def, err := g.ItemStore.Load(itemID); err == nil && def.ToolType == toolType {
- return true
- }
- }
- for i := 0; i < 28; i++ {
- slot := p.InvSlot(i)
- if slot == nil {
- continue
- }
- if def, err := g.ItemStore.Load(slot.ItemID); err == nil && def.ToolType == toolType {
- return true
- }
- }
- return false
+ g.showProductionTable(sess, p, recipes, titleCase(barName)+" Smithing", "smithing", lastFlag, "Produce", false)
}
func hasSmithingRecipes(allRecipes []action.RecipeDef, barID string) bool {
@@ -292,21 +136,6 @@ func findSmithableBars(allRecipes []action.RecipeDef, p *player.Player) []string
return bars
}
-func barsRequired(r action.RecipeDef, barID string) int {
- for _, e := range r.Consume {
- for _, id := range e.Items {
- if id == barID {
- qty := e.Qty
- if qty <= 0 {
- qty = 1
- }
- return qty
- }
- }
- }
- return 1
-}
-
func barMenuData(barIDs []string) []map[string]string {
out := make([]map[string]string, len(barIDs))
for i, id := range barIDs {
diff --git a/internal/game/cmd_use.go b/internal/game/cmd_use.go
index 8b8f43e..4d4ce88 100644
--- a/internal/game/cmd_use.go
+++ b/internal/game/cmd_use.go
@@ -86,7 +86,7 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName,
if !r.HasAllItemsQty(p.CountItem) {
continue
}
- skillLevel := p.Level(player.SkillName(r.Skill))
+ skillLevel := p.Level(player.SkillName(r.EffectiveSkill()))
if skillLevel < r.Level {
continue
}
@@ -171,7 +171,53 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName,
itemBID := matchesB[0].ID
+ craftRecipes := g.findCraftRecipesForItems(p, itemAID, itemBID)
fletchRecipes := g.findFletchRecipesForItems(p, itemAID, itemBID)
+
+ if len(craftRecipes) > 0 && len(fletchRecipes) > 0 {
+ var menu []map[string]string
+ var names []string
+ for _, r := range craftRecipes {
+ menu = append(menu, map[string]string{"recipe_id": r.ID})
+ outDef, _ := g.ItemStore.Load(r.Output)
+ name := r.Output
+ if outDef != nil {
+ name = outDef.Name
+ }
+ names = append(names, fmt.Sprintf("%s (Crafting)", name))
+ }
+ for _, r := range fletchRecipes {
+ menu = append(menu, map[string]string{"fletch_recipe_id": r.ID})
+ outDef, _ := g.ItemStore.Load(r.Output)
+ name := r.Output
+ if outDef != nil {
+ name = outDef.Name
+ }
+ names = append(names, fmt.Sprintf("%s (Fletching)", name))
+ }
+ sess.PendingMenu = menu
+ sess.State = net.StateRecipeChoice
+ g.showMenuTable(sess, "What would you like to make?", names)
+ return
+ }
+
+ if len(craftRecipes) > 0 {
+ var available []action.RecipeDef
+ for _, r := range craftRecipes {
+ if g.canDoCraftRecipe(p, &r) {
+ available = append(available, r)
+ }
+ }
+ if len(available) == 1 {
+ g.startCraftRecipe(sess, p, &available[0], 0)
+ return
+ }
+ if len(available) > 1 {
+ g.showProductionTable(sess, p, available, "Crafting", "crafting", "last_craft", "Craft", false)
+ return
+ }
+ }
+
if len(fletchRecipes) > 0 {
var available []action.RecipeDef
for _, r := range fletchRecipes {
@@ -184,7 +230,7 @@ func (g *Game) doUseItemOnTarget(sess *net.Session, p *player.Player, itemAName,
return
}
if len(available) > 1 {
- g.showFletchTable(sess, p, available)
+ g.showProductionTable(sess, p, available, "Fletching", "fletching", "last_fletch", "Fletch", true)
return
}
}
diff --git a/internal/game/game.go b/internal/game/game.go
index ef81fca..a1cba83 100644
--- a/internal/game/game.go
+++ b/internal/game/game.go
@@ -126,10 +126,8 @@ func (g *Game) HandleSession(sess *net.Session, input string) {
g.handleRecipeChoice(sess, input)
case net.StateHowMany:
g.handleHowMany(sess, input)
- case net.StateSmithProduct:
- g.handleSmithProduct(sess, input)
- case net.StateFletchProduct:
- g.handleFletchProduct(sess, input)
+ case net.StateSmithProduct, net.StateFletchProduct, net.StateCraftProduct, net.StateProductChoice:
+ g.handleProductChoice(sess, input)
case net.StateColorChoice:
g.handleColorChoice(sess, input)
}
@@ -149,7 +147,7 @@ func classifyCommand(cmd string) CommandClass {
"attack", "kill",
"north", "n", "south", "s", "east", "e",
"west", "w", "up", "u", "down", "d",
- "quit", "use", "burn", "stoke", "search", "walk", "cook", "smelt", "smith":
+ "quit", "use", "burn", "stoke", "search", "walk", "cook", "smelt", "smith", "craft":
return ClassActive
case "eat", "fletch":
return ClassFree
@@ -378,6 +376,9 @@ func (g *Game) executeCommand(sess *net.Session, cmd string, args []string, rawI
case "smith":
g.doSmith(sess, strings.Join(args, " "))
return
+ case "craft":
+ g.doCraft(sess, strings.Join(args, " "))
+ return
case "eat":
g.doEat(sess, strings.Join(args, " "))
return
diff --git a/internal/net/server.go b/internal/net/server.go
index e74f15f..f6776fc 100644
--- a/internal/net/server.go
+++ b/internal/net/server.go
@@ -35,6 +35,8 @@ const (
StateHowMany
StateSmithProduct
StateFletchProduct
+ StateCraftProduct
+ StateProductChoice
StateColorChoice
)
@@ -47,6 +49,9 @@ type Session struct {
PendingPass string
PendingMenu []map[string]string
PendingRecipeID string
+ PendingSkill string
+ PendingLastFlag string
+ PendingBackground bool
Disconnecting bool
DisconnectTicks int
}