aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_map.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-06 21:56:32 -0400
committerhistoria <[not public]>2026-07-06 21:56:32 -0400
commite9144cad4a8c55dcee4a694149f06588edd8595a (patch)
tree5bef00b718d1b7c898064ea98ddd9d8ac630dd42 /internal/admin/api_map.go
parentcd52f9dbb8c35f37a9b52e8092bf5d722d56b044 (diff)
downloadthehouseoficarus-e9144cad4a8c55dcee4a694149f06588edd8595a.tar.gz
fix: change one-way modifier on admin map from shift to ctrl for firefox support
Diffstat (limited to 'internal/admin/api_map.go')
-rw-r--r--internal/admin/api_map.go119
1 files changed, 98 insertions, 21 deletions
diff --git a/internal/admin/api_map.go b/internal/admin/api_map.go
index bb81e59..5168165 100644
--- a/internal/admin/api_map.go
+++ b/internal/admin/api_map.go
@@ -84,7 +84,6 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) {
if err != nil {
continue
}
- // Try adjacent to a connected neighbour already on grid.
for _, exit := range room.Exits {
if exit.Room <= 0 {
continue
@@ -93,32 +92,69 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) {
if !ok {
continue
}
- for dx := -1; dx <= 1; dx++ {
- for dy := -1; dy <= 1; dy++ {
- if dx == 0 && dy == 0 {
- continue
- }
- want := [3]int{nc[0] + dx, nc[1] + dy, nc[2]}
- if _, used := g.RoomAt[want]; !used {
- g.Coord[id] = want
- g.RoomAt[want] = id
- goto placed
- }
+ if tryPlaceAdjacent(&g, id, nc) {
+ goto placed
+ }
+ }
+ tryPlaceRoom(&g, id, [3]int{}, false, [3]int{0, 0, z})
+ placed:
+ }
+
+ // Place rooms that have a one-way exit into the already-placed set.
+ // These rooms are not reachable from the seed via outgoing exits but
+ // their one-way link points into the connected component, so they
+ // should appear on the map as connected (not disconnected).
+ {
+ roomIndex := s.world.RoomIndex()
+ sortedIDs := make([]int, 0, len(roomIndex))
+ for id := range roomIndex {
+ sortedIDs = append(sortedIDs, id)
+ }
+ sort.Ints(sortedIDs)
+
+ type revEdge struct {
+ src int
+ dir world.ExitDir
+ }
+ rev := make(map[int][]revEdge)
+ for _, id := range sortedIDs {
+ room, err := s.world.LoadRoom(id)
+ if err != nil {
+ continue
+ }
+ for _, dir := range world.ExitOrder {
+ exit, ok := room.Exits[dir]
+ if !ok || exit.Room <= 0 || exit.Room == id {
+ continue
}
+ rev[exit.Room] = append(rev[exit.Room], revEdge{src: id, dir: dir})
}
}
- // Fallback: scan a generous rectangle for a free cell.
- for sx := -10; sx <= 10; sx++ {
- for sy := -10; sy <= 10; sy++ {
- want := [3]int{sx, sy, z}
- if _, used := g.RoomAt[want]; !used {
- g.Coord[id] = want
- g.RoomAt[want] = id
- goto placed
+
+ queue := make([]int, 0, len(g.Coord))
+ for rid := range g.Coord {
+ queue = append(queue, rid)
+ }
+ sort.Ints(queue)
+
+ for len(queue) > 0 {
+ target := queue[0]
+ queue = queue[1:]
+ for _, e := range rev[target] {
+ if _, placed := g.Coord[e.src]; placed || e.src == target {
+ continue
+ }
+ tc := g.Coord[target]
+ delta := world.DirectionDeltas3D[world.OppositeExit[e.dir]]
+ want := [3]int{tc[0] + delta[0], tc[1] + delta[1], tc[2] + delta[2]}
+ if tryPlaceRoom(&g, e.src, want, true, tc) {
+ if d, ok := g.Dist[target]; ok {
+ g.Dist[e.src] = d + 1
+ }
+ queue = append(queue, e.src)
}
}
}
- placed:
}
type RoomEntry struct {
@@ -262,6 +298,47 @@ func (s *AdminServer) handleMap(w http.ResponseWriter, r *http.Request) {
})
}
+func tryPlaceAdjacent(g *world.RoomGrid, roomID int, center [3]int) bool {
+ for dx := -1; dx <= 1; dx++ {
+ for dy := -1; dy <= 1; dy++ {
+ if dx == 0 && dy == 0 {
+ continue
+ }
+ cell := [3]int{center[0] + dx, center[1] + dy, center[2]}
+ if _, used := g.RoomAt[cell]; !used {
+ g.Coord[roomID] = cell
+ g.RoomAt[cell] = roomID
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func tryPlaceRoom(g *world.RoomGrid, roomID int, want [3]int, allowWant bool, center [3]int) bool {
+ if allowWant {
+ if _, used := g.RoomAt[want]; !used {
+ g.Coord[roomID] = want
+ g.RoomAt[want] = roomID
+ return true
+ }
+ }
+ if tryPlaceAdjacent(g, roomID, center) {
+ return true
+ }
+ for sx := -10; sx <= 10; sx++ {
+ for sy := -10; sy <= 10; sy++ {
+ cell := [3]int{center[0] + sx, center[1] + sy, center[2]}
+ if _, used := g.RoomAt[cell]; !used {
+ g.Coord[roomID] = cell
+ g.RoomAt[cell] = roomID
+ return true
+ }
+ }
+ }
+ return false
+}
+
func getRoomDir(s *AdminServer, roomID int) string {
path, ok := s.world.GetRoomPath(roomID)
if !ok {