From abd612c15799f604e671e83dc7c410ed2b44185f Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Thu, 25 Jun 2026 15:40:48 -0400 Subject: slop refactor --- internal/game/ui_map.go | 428 ------------------------------------------------ 1 file changed, 428 deletions(-) delete mode 100644 internal/game/ui_map.go (limited to 'internal/game/ui_map.go') diff --git a/internal/game/ui_map.go b/internal/game/ui_map.go deleted file mode 100644 index a07606f..0000000 --- a/internal/game/ui_map.go +++ /dev/null @@ -1,428 +0,0 @@ -package game - -import ( - "strings" - "unicode/utf8" - - "thehouseoficarus/internal/color" - "thehouseoficarus/internal/net" - "thehouseoficarus/internal/world" -) - -type mapGlyphs struct { - topLeft, topRight rune - bottomLeft, bottomRight rune - side rune - topFill rune - connectorH, connectorV rune - upArrow, downArrow rune -} - -func mapGlyphsForPlayer(unicode bool) mapGlyphs { - if unicode { - return mapGlyphs{ - topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝', - side: '║', topFill: '═', connectorH: '-', connectorV: '│', - upArrow: '↑', downArrow: '↓', - } - } - return mapGlyphs{ - topLeft: '.', topRight: '.', bottomLeft: ':', bottomRight: ':', - side: ':', topFill: '.', connectorH: '-', connectorV: '|', - upArrow: '^', downArrow: 'v', - } -} - -type mapCell struct { - char rune - spec color.ColorSpec -} - -type mapGraph struct { - posToRoom map[[2]int]int - roomToPos map[int][2]int -} - -var bfsDirs = []struct { - dir world.ExitDir - dx, dy int -}{ - {world.North, 0, -1}, - {world.South, 0, 1}, - {world.East, 1, 0}, - {world.West, -1, 0}, -} - -func buildGraph(g *Game, startRoomID int, visited map[int]bool) *mapGraph { - mg := &mapGraph{ - posToRoom: make(map[[2]int]int), - roomToPos: make(map[int][2]int), - } - - type node struct { - roomID int - x, y int - } - queue := []node{{startRoomID, 0, 0}} - mg.posToRoom[[2]int{0, 0}] = startRoomID - mg.roomToPos[startRoomID] = [2]int{0, 0} - - for len(queue) > 0 { - n := queue[0] - queue = queue[1:] - - room, ok := loadRoom(g, n.roomID) - if !ok { - continue - } - - if visited != nil && !visited[n.roomID] { - continue - } - - for _, d := range bfsDirs { - targetID, ok := exitTarget(room, d.dir) - if !ok { - continue - } - if _, seen := mg.roomToPos[targetID]; seen { - continue - } - nx, ny := n.x+d.dx, n.y+d.dy - mg.posToRoom[[2]int{nx, ny}] = targetID - mg.roomToPos[targetID] = [2]int{nx, ny} - queue = append(queue, node{targetID, nx, ny}) - } - } - - return mg -} - -func renderMapCells(grid [][]mapCell, colorMode string, startRow, endRow int, border rune) []string { - lines := make([]string, 0, endRow-startRow) - for row := startRow; row < endRow; row++ { - var sb strings.Builder - if border != 0 { - sb.WriteRune(border) - } - for _, cell := range grid[row] { - if cell.char == ' ' { - sb.WriteRune(' ') - } else if !cell.spec.Empty() { - sb.WriteString(color.Render(colorMode, cell.spec, string(cell.char))) - } else { - sb.WriteRune(cell.char) - } - } - if border != 0 { - sb.WriteRune(border) - } - lines = append(lines, sb.String()) - } - return lines -} - -func buildTinyMap(g *Game, sess *net.Session, roomID int, mg mapGlyphs) []string { - visited := roomsVisited(sess) - bg := buildGraph(g, roomID, visited) - - colorMode := colorModeFor(sess) - atSpec := resolveMapAt(g, sess) - dimSpec := resolveDim(g, sess) - - grid := make([][]mapCell, 5) - for i := range grid { - grid[i] = make([]mapCell, 5) - for j := range grid[i] { - grid[i][j] = mapCell{char: ' '} - } - } - - for y := -1; y <= 1; y++ { - for x := -1; x <= 1; x++ { - pos := [2]int{x, y} - rid, ok := bg.posToRoom[pos] - if !ok { - continue - } - gr := (y + 1) * 2 - gc := (x + 1) * 2 - if rid == roomID { - grid[gr][gc] = mapCell{char: '@', spec: atSpec} - } else { - unvisited := visited != nil && !visited[rid] - ch, spec := roomMapSymbol(g, sess, rid, unvisited) - if unvisited { - spec = dimSpec - } - grid[gr][gc] = mapCell{char: ch, spec: spec} - } - } - } - - for y := -1; y <= 1; y++ { - for x := -1; x <= 0; x++ { - leftPos := [2]int{x, y} - rightPos := [2]int{x + 1, y} - leftRoom, leftOK := bg.posToRoom[leftPos] - rightRoom, rightOK := bg.posToRoom[rightPos] - if !leftOK || !rightOK { - continue - } - if exitsConnect(g, leftRoom, rightRoom, world.East, world.West) { - connSpec := color.NoColor() - if visited != nil && (!visited[leftRoom] || !visited[rightRoom]) { - connSpec = dimSpec - } - grid[(y+1)*2][(x+1)*2+1] = mapCell{char: mg.connectorH, spec: connSpec} - } - } - } - - for y := -1; y <= 0; y++ { - for x := -1; x <= 1; x++ { - topPos := [2]int{x, y} - bottomPos := [2]int{x, y + 1} - topRoom, topOK := bg.posToRoom[topPos] - bottomRoom, bottomOK := bg.posToRoom[bottomPos] - if !topOK || !bottomOK { - continue - } - if exitsConnect(g, topRoom, bottomRoom, world.South, world.North) { - connSpec := color.NoColor() - if visited != nil && (!visited[topRoom] || !visited[bottomRoom]) { - connSpec = dimSpec - } - grid[(y+1)*2+1][(x+1)*2] = mapCell{char: mg.connectorV, spec: connSpec} - } - } - } - - cur, _ := loadRoom(g, roomID) - if cur != nil { - if _, ok := exitTarget(cur, world.Up); ok { - grid[1][3] = mapCell{char: mg.upArrow, spec: color.NoColor()} - } - if _, ok := exitTarget(cur, world.Down); ok { - grid[3][1] = mapCell{char: mg.downArrow, spec: color.NoColor()} - } - } - - topFill := strings.Repeat(string(mg.topFill), 5) - lines := make([]string, 7) - lines[0] = string(mg.topLeft) + topFill + string(mg.topRight) - inner := renderMapCells(grid, colorMode, 0, 5, mg.side) - copy(lines[1:], inner) - botFill := strings.Repeat(string(mg.topFill), 5) - lines[6] = string(mg.bottomLeft) + botFill + string(mg.bottomRight) - - return lines -} - -func buildFullMap(g *Game, sess *net.Session, roomID, mapWidth, mapHeight int, mg mapGlyphs) []string { - visited := roomsVisited(sess) - bg := buildGraph(g, roomID, visited) - - colorMode := colorModeFor(sess) - atSpec := resolveMapAt(g, sess) - dimSpec := resolveDim(g, sess) - - grid := make([][]mapCell, mapHeight) - for i := range grid { - grid[i] = make([]mapCell, mapWidth) - for j := range grid[i] { - grid[i][j] = mapCell{char: ' '} - } - } - - cx := mapWidth / 2 - cy := mapHeight / 2 - - for pos, rid := range bg.posToRoom { - gr := cy + pos[1]*2 - gc := cx + pos[0]*2 - if gr < 0 || gr >= mapHeight || gc < 0 || gc >= mapWidth { - continue - } - if rid == roomID { - grid[gr][gc] = mapCell{char: '@', spec: atSpec} - } else { - unvisited := visited != nil && !visited[rid] - ch, spec := roomMapSymbol(g, sess, rid, unvisited) - if unvisited { - spec = dimSpec - } - grid[gr][gc] = mapCell{char: ch, spec: spec} - } - } - - for pos, rid := range bg.posToRoom { - x, y := pos[0], pos[1] - - if rightID, ok := bg.posToRoom[[2]int{x + 1, y}]; ok { - if exitsConnect(g, rid, rightID, world.East, world.West) { - gr := cy + y*2 - gc := cx + x*2 + 1 - if gr >= 0 && gr < mapHeight && gc >= 0 && gc < mapWidth { - connSpec := color.NoColor() - if visited != nil && (!visited[rid] || !visited[rightID]) { - connSpec = dimSpec - } - grid[gr][gc] = mapCell{char: mg.connectorH, spec: connSpec} - } - } - } - - if bottomID, ok := bg.posToRoom[[2]int{x, y + 1}]; ok { - if exitsConnect(g, rid, bottomID, world.South, world.North) { - gr := cy + y*2 + 1 - gc := cx + x*2 - if gr >= 0 && gr < mapHeight && gc >= 0 && gc < mapWidth { - connSpec := color.NoColor() - if visited != nil && (!visited[rid] || !visited[bottomID]) { - connSpec = dimSpec - } - grid[gr][gc] = mapCell{char: mg.connectorV, spec: connSpec} - } - } - } - } - - return renderMapCells(grid, colorMode, 0, mapHeight, 0) -} - -func roomsVisited(sess *net.Session) map[int]bool { - if sess != nil && sess.Player != nil { - return sess.Player.Stats.RoomsVisited - } - return nil -} - -func colorModeFor(sess *net.Session) string { - if sess != nil && sess.Player != nil { - return sess.Player.OptionString("color") - } - return "none" -} - -func resolveMapAt(g *Game, sess *net.Session) color.ColorSpec { - if sess != nil { - return g.resolveColor(sess, "map_at") - } - return color.NoColor() -} - -func resolveDim(g *Game, sess *net.Session) color.ColorSpec { - if sess != nil { - return g.resolveColor(sess, "dim") - } - return color.Parse("243 dim") -} - -func roomMapSymbol(g *Game, sess *net.Session, roomID int, unvisited bool) (rune, color.ColorSpec) { - if sess != nil && sess.Player != nil { - if data, ok := sess.Player.MapSymbols[roomID]; ok { - r, size := utf8.DecodeRuneInString(data.Char) - if size > 0 && r != utf8.RuneError { - spec := color.NoColor() - if data.Color != "" { - spec = color.Parse(data.Color) - } - // ponytail: non-ASCII custom symbols fall back to 'o' - // when unicode mode is off, but preserve the color. - if !sess.Player.OptionBool("unicode") && r > 127 { - return 'o', spec - } - return r, spec - } - } - if sess.Player.OptionBool("unicode") { - if unvisited { - return '□', color.NoColor() - } - return '■', color.NoColor() - } - return 'o', color.NoColor() - } - return '■', color.NoColor() -} - -func exitsConnect(g *Game, room1, room2 int, dir12, dir21 world.ExitDir) bool { - r1, ok := loadRoom(g, room1) - if !ok { - return false - } - if id, ok := exitTarget(r1, dir12); ok && id == room2 { - return true - } - r2, ok := loadRoom(g, room2) - if !ok { - return false - } - id, ok := exitTarget(r2, dir21) - return ok && id == room1 -} - -func exitTarget(room *world.Room, dir world.ExitDir) (int, bool) { - if room == nil { - return 0, false - } - exit, ok := room.Exits[dir] - if !ok { - return 0, false - } - return exit.Room, true -} - -func loadRoom(g *Game, roomID int) (*world.Room, bool) { - if roomID == 0 { - return nil, false - } - room, err := g.World.LoadRoom(roomID) - if err != nil { - return nil, false - } - return room, true -} - -func stripBlankRows(lines []string) []string { - var out []string - for _, line := range lines { - if strings.TrimSpace(line) != "" { - out = append(out, line) - } - } - return out -} - -func leftTrimCommon(lines []string) []string { - min := -1 - for _, line := range lines { - if strings.TrimSpace(line) == "" { - continue - } - n := 0 - for _, r := range line { - if r == ' ' { - n++ - } else { - break - } - } - if min < 0 || n < min { - min = n - } - } - if min <= 0 { - return lines - } - result := make([]string, len(lines)) - for i, line := range lines { - if len(line) <= min { - result[i] = "" - } else { - result[i] = line[min:] - } - } - return result -} -- cgit v1.2.3