package game import ( "fmt" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" "thehouseoficarus/internal/world" ) func (g *Game) showRoomName(sess *net.Session, p *player.Player, room *world.Room) { title := fmt.Sprintf("%s (%s)", g.colorize(sess, "room_name", room.Name), g.colorize(sess, "room_number", fmt.Sprintf("#%d", room.ID))) if bracket := g.roomSymbolBracket(sess, p, room); bracket != "" { title += " " + bracket } sess.WriteLines("", title) } // roomSymbolBracket renders a dim-bracketed colored symbol (e.g. "[D]") when the // player has set a custom symbol for this room, else "". func (g *Game) roomSymbolBracket(sess *net.Session, p *player.Player, room *world.Room) string { if p == nil { return "" } if _, ok := p.MapSymbols[room.ID]; !ok { return "" } ch, spec := roomMapSymbol(g, sess, room.ID, false) mode := g.colorMode(sess) dimSpec := g.resolveColor(sess, "dim") return color.Render(mode, dimSpec, "[") + color.Render(mode, spec, string(ch)) + color.Render(mode, dimSpec, "]") } func (g *Game) showRoomDescription(sess *net.Session, p *player.Player, room *world.Room, descWidth int) []string { if descWidth <= 0 { descWidth = 70 } rawLines := wrapText(g.roomDescription(sess, room), descWidth) mode := g.colorMode(sess) roomDescSpec := g.resolveColor(sess, "room_desc") lines := make([]string, len(rawLines)) for i, l := range rawLines { lines[i] = color.ExpandTagsDefault(mode, roomDescSpec, l) } return lines } // roomDescription resolves the room's effective description for this player, // picking the first conditional variant whose condition passes. func (g *Game) roomDescription(sess *net.Session, room *world.Room) string { for _, d := range room.Description { if d.Condition == nil || g.checkCondition(sess, d.Condition) { return d.Text } } return "" } // resolveObjDesc resolves the description an object shows to this player. // The first variant whose condition passes wins; if none pass the object is // reported as not present (false), so look falls through as if it were not there. func (g *Game) resolveObjDesc(sess *net.Session, def *object.ObjectDef) (string, bool) { for _, d := range def.Description { if d.Condition == nil || g.checkCondition(sess, d.Condition) { return d.Text, true } } return "", false } func (g *Game) showRoomExits(sess *net.Session, p *player.Player, room *world.Room) { if len(room.Exits) > 0 { sess.WriteLine("") if p.OptionBool("exits") { sess.WriteLine("Exits:") type exitLine struct { dir string targetName string } var lines []exitLine maxDirLen := 0 for _, dir := range world.ExitOrder { exitDef, ok := room.Exits[dir] if !ok { continue } if exitDef.Hidden && !p.GodMode { continue } coloredDir := g.colorize(sess, "exit_direction", string(dir)) targetRoom, err := g.World.LoadRoom(exitDef.Room) targetName := g.colorize(sess, "room_number", fmt.Sprintf("#%d", exitDef.Room)) if err == nil { targetName = g.colorize(sess, "exit_name", targetRoom.Name) } if exitDef.Condition != nil && !g.checkCondition(sess, exitDef.Condition) { targetName += " (blocked)" } if exitDef.Hidden { targetName += " (hidden)" } lines = append(lines, exitLine{coloredDir, targetName}) if visibleLen(coloredDir) > maxDirLen { maxDirLen = visibleLen(coloredDir) } } for _, l := range lines { pad := maxDirLen + (len(l.dir) - visibleLen(l.dir)) sess.WriteLine(fmt.Sprintf(" %-*s - %s", pad, l.dir, l.targetName)) } } else { sess.Write("Exits: ") first := true for _, dir := range world.ExitOrder { exitDef, ok := room.Exits[dir] if !ok || (exitDef.Hidden && !p.GodMode) { continue } if !first { sess.Write(", ") } sess.Write(g.colorize(sess, "exit_direction", string(dir))) first = false } sess.WriteLine("") } } }