diff options
Diffstat (limited to 'internal/game/polish_wear_swap_quality_test.go')
| -rw-r--r-- | internal/game/polish_wear_swap_quality_test.go | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/internal/game/polish_wear_swap_quality_test.go b/internal/game/polish_wear_swap_quality_test.go new file mode 100644 index 0000000..bb9e996 --- /dev/null +++ b/internal/game/polish_wear_swap_quality_test.go @@ -0,0 +1,140 @@ +package game + +// Regression: swapping worn equipment used to return the displaced item as a +// raw Quality 0/MaxQuality 0 slot and leave its stale EquipQuality entry +// behind. Reachable with the shipped lighter (the only max_quality > 0 item): +// wielding a weapon after the lighter returned it zeroed, and act_burn charged +// the stale equipment record instead of the carried stack. The displaced +// item's equipped quality must move onto the returned slot and out of the map. + +import ( + "path/filepath" + "testing" + + "thehouseoficarus/internal/item" + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" +) + +const polishLighterYAML = `id: polish_lighter +name: polish lighter +stackable: false +max_quality: 100 +equipment: + slot: main_hand + type: tool +tool: + type: fire +` + +const polishBladeYAML = `id: polish_blade +name: polish blade +stackable: false +equipment: + slot: main_hand + type: melee_weapon +` + +func seedPolishWearItems(t *testing.T, dir string) { + t.Helper() + writeSeedFile(t, filepath.Join(dir, "items", "polish_lighter.yaml"), []byte(polishLighterYAML)) + writeSeedFile(t, filepath.Join(dir, "items", "polish_blade.yaml"), []byte(polishBladeYAML)) +} + +// carriedInventSlot returns the first inventory slot holding itemID. +func carriedInventSlot(p *player.Player, itemID string) *player.InventorySlot { + for i := 0; i < 28; i++ { + if s := p.InvSlot(i); s != nil && s.ItemID == itemID { + return s + } + } + return nil +} + +func TestWearSwapReturnsEquippedQualityToInventory(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice") + p := h.seedCharacter("alice", "alice") + seedPolishWearItems(t, h.dir) + + sess := &net.Session{Conn: newChanConn(), Player: p} + sess.SetState(net.StateGame) + + h.g.RunOnOwner(func() { + h.g.ItemStore.Reload(h.dir) + p.SetInvSlot(0, h.g.newInventorySlot("polish_lighter", 1)) + + h.g.doWear(sess, "lighter") + if got := p.Equipment[item.SlotMainHand]; got != "polish_lighter" { + t.Fatalf("lighter not equipped: %q", got) + } + // Burn two charges while the lighter is equipped. + for i := 0; i < 2; i++ { + if !h.g.consumeFireTool(sess, p, "polish_lighter") { + t.Fatal("consumeFireTool refused a fresh lighter") + } + } + if got := p.EquipQuality["polish_lighter"]; got != 98 { + t.Fatalf("equipped lighter charge = %d, want 98", got) + } + + // Wielding a weapon displaces the lighter back into the inventory. + p.SetInvSlot(1, h.g.newInventorySlot("polish_blade", 1)) + h.g.doWear(sess, "blade") + if got := p.Equipment[item.SlotMainHand]; got != "polish_blade" { + t.Fatalf("blade not equipped: %q", got) + } + + lighter := carriedInventSlot(p, "polish_lighter") + if lighter == nil { + t.Fatal("the displaced lighter was not returned to the inventory") + } + if lighter.Quality != 98 || lighter.MaxQuality != 100 { + t.Errorf("returned lighter = %+v, want quality 98/100", lighter) + } + if _, ok := p.EquipQuality["polish_lighter"]; ok { + t.Error("stale EquipQuality entry left behind after the swap") + } + + // act_burn must charge the carried stack, not a stale equipment record. + if !h.g.consumeFireTool(sess, p, "polish_lighter") { + t.Fatal("consumeFireTool refused the carried lighter stack") + } + if lighter.Quality != 97 { + t.Errorf("carried lighter charge = %d, want 97", lighter.Quality) + } + }) +} + +func TestWearAllSwapReturnsEquippedQualityToInventory(t *testing.T) { + h := newHarness(t) + h.seedAccount("alice") + p := h.seedCharacter("alice", "alice") + seedPolishWearItems(t, h.dir) + + sess := &net.Session{Conn: newChanConn(), Player: p} + sess.SetState(net.StateGame) + + h.g.RunOnOwner(func() { + h.g.ItemStore.Reload(h.dir) + p.SetInvSlot(0, h.g.newInventorySlot("polish_lighter", 1)) + h.g.doWear(sess, "lighter") + if got := p.EquipQuality["polish_lighter"]; got != 100 { + t.Fatalf("equipped lighter charge = %d, want 100", got) + } + + p.SetInvSlot(1, h.g.newInventorySlot("polish_blade", 1)) + h.g.doWearAll(sess) + + lighter := carriedInventSlot(p, "polish_lighter") + if lighter == nil { + t.Fatal("wear all did not return the displaced lighter") + } + if lighter.Quality != 100 || lighter.MaxQuality != 100 { + t.Errorf("returned lighter = %+v, want quality 100/100", lighter) + } + if _, ok := p.EquipQuality["polish_lighter"]; ok { + t.Error("stale EquipQuality entry left behind by wear all") + } + }) +} |
