package game import ( "fmt" "sort" "strconv" "strings" "thehouseoficarus/internal/color" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" "thehouseoficarus/internal/world" ) func (g *Game) doLook(sess *net.Session) { p := sess.Player room, err := g.World.LoadRoom(p.RoomID) if err != nil { sess.WriteLine("You are in a void.") return } g.showRoomName(sess, p, room) wrapWidth := p.OptionInt("wrap_width") if wrapWidth < 80 { wrapWidth = 80 } var mapLines []string mapOn := p.OptionString("tiny_map") != "off" if mapOn { mapLines = buildTinyMap(g, sess, p.RoomID, mapGlyphsForPlayer(p.OptionBool("unicode"))) if len(mapLines) != 7 { mapLines = nil mapOn = false } } descWidth := wrapWidth if mapOn { descWidth = wrapWidth - 9 } var content []string content = append(content, g.showRoomDescription(sess, p, room, descWidth)...) content = append(content, g.showRoomObjects(sess, p, room)...) content = append(content, g.showRoomMobs(sess, p, room)...) content = append(content, g.showGroundItems(sess, p, room)...) if mapOn { g.writeLookSideBySide(sess, p, content, mapLines, descWidth) } else { for _, line := range content { sess.WriteLine(line) } } g.showRoomExits(sess, p, room) g.showRoomPlayers(sess, p, room) } func (g *Game) doExits(sess *net.Session) { p := sess.Player room, err := g.World.LoadRoom(p.RoomID) if err != nil || len(room.Exits) == 0 { sess.WriteLine("There are no exits here.") return } lines := g.formatExitLines(sess, room) if len(lines) == 0 { sess.WriteLine("There are no exits here.") return } for _, l := range lines { sess.WriteLine(l) } } func joinInts(nums []int) string { var parts []string for _, n := range nums { parts = append(parts, strconv.Itoa(n)) } return strings.Join(parts, ",") } func mobInstanceIdx(mob *world.MobInstance, roomMobs []*world.MobInstance) int { var same []*world.MobInstance for _, m := range roomMobs { if m.DefID == mob.DefID { same = append(same, m) } } if len(same) <= 1 { return 0 } sort.Slice(same, func(i, j int) bool { return same[i].InstanceID < same[j].InstanceID }) for i, m := range same { if m.InstanceID == mob.InstanceID { return i + 1 } } return 0 } func visibleLen(s string) int { return color.VisibleLen(s) } func wrapText(text string, width int) []string { if width <= 0 { return []string{text} } words := strings.Fields(text) if len(words) == 0 { return nil } var lines []string current := words[0] for _, word := range words[1:] { if visibleLen(current)+1+visibleLen(word) <= width { current += " " + word } else { lines = append(lines, current) current = word } } lines = append(lines, current) return lines } func (g *Game) writeLookSideBySide(sess *net.Session, p *player.Player, contentLines []string, mapLines []string, descWidth int) { total := len(contentLines) if len(mapLines) > total { total = len(mapLines) } leftMap := p.OptionString("tiny_map") == "left" mapWidth := descWidth if mapWidth <= 0 { mapWidth = 70 } for i := 0; i < total; i++ { content := "" if i < len(contentLines) { content = contentLines[i] } if i < len(mapLines) { mapLine := mapLines[i] if leftMap { sess.WriteLine(fmt.Sprintf("%s %s", mapLine, content)) } else { pad := mapWidth + (len(content) - visibleLen(content)) if pad < 0 { pad = 0 } sess.WriteLine(fmt.Sprintf("%-*s %s", pad, content, mapLine)) } } else { sess.WriteLine(content) } } } func (g *Game) executeLook(sess *net.Session, args []string, rawInput string) { if len(args) == 0 { g.doLook(sess) } else { g.doLookTarget(sess, strings.Join(args, " ")) } } func (g *Game) executeExits(sess *net.Session, args []string, rawInput string) { g.doExits(sess) }