aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_wear.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/cmd_wear.go')
-rw-r--r--internal/game/cmd_wear.go56
1 files changed, 45 insertions, 11 deletions
diff --git a/internal/game/cmd_wear.go b/internal/game/cmd_wear.go
index a02fd3b..5a293de 100644
--- a/internal/game/cmd_wear.go
+++ b/internal/game/cmd_wear.go
@@ -101,7 +101,7 @@ func (g *Game) doWear(sess *net.Session, input string) {
sess.WriteLine("Your inventory is full.")
return
}
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: existingItemID, Quantity: 1})
+ p.SetInvSlot(freeSlot, g.displacedEquipSlot(p, existingItemID))
}
if slot.Quantity > 1 {
@@ -127,6 +127,24 @@ func (g *Game) doWear(sess *net.Session, input string) {
sess.WriteLine(fmt.Sprintf("You %s %s.", verb, g.itemColorize(sess, def, match.Name)))
}
+// displacedEquipSlot builds the inventory slot that receives an item
+// displaced by a swap. The item's equipped quality (EquipQuality, kept
+// because the equipment entry alone cannot carry a charge) is stamped onto
+// the returned stack and cleared from the map, so the returned item keeps
+// merging and charging like one carried normally; leaving the entry behind
+// would let act_burn charge a stale record or a zeroed slot.
+func (g *Game) displacedEquipSlot(p *player.Player, itemID string) *player.InventorySlot {
+ slot := &player.InventorySlot{ItemID: itemID, Quantity: 1}
+ if q, ok := p.EquipQuality[itemID]; ok {
+ slot.Quality = q
+ if def, _ := g.ItemStore.Load(itemID); def != nil {
+ slot.MaxQuality = def.MaxQuality
+ }
+ delete(p.EquipQuality, itemID)
+ }
+ return slot
+}
+
func (g *Game) equipAmmo(sess *net.Session, p *player.Player, invIdx int, slot *player.InventorySlot, def *item.ItemDef, qty int) {
transferQty := slot.Quantity
if qty > 0 && qty < transferQty {
@@ -135,7 +153,12 @@ func (g *Game) equipAmmo(sess *net.Session, p *player.Player, invIdx int, slot *
existingAmmoID, hasAmmo := p.Equipment[item.SlotAmmo]
if hasAmmo && existingAmmoID != slot.ItemID {
- g.unequipAmmo(p)
+ // The equipped stack stays equipped when there is nowhere to put
+ // it; equipping the new stack would otherwise strand the old one.
+ if !g.unequipAmmo(p) {
+ sess.WriteLine("Your inventory is full.")
+ return
+ }
}
if slot.Quantity <= transferQty {
@@ -156,26 +179,35 @@ func (g *Game) equipAmmo(sess *net.Session, p *player.Player, invIdx int, slot *
sess.WriteLine(fmt.Sprintf("You equip %s (x%d).", displayName, p.AmmoQty))
}
-func (g *Game) unequipAmmo(p *player.Player) {
+// unequipAmmo returns the equipped ammo to the inventory and reports whether
+// the equipped stack is now stored. With nowhere to put it the ammo stays
+// equipped: the equipment entry is only cleared once the stack has actually
+// been merged into an inventory stack or placed in a free slot.
+func (g *Game) unequipAmmo(p *player.Player) bool {
ammoID, ok := p.Equipment[item.SlotAmmo]
if !ok || p.AmmoQty <= 0 {
- return
+ return true
}
+ quality, maxQuality := g.pickedStackProps(ammoID)
for i := 0; i < 28; i++ {
s := p.InvSlot(i)
- if s != nil && s.ItemID == ammoID {
+ // Only a stack with the properties a fresh stack gets may absorb the
+ // equipped stack (see pickedStackProps).
+ if s != nil && s.ItemID == ammoID && s.Quality == quality && s.MaxQuality == maxQuality {
s.Quantity += p.AmmoQty
delete(p.Equipment, item.SlotAmmo)
p.AmmoQty = 0
- return
+ return true
}
}
freeSlot := p.FirstFreeSlot()
- if freeSlot >= 0 {
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: ammoID, Quantity: p.AmmoQty})
+ if freeSlot < 0 {
+ return false
}
+ p.SetInvSlot(freeSlot, g.newInventorySlot(ammoID, p.AmmoQty))
delete(p.Equipment, item.SlotAmmo)
p.AmmoQty = 0
+ return true
}
func (g *Game) doWearAll(sess *net.Session) {
@@ -235,8 +267,10 @@ func (g *Game) doWearAll(sess *net.Session) {
continue
}
existingID, hasAmmo := p.Equipment[item.SlotAmmo]
- if hasAmmo && existingID != best.itemID {
- g.unequipAmmo(p)
+ // No free slot for the equipped stack: leave it equipped and
+ // skip this item rather than delete the old stack.
+ if hasAmmo && existingID != best.itemID && !g.unequipAmmo(p) {
+ continue
}
transferQty := invSlot.Quantity
p.SetInvSlot(best.invSlot, nil)
@@ -256,7 +290,7 @@ func (g *Game) doWearAll(sess *net.Session) {
if freeSlot == -1 {
continue
}
- p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: existing, Quantity: 1})
+ p.SetInvSlot(freeSlot, g.displacedEquipSlot(p, existing))
}
invSlot := p.InvSlot(best.invSlot)