1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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")
}
})
}
|