package game import ( "fmt" "strings" "thehouseoficarus/internal/item" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) executeRemove(sess *net.Session, args []string, rawInput string) { g.doRemove(sess, strings.Join(args, " ")) } func (g *Game) doRemove(sess *net.Session, input string) { p := sess.Player lower := strings.ToLower(strings.TrimSpace(input)) if lower == "all" { g.doRemoveAll(sess) return } if lower == "" { sess.WriteLine("Remove what?") return } g.cancelAction(p) qty, itemName := parseQty(input) var foundSlot item.EquipSlot var foundItemID string for _, slot := range EquipSlots { itemID, ok := p.Equipment[slot] if !ok { continue } if strings.EqualFold(string(slot), itemName) { foundSlot = slot foundItemID = itemID break } def, err := g.ItemStore.Load(itemID) if err != nil { continue } if def.MatchesName(itemName) { foundSlot = slot foundItemID = itemID break } } if foundSlot == "" { sess.WriteLine(fmt.Sprintf("You aren't wearing any '%s'.", input)) return } if foundSlot == item.SlotAmmo && p.AmmoQty > 0 { g.removeAmmo(sess, p, qty) return } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Nowhere to put that!") return } delete(p.Equipment, foundSlot) invSlot := &player.InventorySlot{ItemID: foundItemID, Quantity: 1} if q, ok := p.EquipQuality[foundItemID]; ok { invSlot.Quality = q if def, _ := g.ItemStore.Load(foundItemID); def != nil { invSlot.MaxQuality = def.MaxQuality } delete(p.EquipQuality, foundItemID) } p.SetInvSlot(freeSlot, invSlot) g.saveCharacter(p) name := foundItemID def, _ := g.ItemStore.Load(foundItemID) if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You remove %s.", g.itemColorize(sess, def, name))) } func (g *Game) removeAmmo(sess *net.Session, p *player.Player, qty int) { ammoID := p.Equipment[item.SlotAmmo] removeQty := p.AmmoQty if qty > 0 && qty < removeQty { removeQty = qty } quality, maxQuality := g.pickedStackProps(ammoID) for i := 0; i < 28; i++ { s := p.InvSlot(i) // 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 += removeQty p.AmmoQty -= removeQty if p.AmmoQty <= 0 { delete(p.Equipment, item.SlotAmmo) p.AmmoQty = 0 } g.saveCharacter(p) def, _ := g.ItemStore.Load(ammoID) name := ammoID if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You unequip %s (x%d).", g.itemColorize(sess, def, name), removeQty)) return } } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Nowhere to put that!") return } p.SetInvSlot(freeSlot, g.newInventorySlot(ammoID, removeQty)) p.AmmoQty -= removeQty if p.AmmoQty <= 0 { delete(p.Equipment, item.SlotAmmo) p.AmmoQty = 0 } g.saveCharacter(p) def, _ := g.ItemStore.Load(ammoID) name := ammoID if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You unequip %s (x%d).", g.itemColorize(sess, def, name), removeQty)) } func (g *Game) doRemoveAll(sess *net.Session) { p := sess.Player if len(p.Equipment) == 0 { sess.WriteLine("You aren't wearing anything.") return } needed := len(p.Equipment) if needed > p.FreeSlots() { sess.WriteLine("You don't have room to remove everything!") return } g.cancelAction(p) for _, slot := range EquipSlots { itemID, ok := p.Equipment[slot] if !ok { continue } if slot == item.SlotAmmo && p.AmmoQty > 0 { g.removeAllAmmo(sess, p, itemID) continue } freeSlot := p.FirstFreeSlot() delete(p.Equipment, slot) invSlot := &player.InventorySlot{ItemID: itemID, Quantity: 1} if q, ok := p.EquipQuality[itemID]; ok { invSlot.Quality = q if def, _ := g.ItemStore.Load(itemID); def != nil { invSlot.MaxQuality = def.MaxQuality } delete(p.EquipQuality, itemID) } p.SetInvSlot(freeSlot, invSlot) name := itemID def, _ := g.ItemStore.Load(itemID) if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You remove %s.", g.itemColorize(sess, def, name))) } g.saveCharacter(p) } // removeAllAmmo moves the whole equipped ammo stack into the inventory. The // equipment entry is only cleared once the stack has been merged into an // existing stack or placed in a free slot, so a full inventory reports a // failure instead of silently destroying the ammo. func (g *Game) removeAllAmmo(sess *net.Session, p *player.Player, itemID string) { quality, maxQuality := g.pickedStackProps(itemID) for i := 0; i < 28; i++ { s := p.InvSlot(i) // Only a stack with the properties a fresh stack gets may absorb the // equipped stack (see pickedStackProps). if s != nil && s.ItemID == itemID && s.Quality == quality && s.MaxQuality == maxQuality { s.Quantity += p.AmmoQty delete(p.Equipment, item.SlotAmmo) p.AmmoQty = 0 def, _ := g.ItemStore.Load(itemID) name := itemID if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You remove %s.", g.itemColorize(sess, def, name))) return } } freeSlot := p.FirstFreeSlot() if freeSlot < 0 { // Nowhere to put the equipped stack: leave it equipped and report // nothing removed. sess.WriteLine("Nowhere to put that!") return } p.SetInvSlot(freeSlot, g.newInventorySlot(itemID, p.AmmoQty)) delete(p.Equipment, item.SlotAmmo) p.AmmoQty = 0 def, _ := g.ItemStore.Load(itemID) name := itemID if def != nil { name = def.Name } sess.WriteLine(fmt.Sprintf("You remove %s.", g.itemColorize(sess, def, name))) }