package game import ( "fmt" "strings" "thehouseoficarus/internal/color" "thehouseoficarus/internal/config" "thehouseoficarus/internal/net" "thehouseoficarus/internal/ui" ) func (g *Game) doColor(sess *net.Session, input string) { if sess.Account == nil { sess.WriteLine("You must be logged into an account to set colors.") return } if input == "" { showColorTable(g, sess) return } parts := strings.Fields(input) target := strings.ToLower(parts[0]) if _, ok := config.DefaultColors()[target]; !ok { sess.WriteLine(fmt.Sprintf("Unknown color target: %s", target)) sess.WriteLine("Available targets:") for _, t := range colorCategoryOrder { sess.WriteLine(fmt.Sprintf(" %s", t)) } return } if len(parts) == 1 { current := g.getCurrentColor(sess, target) source := g.colorSource(sess, target) sess.WriteLine(fmt.Sprintf("%s = %s [source: %s]", target, current, source)) return } value := strings.Join(parts[1:], " ") if len(parts) == 2 && parts[1] == "reset" { g.saveAccountColor(sess, target, "") sess.WriteLine(fmt.Sprintf("%s reset to default (%s).", target, config.DefaultColors()[target])) return } if value == "off" { g.saveAccountColor(sess, target, "off") sess.WriteLine(fmt.Sprintf("%s set to off.", target)) return } spec := color.Parse(value) if spec.Empty() && value != "" { sess.WriteLine(fmt.Sprintf("Invalid color string: %s", value)) sess.WriteLine("Format: <00-FF> [bg:<00-FF>] [bold] [dim] [underline]") sess.WriteLine("Example: D0 bold") return } g.saveAccountColor(sess, target, value) sess.WriteLine(fmt.Sprintf("%s set to %s.", target, value)) } func (g *Game) saveAccountColor(sess *net.Session, target, value string) { if value == "" { if sess.Account.Colors != nil { delete(sess.Account.Colors, target) } } else { if sess.Account.Colors == nil { sess.Account.Colors = make(map[string]string) } sess.Account.Colors[target] = value } acc, err := g.AccountStore.LoadAccount(sess.Account.Name) if err != nil { sess.WriteLine("Error loading account.") return } if value == "" { if acc.Colors != nil { delete(acc.Colors, target) } } else { if acc.Colors == nil { acc.Colors = make(map[string]string) } acc.Colors[target] = value } g.AccountStore.SaveAccount(acc) } func (g *Game) getCurrentColor(sess *net.Session, category string) string { if sess.Account != nil && sess.Account.Colors != nil { if val, ok := sess.Account.Colors[category]; ok { if val == "off" { return "off" } if val != "" { return val } } } if g.ColorConfig != nil { if val, ok := (*g.ColorConfig)[category]; ok && val != "" { return val } } return config.DefaultColors()[category] } func (g *Game) colorSource(sess *net.Session, category string) string { if sess.Account != nil && sess.Account.Colors != nil { if _, ok := sess.Account.Colors[category]; ok { return "account" } } if g.ColorConfig != nil { if _, ok := (*g.ColorConfig)[category]; ok { return "default" } } return "builtin" } func (g *Game) executeColor(sess *net.Session, args []string, rawInput string) { g.doColor(sess, strings.Join(args, " ")) } var colorCategoryOrder = []string{ "room_name", "room_number", "room_desc", "direction", "exit_direction", "exit_name", "protected_mob", "mob", "damage_dealt", "damage_taken", "damage", "xp", "level_up", "item", "player_name", "death", "victory", "miss", "error", "say", "global", "dialog", "dialog_options", "broadcast", "fire", "eat_food", "drop_message", "credits_pickup", "map_at", "map_blocked", "safespot_alert", } func showColorTable(g *Game, sess *net.Session) { p := sess.Player mode := g.colorMode(sess) table := &ui.Table{ Columns: []string{ color.Render(mode, color.Parse("4B"), "Target"), "Color", color.Render(mode, color.Parse("F3"), "Source"), }, } for _, cat := range colorCategoryOrder { val := g.getCurrentColor(sess, cat) source := g.colorSource(sess, cat) coloredVal := val if val != "off" && val != "" { spec := color.Parse(val) if !spec.Empty() { coloredVal = color.Render(mode, spec, val) } } table.Rows = append(table.Rows, []string{ color.Render(mode, color.Parse("4B"), cat), coloredVal, color.Render(mode, color.Parse("F3"), source), }) } for _, line := range table.Render(p.OptionBool("unicode"), p.OptionInt("wrap_width")) { sess.WriteLine(line) } }