aboutsummaryrefslogtreecommitdiff
path: root/internal/game/casino_commands.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/casino_commands.go')
-rw-r--r--internal/game/casino_commands.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/internal/game/casino_commands.go b/internal/game/casino_commands.go
new file mode 100644
index 0000000..f4ca79f
--- /dev/null
+++ b/internal/game/casino_commands.go
@@ -0,0 +1,83 @@
+package game
+
+import (
+ "strings"
+ "unicode/utf8"
+
+ "thehouseoficarus/internal/casino"
+ "thehouseoficarus/internal/net"
+)
+
+// Wrap before Session.WriteLine: generic prose wrapping strips alignment from
+// overlong lines. Every casino menu uses the same two-space command indent and
+// hanging description column, capped at 80 even when prose wrapping is off.
+func (g *Game) casinoCommandColumns(sess *net.Session, commands []casino.MenuCommand) string {
+ limit := 80
+ if sess.Player != nil {
+ if wrap := sess.Player.OptionInt("wrap_width"); wrap > 0 {
+ limit = min(limit, wrap)
+ }
+ }
+ width := 0
+ for _, c := range commands {
+ n := utf8.RuneCountInString(c.Command)
+ // Unusually long commands get their own lines instead of squeezing every
+ // other command's description into a tiny column.
+ if n <= limit/2 {
+ width = max(width, n)
+ }
+ }
+ var lines []string
+ for _, c := range commands {
+ if sess.Player != nil && c.Cost > casinoAffordable(sess.Player) {
+ continue
+ }
+ n := utf8.RuneCountInString(c.Command)
+ if n > limit/2 {
+ for _, line := range casinoWrapWords(c.Command, max(1, limit-2)) {
+ lines = append(lines, " "+g.colorize(sess, "command", line))
+ }
+ for _, line := range casinoWrapWords(c.Desc, max(1, limit-4)) {
+ lines = append(lines, " "+line)
+ }
+ continue
+ }
+ if strings.TrimSpace(c.Desc) == "" {
+ lines = append(lines, " "+g.colorize(sess, "command", c.Command))
+ continue
+ }
+ indent := width + 4
+ desc := casinoWrapWords(c.Desc, max(1, limit-indent))
+ cmd := c.Command + strings.Repeat(" ", width-n)
+ lines = append(lines, " "+g.colorize(sess, "command", cmd)+" "+desc[0])
+ for _, line := range desc[1:] {
+ lines = append(lines, strings.Repeat(" ", indent)+line)
+ }
+ }
+ return strings.Join(lines, "\n")
+}
+
+// Input is uncolored command/description text; paint only after measuring.
+func casinoWrapWords(text string, width int) []string {
+ var lines []string
+ line := ""
+ for _, word := range strings.Fields(text) {
+ if line != "" && utf8.RuneCountInString(line)+1+utf8.RuneCountInString(word) > width {
+ lines = append(lines, line)
+ line = ""
+ }
+ runes := []rune(word)
+ for len(runes) > width {
+ lines = append(lines, string(runes[:width]))
+ runes = runes[width:]
+ }
+ if line != "" {
+ line += " "
+ }
+ line += string(runes)
+ }
+ if line != "" {
+ lines = append(lines, line)
+ }
+ return lines
+}