diff options
Diffstat (limited to 'internal/game/hardening_craft_menu_skill_test.go')
| -rw-r--r-- | internal/game/hardening_craft_menu_skill_test.go | 91 |
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()) + } + }) +} |
