package game import ( "fmt" "strconv" "strings" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" "thehouseoficarus/internal/ui" ) func (g *Game) doOption(sess *net.Session, input string) { p := sess.Player mode := g.colorMode(sess) if input == "" { table := &ui.Table{ Columns: []string{ color.Render(mode, color.Parse("49"), "Option"), color.Render(mode, color.Parse("FA"), "Value"), color.Render(mode, color.Parse("F5"), "Valid"), color.Render(mode, color.Parse("FF"), "Description"), }, } for _, def := range player.OptionDefs { val := formatOptionValue(p, &def) val = truncateForTable(val, p.OptionBool("unicode")) valid := formatValidValues(&def) table.Rows = append(table.Rows, []string{ color.Render(mode, color.Parse("49"), def.Name), color.Render(mode, color.Parse("FA"), val), color.Render(mode, color.Parse("F5"), valid), color.Render(mode, color.Parse("FF"), def.Description), }) } for _, line := range table.Render(p.OptionBool("unicode"), p.OptionInt("wrap_width")) { sess.WriteLine(line) } return } parts := strings.Fields(input) name := strings.ToLower(parts[0]) def := player.GetOptionDef(name) if def == nil { sess.WriteLine(fmt.Sprintf("Unknown option: %s", name)) return } if len(parts) == 1 { val := formatOptionValue(p, def) valid := formatValidValues(def) sess.WriteLine(fmt.Sprintf("%s = %s [%s]", def.Name, val, valid)) sess.WriteLine(fmt.Sprintf(" %s", def.Description)) return } value := strings.ToLower(parts[1]) parsed, ok := parseOptionValue(def, value) if !ok { valid := formatValidValues(def) sess.WriteLine(fmt.Sprintf("Invalid value for %s: %s [%s]", def.Name, value, valid)) return } if p.Options == nil { p.Options = make(map[string]any) } p.Options[def.Name] = parsed if sess.Account.Options == nil { sess.Account.Options = make(map[string]any) } sess.Account.Options[def.Name] = parsed acc, err := g.AccountStore.LoadAccount(sess.Account.Name) if err == nil { if acc.Options == nil { acc.Options = make(map[string]any) } acc.Options[def.Name] = parsed g.AccountStore.SaveAccount(acc) } sess.WriteLine(fmt.Sprintf("%s set to %s.", def.Name, formatOptionValue(p, def))) } func (g *Game) executeOption(sess *net.Session, args []string, rawInput string) { g.doOption(sess, strings.Join(args, " ")) } func formatOptionValue(p *player.Player, def *player.OptionDef) string { switch def.Type { case player.OptBool: if p.OptionBool(def.Name) { return "on" } return "off" case player.OptString: return p.OptionString(def.Name) case player.OptInt: return strconv.Itoa(p.OptionInt(def.Name)) } return "" } func formatValidValues(def *player.OptionDef) string { switch def.Type { case player.OptBool: return "on/off" case player.OptString: if len(def.ValidValues) > 0 { return strings.Join(def.ValidValues, "/") } return "string" case player.OptInt: return "num" } return "" } func parseOptionValue(def *player.OptionDef, input string) (any, bool) { switch def.Type { case player.OptBool: switch input { case "on", "true", "yes", "1": return true, true case "off", "false", "no", "0": return false, true } return nil, false case player.OptString: if len(def.ValidValues) == 0 { return input, true } for _, v := range def.ValidValues { if strings.EqualFold(v, input) { return v, true } } return nil, false case player.OptInt: n, err := strconv.Atoi(input) if err != nil { return nil, false } return n, true } return nil, false } func truncateForTable(s string, unicode bool) string { ellipsis := color.Ellipsis(unicode) ellipLen := len([]rune(ellipsis)) if len([]rune(s)) <= 10 { return s } runes := []rune(s) return string(runes[:10-ellipLen]) + ellipsis }