package game import ( "fmt" "os" "strings" "gopkg.in/yaml.v3" "thehouseoficarus/internal/behavior" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" "thehouseoficarus/internal/world" ) func (g *Game) executeRoom(sess *net.Session, args []string, rawInput string) { if !g.checkAdmin(sess) { sess.WriteLine("Unknown command.") return } p := sess.Player if p == nil { return } if len(args) == 0 { g.showRoomHelp(sess) return } action := strings.ToLower(args[0]) rest := args[1:] switch action { case "name": g.roomSetName(sess, rest) case "desc": g.roomSetDesc(sess, rest) case "addobj", "remobj", "hide", "unhide": g.roomObject(sess, action, rest) case "addlocalobj": name, aliases, desc := parseLocalObjArgs(rawInput, "addlocalobj") g.roomAddLocalObj(sess, name, aliases, desc) case "remlocalobj": name, _, _ := parseLocalObjArgs(rawInput, "remlocalobj") g.roomRemLocalObj(sess, name) case "addmob", "remmob": g.roomMob(sess, action, rest) case "addspawn", "remspawn": g.roomSpawn(sess, action, rest) case "color": g.roomSetColor(sess, rest) case "insert": g.roomInsert(sess, rest) default: sess.WriteLine(fmt.Sprintf("Unknown room action: %s", action)) g.showRoomHelp(sess) } } func (g *Game) showRoomHelp(sess *net.Session) { sess.WriteLine("room actions:") sess.WriteLine(" room name — set room name") sess.WriteLine(" room desc — set room description") sess.WriteLine(" room addobj — add a referenced object") sess.WriteLine(" room remobj — remove a referenced object") sess.WriteLine(" room addlocalobj [name, alias...] — add a local object") sess.WriteLine(" room remlocalobj [name]| — remove a local object") sess.WriteLine(" room hide — hide all matching objects") sess.WriteLine(" room unhide — unhide all matching objects") sess.WriteLine(" room addmob — add a mob spawn") sess.WriteLine(" room remmob — remove a mob spawn") sess.WriteLine(" room addspawn [qty] [respawn_ticks] — add an item spawn") sess.WriteLine(" room remspawn — remove an item spawn") sess.WriteLine(" room color — set or clear room map color") sess.WriteLine(" room insert [name] — insert a new room into the exit, pushing rooms beyond") } func (g *Game) roomSetName(sess *net.Session, args []string) { if len(args) == 0 { sess.WriteLine("Usage: room name ") return } text := strings.Join(args, " ") g.writeRoom(sess, func(room *world.Room) { room.Name = text }) sess.WriteLine(fmt.Sprintf("Room name set to: %s", text)) } func (g *Game) roomSetDesc(sess *net.Session, args []string) { if len(args) == 0 { sess.WriteLine("Usage: room desc ") return } text := strings.Join(args, " ") g.writeRoom(sess, func(room *world.Room) { room.Description = behavior.DescList{{Text: text}} }) sess.WriteLine("Room description updated.") } func (g *Game) roomSetColor(sess *net.Session, args []string) { if len(args) == 0 { sess.WriteLine("Usage: room color ") sess.WriteLine("Format: <00-FF> [bg:<00-FF>] [bold] [dim] [underline]") sess.WriteLine("Example: D0 bold") return } value := strings.Join(args, " ") if value == "off" { value = "" } if value != "" { spec := color.Parse(value) if spec.Empty() { 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.writeRoom(sess, func(room *world.Room) { room.Color = value }) if value == "" { sess.WriteLine("Room color cleared.") } else { sess.WriteLine(fmt.Sprintf("Room color set to: %s", value)) } } func (g *Game) loadRoomWrite(p *player.Player) (*world.Room, string, error) { path, ok := g.World.GetRoomPath(p.RoomID) if !ok { return nil, "", fmt.Errorf("room file not found") } room, err := g.World.LoadRoom(p.RoomID) if err != nil { return nil, "", err } return room, path, nil } func parseLocalObjArgs(rawInput, action string) (name string, aliases []string, desc string) { prefix := "room " + action rest := rawInput if idx := strings.Index(strings.ToLower(rest), prefix); idx >= 0 { rest = strings.TrimSpace(rest[idx+len(prefix):]) } if rest == "" { return "", nil, "" } if rest[0] == '[' { closeB := strings.Index(rest, "]") if closeB < 0 { return rest, nil, "" } desc = strings.TrimSpace(rest[closeB+1:]) for _, p := range strings.Split(rest[1:closeB], ",") { p = strings.TrimSpace(p) if name == "" { name = p } else if p != "" { aliases = append(aliases, p) } } return name, aliases, desc } fields := strings.Fields(rest) name = fields[0] if len(fields) > 1 { desc = strings.Join(fields[1:], " ") } return name, nil, desc } func (g *Game) writeRoom(sess *net.Session, fn func(*world.Room)) { p := sess.Player room, path, err := g.loadRoomWrite(p) if err != nil { sess.WriteLine(fmt.Sprintf("Error loading room: %v", err)) return } fn(room) data, err := yaml.Marshal(room) if err != nil { sess.WriteLine("Error marshaling room YAML.") return } if err := os.WriteFile(path, data, 0644); err != nil { sess.WriteLine("Error writing room file.") return } }