aboutsummaryrefslogtreecommitdiff
path: root/internal/game/hardening_craft_menu_skill_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/hardening_craft_menu_skill_test.go')
-rw-r--r--internal/game/hardening_craft_menu_skill_test.go91
1 files changed, 91 insertions, 0 deletions
diff --git a/internal/game/hardening_craft_menu_skill_test.go b/internal/game/hardening_craft_menu_skill_test.go
new file mode 100644
index 0000000..9b4e8c7
--- /dev/null
+++ b/internal/game/hardening_craft_menu_skill_test.go
@@ -0,0 +1,91 @@
+package game
+
+// Regression: the multi-match production menu (craft <name>/mix/construct)
+// must pass the real lowercase recipe type as PendingSkill. It previously
+// passed the capitalised display label ("Crafting"), which
+// handleProductChoice looks up with player.SkillName — a map miss that
+// resolves to level 1, so every recipe above level 1 was refused even for a
+// level-50 crafter.
+
+import (
+ "testing"
+
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+)
+
+const craftMenuIngotYAML = `id: test_ingot
+name: test ingot
+stackable: true
+value: 1
+`
+
+const craftMenuSwordYAML = `id: test_iron_sword
+name: iron sword
+stackable: false
+value: 5
+craft:
+ - type: crafting
+ ingredients:
+ - items:
+ - test_ingot
+ quantity: 1
+ level: 1
+ output_qty: 1
+`
+
+const craftMenuPlateYAML = `id: test_iron_plate
+name: iron plate
+stackable: false
+value: 50
+craft:
+ - type: crafting
+ ingredients:
+ - items:
+ - test_ingot
+ quantity: 1
+ level: 40
+ output_qty: 1
+`
+
+func TestCraftMenuResolvesRealSkillForMultiMatch(t *testing.T) {
+ dir := t.TempDir()
+ seedWorld(t, dir)
+ writeDataFile(t, dir, "items", "test_ingot.yaml", craftMenuIngotYAML)
+ writeDataFile(t, dir, "items", "test_iron_sword.yaml", craftMenuSwordYAML)
+ writeDataFile(t, dir, "items", "test_iron_plate.yaml", craftMenuPlateYAML)
+
+ g := newHardeningGame(t, dir)
+
+ g.RunOnOwner(func() {
+ p := player.New("alice")
+ p.RoomID = 1
+ p.Skills[player.Crafting] = player.XPForLevel(50)
+ p.SetInvSlot(0, &player.InventorySlot{ItemID: "test_ingot", Quantity: 1})
+
+ conn := newChanConn()
+ sess := &net.Session{Conn: conn, Player: p}
+ sess.SetState(net.StateGame)
+
+ // "iron" matches both products, forcing the multi-match menu path.
+ g.doCraft(sess, "iron")
+
+ if sess.PendingSkill != "crafting" {
+ t.Fatalf("PendingSkill = %q, want %q (a display label is not a skill)",
+ sess.PendingSkill, "crafting")
+ }
+ if len(sess.PendingMenu) != 2 {
+ t.Fatalf("menu entries = %d, want 2 (iron sword, iron plate)", len(sess.PendingMenu))
+ }
+
+ // Choice 2 is iron plate (level 40, the only row above level 1).
+ g.handleProductChoice(sess, "2")
+
+ if p.Action == nil {
+ t.Fatalf("level-50 crafter could not start the level-40 recipe; output=%q", conn.Bytes())
+ }
+ if p.Action.TargetID != "test_iron_plate" {
+ t.Fatalf("started recipe %q, want test_iron_plate; output=%q", p.Action.TargetID, conn.Bytes())
+ }
+ })
+}