aboutsummaryrefslogtreecommitdiff
path: root/internal/game/map.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/map.go')
-rw-r--r--internal/game/map.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/internal/game/map.go b/internal/game/map.go
new file mode 100644
index 0000000..cd1012b
--- /dev/null
+++ b/internal/game/map.go
@@ -0,0 +1,191 @@
+package game
+
+import (
+ "thirdcollapse/internal/world"
+)
+
+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) *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
+ }
+
+ for _, d := range bfsDirs {
+ targetID, ok := exitTarget(room, d.dir)
+ if !ok {
+ continue
+ }
+ if _, visited := mg.roomToPos[targetID]; visited {
+ 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 buildTinyMap(g *Game, roomID int) []string {
+ mg := buildGraph(g, roomID)
+
+ grid := make([][]rune, 5)
+ for i := range grid {
+ grid[i] = make([]rune, 5)
+ for j := range grid[i] {
+ grid[i][j] = ' '
+ }
+ }
+
+ for y := -1; y <= 1; y++ {
+ for x := -1; x <= 1; x++ {
+ pos := [2]int{x, y}
+ rid, ok := mg.posToRoom[pos]
+ if !ok {
+ continue
+ }
+ gr := (y + 1) * 2
+ gc := (x + 1) * 2
+ if rid == roomID {
+ grid[gr][gc] = '@'
+ } else {
+ grid[gr][gc] = roomMapSymbol(g, rid)
+ }
+ }
+ }
+
+ 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 := mg.posToRoom[leftPos]
+ rightRoom, rightOK := mg.posToRoom[rightPos]
+ if !leftOK || !rightOK {
+ continue
+ }
+ if exitsConnect(g, leftRoom, rightRoom, world.East, world.West) {
+ grid[(y+1)*2][(x+1)*2+1] = '─'
+ }
+ }
+ }
+
+ 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 := mg.posToRoom[topPos]
+ bottomRoom, bottomOK := mg.posToRoom[bottomPos]
+ if !topOK || !bottomOK {
+ continue
+ }
+ if exitsConnect(g, topRoom, bottomRoom, world.South, world.North) {
+ grid[(y+1)*2+1][(x+1)*2] = '│'
+ }
+ }
+ }
+
+ cur, _ := loadRoom(g, roomID)
+ if cur != nil {
+ if _, ok := exitTarget(cur, world.Up); ok {
+ grid[1][3] = '↑'
+ }
+ if _, ok := exitTarget(cur, world.Down); ok {
+ grid[3][1] = '↓'
+ }
+ }
+
+ lines := make([]string, 7)
+ lines[0] = "╔═════╗"
+ for row := 0; row < 5; row++ {
+ lines[row+1] = "║" + string(grid[row]) + "║"
+ }
+ lines[6] = "╚═════╝"
+
+ return lines
+}
+
+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
+ }
+ if id, ok := exitTarget(r2, dir21); ok && id == room1 {
+ return true
+ }
+ return false
+}
+
+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 roomMapSymbol(g *Game, roomID int) rune {
+ room, ok := loadRoom(g, roomID)
+ if !ok {
+ return '?'
+ }
+ if room.MapSymbol != "" {
+ runes := []rune(room.MapSymbol)
+ return runes[0]
+ }
+ return 'o'
+}