package game import ( "fmt" "strings" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" ) func (g *Game) doGet(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) ground := g.World.GroundItems(p.RoomID) if len(ground) == 0 { sess.WriteLine("There's nothing on the ground to pick up.") return } qty, itemName := parseQty(input) matches := g.findGroundMatches(itemName, p.RoomID) if len(matches) == 0 { sess.WriteLine(fmt.Sprintf("There's no '%s' here.", itemName)) return } if len(matches) > 1 { unique := uniqueItemNames(matches) if len(unique) > 1 { g.showWhichOne(sess, matches) return } } itemID := matches[0].ID if itemID == "credits" { g.pickupCredits(sess, p, itemID) p.ActionState = &ActionState{Type: ActionPickingUp, TargetName: "credits"} return } def, _ := g.ItemStore.Load(itemID) name := itemID if def != nil { name = def.Name } p.ActionState = &ActionState{Type: ActionPickingUp, TargetName: name} available := 0 if gqty, ok := ground[itemID]; ok { available = gqty } if available <= 0 { sess.WriteLine("There's none of that here.") return } if qty == 0 { if def != nil && def.Stackable { qty = available } else { qty = 1 } } else if qty > available { qty = available } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is full.") return } if def != nil && def.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == itemID { if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name); !ok { sess.WriteLine("That's not yours!") return } slot.Quantity += qty g.AccountStore.SaveCharacter(p) sess.WriteLine(fmt.Sprintf("You pick up %d x %s. (now %d)", qty, g.itemColorize(sess, def, def.Name), slot.Quantity)) return } } freeSlot = p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is full.") return } if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name); !ok { sess.WriteLine("That's not yours!") return } p.SetInvSlot(freeSlot, g.newInventorySlot(itemID, qty)) g.AccountStore.SaveCharacter(p) if qty == 1 { sess.WriteLine(fmt.Sprintf("You pick up a %s.", g.itemColorize(sess, def, def.Name))) } else { sess.WriteLine(fmt.Sprintf("You pick up %d x %s.", qty, g.itemColorize(sess, def, def.Name))) } return } picked := 0 for picked < qty { fs := p.FirstFreeSlot() if fs == -1 { break } if _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 1, p.Name); !ok { break } p.SetInvSlot(fs, &player.InventorySlot{ItemID: itemID, Quantity: 1}) picked++ } g.AccountStore.SaveCharacter(p) if picked == 0 { sess.WriteLine("Your inventory is full.") } else if picked == 1 { sess.WriteLine(fmt.Sprintf("You pick up a %s.", g.itemColorize(sess, def, name))) } else { sess.WriteLine(fmt.Sprintf("You pick up %d x %s.", picked, g.itemColorize(sess, def, name))) } } func (g *Game) doGetAllNamed(sess *net.Session, input string) { p := sess.Player g.cancelAction(p) ground := g.World.GroundItems(p.RoomID) if len(ground) == 0 { sess.WriteLine("There's nothing on the ground to pick up.") return } matches := g.findGroundMatches(input, p.RoomID) if len(matches) == 0 { sess.WriteLine(fmt.Sprintf("There's no '%s' here.", input)) return } if len(matches) > 1 { unique := uniqueItemNames(matches) if len(unique) > 1 { g.showWhichOne(sess, matches) return } } itemID := matches[0].ID if itemID == "credits" { g.pickupCredits(sess, p, itemID) return } def, _ := g.ItemStore.Load(itemID) available := 0 if gqty, ok := ground[itemID]; ok { available = gqty } if available <= 0 { sess.WriteLine("There's none of that here.") return } wanted := available if def != nil && !def.Stackable { free := p.FreeSlots() if wanted > free { wanted = free } } if wanted <= 0 { sess.WriteLine("Your inventory is full.") return } name := itemID if def != nil { name = def.Name } coloredName := g.itemColorize(sess, def, name) if def != nil && def.Stackable { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == itemID { removed, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, wanted, p.Name) if !ok { sess.WriteLine("That's not yours!") return } slot.Quantity += removed g.AccountStore.SaveCharacter(p) sess.WriteLine(fmt.Sprintf("You pick up %d x %s. (now %d)", removed, coloredName, slot.Quantity)) return } } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { sess.WriteLine("Your inventory is full.") return } removed, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, wanted, p.Name) if !ok { sess.WriteLine("That's not yours!") return } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: itemID, Quantity: removed}) g.AccountStore.SaveCharacter(p) if removed == 1 { sess.WriteLine(fmt.Sprintf("You pick up a %s.", coloredName)) } else { sess.WriteLine(fmt.Sprintf("You pick up %d x %s.", removed, coloredName)) } return } picked := 0 for picked < wanted { fs := p.FirstFreeSlot() if fs == -1 { break } _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 1, p.Name) if !ok { break } p.SetInvSlot(fs, &player.InventorySlot{ItemID: itemID, Quantity: 1}) picked++ } g.AccountStore.SaveCharacter(p) if picked == 0 { sess.WriteLine("Your inventory is full.") } else if picked == 1 { sess.WriteLine(fmt.Sprintf("You pick up a %s.", coloredName)) } else { sess.WriteLine(fmt.Sprintf("You pick up %d x %s.", picked, coloredName)) } if picked < available { sess.WriteLine(fmt.Sprintf("You're only able to take %d x %s!", picked, coloredName)) } } func (g *Game) doGetAll(sess *net.Session) { p := sess.Player g.cancelAction(p) ground := g.World.GroundItems(p.RoomID) if len(ground) == 0 { sess.WriteLine("There's nothing on the ground to pick up.") return } var picked []string for itemID, qty := range ground { if qty <= 0 { continue } if itemID == "credits" { taken, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 999999, p.Name) if !ok { continue } p.Credits += taken if taken == 1 { picked = append(picked, "1 credit") } else { picked = append(picked, fmt.Sprintf("%d credits", taken)) } continue } def, _ := g.ItemStore.Load(itemID) for qty > 0 { if def != nil && def.Stackable { stacked := false for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot != nil && slot.ItemID == itemID { _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name) if !ok { qty = 0 stacked = true break } slot.Quantity += qty picked = append(picked, fmt.Sprintf("%s (now %d)", g.itemColorize(sess, def, def.Name), slot.Quantity)) stacked = true qty = 0 break } } if stacked { break } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { if len(picked) > 0 { sess.WriteLine("You can't hold everything but you picked up:") formatPickupList(sess, picked) } else { sess.WriteLine("Your inventory is full!") } g.AccountStore.SaveCharacter(p) return } _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, qty, p.Name) if !ok { break } p.SetInvSlot(freeSlot, g.newInventorySlot(itemID, qty)) name := itemID if def != nil { name = def.Name } picked = append(picked, g.itemColorize(sess, def, name)) break } freeSlot := p.FirstFreeSlot() if freeSlot == -1 { if len(picked) > 0 { sess.WriteLine("You can't hold everything but you picked up:") formatPickupList(sess, picked) } else { sess.WriteLine("Your inventory is full!") } g.AccountStore.SaveCharacter(p) return } take := 1 _, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, take, p.Name) if !ok { break } p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: itemID, Quantity: take}) name := itemID if def != nil { name = def.Name } picked = append(picked, g.itemColorize(sess, def, name)) qty -= take } } g.AccountStore.SaveCharacter(p) if len(picked) == 0 { sess.WriteLine("Your inventory is full.") } else { sess.Write("You picked up: ") formatPickupList(sess, picked) } } func (g *Game) pickupCredits(sess *net.Session, p *player.Player, itemID string) { qty, ok := g.World.RemoveReservedGroundItem(p.RoomID, itemID, 999999, p.Name) if !ok { sess.WriteLine("That's not yours!") return } if qty <= 0 { return } p.Credits += qty g.AccountStore.SaveCharacter(p) if qty == 1 { sess.WriteLine(g.colorize(sess, "credits_pickup", "You pick up 1 credit.")) } else { sess.WriteLine(g.colorize(sess, "credits_pickup", fmt.Sprintf("You pick up %d credits. (total: %d)", qty, p.Credits))) } } func (g *Game) collectMatches(input string, each func(func(itemID string, slot int) bool)) []itemMatch { var matches []itemMatch each(func(itemID string, slot int) bool { def, err := g.ItemStore.Load(itemID) if err != nil { return true } if def.MatchesName(input) { matches = append(matches, itemMatch{ID: itemID, Name: def.Name, Slot: slot}) } return true }) return matches } func (g *Game) findGroundMatches(input string, roomID int) []itemMatch { ground := g.World.GroundItems(roomID) return g.collectMatches(input, func(yield func(string, int) bool) { for itemID := range ground { if !yield(itemID, -1) { return } } }) } func (g *Game) findInventoryMatches(input string, p *player.Player) []itemMatch { return g.collectMatches(input, func(yield func(string, int) bool) { for i := 0; i < 28; i++ { slot := p.InvSlot(i) if slot == nil { continue } if !yield(slot.ItemID, i) { return } } }) } func (g *Game) executeGet(sess *net.Session, args []string, rawInput string) { if len(args) == 0 { sess.WriteLine("Get what?") } else if args[0] == "all" { if len(args) == 1 { g.doGetAll(sess) } else { g.doGetAllNamed(sess, strings.Join(args[1:], " ")) } } else { g.doGet(sess, strings.Join(args, " ")) } }