From 3f30fa3eec9c2e2acf9a984ccefb9529a25e688a Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 7 Jul 2026 05:50:37 -0400 Subject: feat: add insert/remove room to context menu in admin web GUI to 'push' or 'pull' map rooms --- internal/game/cmd_room_insert.go | 91 ++++++++++------------------------------ 1 file changed, 23 insertions(+), 68 deletions(-) (limited to 'internal/game/cmd_room_insert.go') diff --git a/internal/game/cmd_room_insert.go b/internal/game/cmd_room_insert.go index 988cd08..b72591f 100644 --- a/internal/game/cmd_room_insert.go +++ b/internal/game/cmd_room_insert.go @@ -65,53 +65,42 @@ func (g *Game) roomInsert(sess *net.Session, args []string) { oppositeDir := world.OppositeExit[dir] - if delta3D, ok := world.DirectionDeltas3D[dir]; ok { - coord, roomAt := g.buildGridFrom(p.RoomID) - - sSet := g.bfsReachable(targetID, func(_ int, _ world.ExitDir, target int) bool { - return target == p.RoomID - }) + newID, err := findNextRoomID(curPath) + if err != nil { + sess.WriteLine("Error scanning room directory.") + return + } - withoutEdge := g.bfsReachable(p.RoomID, func(rid int, d world.ExitDir, target int) bool { - return rid == p.RoomID && d == dir && target == targetID - }) - for rid := range sSet { - if withoutEdge[rid] { - room, _ := g.World.LoadRoom(rid) - conflictName := fmt.Sprintf("#%d", rid) + conflicts := world.InsertGridConflicts(p.RoomID, dir, targetID, newID, func(id int) (*world.Room, bool) { + r, err := g.World.LoadRoom(id) + if err != nil { + return nil, false + } + return r, true + }) + if len(conflicts) > 0 { + for _, c := range conflicts { + switch c.Kind { + case "twist": + room, _ := g.World.LoadRoom(c.Target) + conflictName := fmt.Sprintf("#%d", c.Target) if room != nil { - conflictName = fmt.Sprintf("#%d (%s)", rid, room.Name) + conflictName = fmt.Sprintf("#%d (%s)", c.Target, room.Name) } sess.WriteLine(fmt.Sprintf( "Cannot insert: room %s would have an ambiguous grid position after insertion (reachable via an alternate path from here).", conflictName)) - return - } - } - - for rid := range sSet { - if _, inGrid := coord[rid]; !inGrid { - continue - } - oldPos := coord[rid] - newPos := [3]int{oldPos[0] + delta3D[0], oldPos[1] + delta3D[1], oldPos[2] + delta3D[2]} - if occupier, ok := roomAt[newPos]; ok && !sSet[occupier] { - occRoom, _ := g.World.LoadRoom(occupier) - occName := fmt.Sprintf("#%d", occupier) + case "overlap": + occRoom, _ := g.World.LoadRoom(c.Occupier) + occName := fmt.Sprintf("#%d", c.Occupier) if occRoom != nil { - occName = fmt.Sprintf("#%d (%s)", occupier, occRoom.Name) + occName = fmt.Sprintf("#%d (%s)", c.Occupier, occRoom.Name) } sess.WriteLine(fmt.Sprintf( "Cannot insert: pushing %s would cause grid collision with %s.", targetName, occName)) - return } } - } - - newID, err := findNextRoomID(curPath) - if err != nil { - sess.WriteLine("Error scanning room directory.") return } @@ -228,37 +217,3 @@ func (g *Game) roomInsert(sess *net.Session, args []string) { g.runEnterSteps(sess, newID) g.checkAggro(sess) } - -// bfsReachable returns the set of rooms reachable from startID over the room -// exit graph, restricted to known rooms. skipEdge, when non-nil, prunes an -// individual directed exit (the edge from rid via dir to target) from the walk. -func (g *Game) bfsReachable(startID int, skipEdge func(rid int, dir world.ExitDir, target int) bool) map[int]bool { - roomIndex := g.World.RoomIndex() - visited := map[int]bool{startID: true} - queue := []int{startID} - - for len(queue) > 0 { - rid := queue[0] - queue = queue[1:] - room, err := g.World.LoadRoom(rid) - if err != nil { - continue - } - for _, ed := range world.ExitOrder { - exit, ok := room.Exits[ed] - if !ok || exit.Room <= 0 || !roomIndex[exit.Room] { - continue - } - target := exit.Room - if skipEdge != nil && skipEdge(rid, ed, target) { - continue - } - if visited[target] { - continue - } - visited[target] = true - queue = append(queue, target) - } - } - return visited -} -- cgit v1.2.3