package game import ( "fmt" "strings" "thirdcollapse/internal/color" "thirdcollapse/internal/config" "thirdcollapse/internal/net" "thirdcollapse/internal/player" ) func (g *Game) doColor(sess *net.Session, input string) { if sess.Account == nil { sess.WriteLine("\nYou 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("\nUnknown 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("\n%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("\n%s reset to default (%s).", target, config.DefaultColors()[target])) return } if value == "off" { g.saveAccountColor(sess, target, "off") sess.WriteLine(fmt.Sprintf("\n%s set to off.", target)) return } spec := color.Parse(value) if spec.Empty() && value != "" { sess.WriteLine(fmt.Sprintf("\nInvalid color string: %s", value)) sess.WriteLine("Format: fg= bg= bold dim italic underline") sess.WriteLine("Example: fg=green bg=black bold") return } g.saveAccountColor(sess, target, value) sess.WriteLine(fmt.Sprintf("\n%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("\nError 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" } var colorCategoryOrder = []string{ "room_name", "room_number", "room_desc", "direction", "exit_direction", "exit_name", "mob_name", "friendly_npc", "hostile_npc", "damage", "enemy_hp", "character_hp", "xp", "level_up", "item", "player_name", "death", "victory", "miss", "error", } func showColorTable(g *Game, sess *net.Session) { p := sess.Player.(*player.Player) table := &Table{ Columns: []string{"Target", "Color", "Source"}, } for _, cat := range colorCategoryOrder { val := g.getCurrentColor(sess, cat) source := g.colorSource(sess, cat) table.Rows = append(table.Rows, []string{cat, val, source}) } for _, line := range table.Render(p.OptionBool("unicode")) { sess.WriteLine(line) } }