aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_bank.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-19 13:28:06 -0400
committerhistoria <[not public]>2026-06-19 13:28:06 -0400
commit3a58125d14bb307f861b38c6c5b0a63babde7e08 (patch)
treebd89e866447d55e6dffd447d8ef5fabf9b8fbe9d /internal/game/cmd_bank.go
parent575a71dcfed3b9fa44af244836f638a23df05a9a (diff)
downloadthehouseoficarus-3a58125d14bb307f861b38c6c5b0a63babde7e08.tar.gz
feat: all skills kind of implemented, random prototype content added
Diffstat (limited to 'internal/game/cmd_bank.go')
-rw-r--r--internal/game/cmd_bank.go345
1 files changed, 345 insertions, 0 deletions
diff --git a/internal/game/cmd_bank.go b/internal/game/cmd_bank.go
new file mode 100644
index 0000000..ff3a3ac
--- /dev/null
+++ b/internal/game/cmd_bank.go
@@ -0,0 +1,345 @@
+package game
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+ "thehouseoficarus/internal/world"
+)
+
+func (g *Game) handleBankInput(sess *net.Session, input string) {
+ if sess.Player == nil {
+ sess.State = net.StateGame
+ g.writePrompt(sess)
+ return
+ }
+
+ input = strings.TrimSpace(input)
+ parts := strings.Fields(strings.ToLower(input))
+ if len(parts) == 0 {
+ g.showBankBrowse(sess)
+ return
+ }
+
+ cmd := parts[0]
+
+ switch cmd {
+ case "deposit":
+ if len(parts) < 2 {
+ sess.WriteLine("Deposit what?")
+ } else if parts[1] == "all" {
+ g.doBankDepositAll(sess)
+ } else {
+ g.doBankDeposit(sess, strings.Join(parts[1:], " "))
+ }
+ case "withdraw":
+ if len(parts) < 2 {
+ sess.WriteLine("Withdraw what?")
+ } else {
+ g.doBankWithdraw(sess, strings.Join(parts[1:], " "))
+ }
+ case "browse", "list":
+ g.showBankBrowse(sess)
+ case "leave", "bye", "exit", "quit":
+ g.leaveBank(sess)
+ return
+ default:
+ sess.WriteLine("Commands: deposit <item>, deposit all, withdraw <item>, browse, leave")
+ }
+ g.writeBankPrompt(sess)
+}
+
+func (g *Game) writeBankPrompt(sess *net.Session) {
+ sess.Write(fmt.Sprintf("\n%s", g.colorize(sess, "dialog", "Bank> ")))
+}
+
+func (g *Game) showBankBrowse(sess *net.Session) {
+ p, _ := sess.Player.(*player.Player)
+
+ unicode := p.OptionBool("unicode")
+
+ t := Table{
+ Title: "Bank Contents",
+ Columns: []string{"#", "Item", "Quantity"},
+ }
+
+ type bankEntry struct {
+ slot int
+ name string
+ id string
+ qty int
+ }
+
+ var entries []bankEntry
+ for _, i := range p.BankSlots() {
+ slot := p.BankSlot(i)
+ if slot == nil {
+ continue
+ }
+ def, _ := g.ItemStore.Load(slot.ItemID)
+ itemName := slot.ItemID
+ if def != nil {
+ itemName = def.Name
+ }
+ entries = append(entries, bankEntry{slot: i, name: itemName, id: slot.ItemID, qty: slot.Quantity})
+ }
+
+ if len(entries) == 0 {
+ sess.WriteLine("\nYour bank is empty.")
+ return
+ }
+
+ sort.Slice(entries, func(i, j int) bool {
+ return entries[i].slot < entries[j].slot
+ })
+
+ for _, e := range entries {
+ t.Rows = append(t.Rows, []string{
+ fmt.Sprintf("%d", e.slot+1),
+ g.colorize(sess, "item", e.name),
+ fmt.Sprintf("%d", e.qty),
+ })
+ }
+
+ for _, line := range t.Render(unicode) {
+ sess.WriteLine(line)
+ }
+}
+
+func (g *Game) doBankDeposit(sess *net.Session, input string) {
+ p, _ := sess.Player.(*player.Player)
+
+ matches := g.findInventoryMatches(input, p)
+ if len(matches) == 0 {
+ sess.WriteLine("You don't have that item.")
+ return
+ }
+
+ if len(matches) > 1 {
+ g.showWhichOne(sess, matches)
+ return
+ }
+
+ match := matches[0]
+
+ slot := p.InvSlot(match.Slot)
+ if slot == nil {
+ return
+ }
+
+ itemID := slot.ItemID
+ qty := slot.Quantity
+ def, _ := g.ItemStore.Load(itemID)
+
+ p.SetInvSlot(match.Slot, nil)
+
+ bankIdx := p.NextBankSlot()
+ p.SetBankSlot(bankIdx, &player.InventorySlot{
+ ItemID: itemID,
+ Quantity: qty,
+ Quality: slot.Quality,
+ })
+
+ g.AccountStore.SaveCharacter(p)
+
+ displayName := itemID
+ if def != nil {
+ displayName = def.Name
+ }
+ itemColor := g.itemColorize(sess, def, displayName)
+ if qty > 1 {
+ sess.WriteLine(fmt.Sprintf("You deposit %d %ss.", qty, itemColor))
+ } else {
+ sess.WriteLine(fmt.Sprintf("You deposit a %s.", itemColor))
+ }
+}
+
+func (g *Game) doBankDepositAll(sess *net.Session) {
+ p, _ := sess.Player.(*player.Player)
+
+ var deposited int
+ for i := 0; i < 28; i++ {
+ slot := p.InvSlot(i)
+ if slot == nil {
+ continue
+ }
+ bankIdx := p.NextBankSlot()
+ p.SetBankSlot(bankIdx, &player.InventorySlot{
+ ItemID: slot.ItemID,
+ Quantity: slot.Quantity,
+ Quality: slot.Quality,
+ })
+ p.SetInvSlot(i, nil)
+ deposited++
+ }
+
+ if deposited == 0 {
+ sess.WriteLine("Your inventory is already empty.")
+ return
+ }
+
+ g.AccountStore.SaveCharacter(p)
+
+ sess.WriteLine(fmt.Sprintf("You deposit %d item%s.", deposited, plural(deposited)))
+}
+
+func (g *Game) doBankWithdraw(sess *net.Session, input string) {
+ p, _ := sess.Player.(*player.Player)
+
+ freeSlot := p.FirstFreeSlot()
+ if freeSlot == -1 {
+ sess.WriteLine("Your inventory is full.")
+ return
+ }
+
+ var entries []struct {
+ slot int
+ name string
+ id string
+ qty int
+ }
+
+ for _, i := range p.BankSlots() {
+ bs := p.BankSlot(i)
+ if bs == nil {
+ continue
+ }
+ def, _ := g.ItemStore.Load(bs.ItemID)
+ itemName := bs.ItemID
+ if def != nil {
+ itemName = def.Name
+ }
+ entries = append(entries, struct {
+ slot int
+ name string
+ id string
+ qty int
+ }{slot: i, name: itemName, id: bs.ItemID, qty: bs.Quantity})
+ }
+
+ idx, err := parseChoiceIndex(input)
+ if err == nil && idx > 0 && idx <= len(entries) {
+ e := entries[idx-1]
+ g.withdrawBankItem(sess, p, e.slot)
+ return
+ }
+
+ var matches []struct {
+ slot int
+ name string
+ id string
+ qty int
+ }
+ lower := strings.ToLower(input)
+ for _, e := range entries {
+ if world.WordPrefixMatch(e.name, lower) {
+ matches = append(matches, e)
+ }
+ }
+
+ if len(matches) == 1 {
+ g.withdrawBankItem(sess, p, matches[0].slot)
+ return
+ }
+
+ for _, e := range entries {
+ def, _ := g.ItemStore.Load(e.id)
+ if def != nil && def.MatchesName(input) {
+ matches = append(matches, e)
+ }
+ }
+
+ if len(matches) == 0 {
+ sess.WriteLine("That item isn't in your bank. Use 'browse' to see your bank contents.")
+ return
+ }
+
+ if len(matches) > 1 {
+ var names []string
+ for _, m := range matches {
+ names = append(names, m.name)
+ }
+ sess.WriteLine("That's ambiguous, which one?")
+ for _, n := range names {
+ sess.WriteLine(fmt.Sprintf(" - %s", n))
+ }
+ return
+ }
+
+ g.withdrawBankItem(sess, p, matches[0].slot)
+}
+
+func (g *Game) withdrawBankItem(sess *net.Session, p *player.Player, bankSlotIdx int) {
+ bs := p.BankSlot(bankSlotIdx)
+ if bs == nil {
+ return
+ }
+
+ freeSlot := p.FirstFreeSlot()
+ if freeSlot == -1 {
+ sess.WriteLine("Your inventory is full.")
+ return
+ }
+
+ itemID := bs.ItemID
+ qty := bs.Quantity
+ def, _ := g.ItemStore.Load(itemID)
+
+ if def != nil && def.Stackable {
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: itemID, Quantity: qty})
+ } else {
+ p.SetInvSlot(freeSlot, &player.InventorySlot{ItemID: itemID, Quantity: 1})
+ if qty > 1 {
+ bs.Quantity--
+ g.AccountStore.SaveCharacter(p)
+ displayName := itemID
+ if def != nil {
+ displayName = def.Name
+ }
+ itemColor := g.itemColorize(sess, def, displayName)
+ sess.WriteLine(fmt.Sprintf("You withdraw a %s.", itemColor))
+ return
+ }
+ }
+
+ p.SetBankSlot(bankSlotIdx, nil)
+ g.AccountStore.SaveCharacter(p)
+
+ displayName := itemID
+ if def != nil {
+ displayName = def.Name
+ }
+ itemColor := g.itemColorize(sess, def, displayName)
+ if qty > 1 {
+ sess.WriteLine(fmt.Sprintf("You withdraw %d %ss.", qty, itemColor))
+ } else {
+ sess.WriteLine(fmt.Sprintf("You withdraw a %s.", itemColor))
+ }
+}
+
+func (g *Game) canUseBank(p *player.Player) bool {
+ instances := g.World.FindObjInstances(p.RoomID, "bank booth")
+ return len(instances) > 0
+}
+
+func (g *Game) doBank(sess *net.Session) {
+ p, _ := sess.Player.(*player.Player)
+
+ if !g.canUseBank(p) {
+ sess.WriteLine("There is no bank here.")
+ return
+ }
+
+ sess.State = net.StateBank
+ sess.WriteLine(g.colorize(sess, "dialog", "\nYou access the bank terminal."))
+ g.showBankBrowse(sess)
+ g.writeBankPrompt(sess)
+}
+
+func (g *Game) leaveBank(sess *net.Session) {
+ sess.State = net.StateGame
+ g.writePrompt(sess)
+}