aboutsummaryrefslogtreecommitdiff
path: root/internal/world
diff options
context:
space:
mode:
Diffstat (limited to 'internal/world')
-rw-r--r--internal/world/grid.go5
-rw-r--r--internal/world/room.go1
-rw-r--r--internal/world/room_test.go44
3 files changed, 49 insertions, 1 deletions
diff --git a/internal/world/grid.go b/internal/world/grid.go
index 837f737..2ea897a 100644
--- a/internal/world/grid.go
+++ b/internal/world/grid.go
@@ -32,12 +32,15 @@ type RoomGrid struct {
// are then not followed, but any coordinate already assigned to it stands.
// - include, when non-nil, restricts placement to targets for which it returns
// true (pass nil to place every reachable target).
+// - edgeInclude, when non-nil, restricts traversal to exits for which it
+// returns true (pass nil to follow every exit whose target passes include).
+// It receives (fromRoomID, dir, targetRoomID) and is checked before include.
// - onConflict, when non-nil, is called for each twist/overlap encountered.
//
// The first assignment to a room or cell always wins; conflicting placements are
// skipped. In a world that passes grid validation there are no conflicts, so the
// layout is unambiguous.
-func BuildGrid(seed int, load func(int) (*Room, bool), include func(int) bool, onConflict func(GridConflict)) RoomGrid {
+func BuildGrid(seed int, load func(int) (*Room, bool), include func(int) bool, edgeInclude func(int, ExitDir, int) bool, onConflict func(GridConflict)) RoomGrid {
g := RoomGrid{
Coord: map[int][3]int{seed: {0, 0, 0}},
RoomAt: map[[3]int]int{{0, 0, 0}: seed},
diff --git a/internal/world/room.go b/internal/world/room.go
index 8843b9e..29cce0b 100644
--- a/internal/world/room.go
+++ b/internal/world/room.go
@@ -81,6 +81,7 @@ type ExitDef struct {
SetFlags map[string]any `yaml:"set_flags,omitempty"`
SetPlayerFlags map[string]any `yaml:"set_player_flags,omitempty"`
Hidden bool `yaml:"hidden,omitempty"`
+ AlwaysBlocked bool `yaml:"always_blocked,omitempty"`
}
func (e *ExitDef) UnmarshalYAML(value *yaml.Node) error {
diff --git a/internal/world/room_test.go b/internal/world/room_test.go
index e7b1718..1ad974e 100644
--- a/internal/world/room_test.go
+++ b/internal/world/room_test.go
@@ -4,6 +4,8 @@ import (
"os"
"path/filepath"
"testing"
+
+ "gopkg.in/yaml.v3"
)
func writeRoom(t *testing.T, dir string, body string) {
@@ -90,3 +92,45 @@ func TestNormalizeObjectName(t *testing.T) {
}
}
}
+
+func TestExitDefUnmarshalAlwaysBlocked(t *testing.T) {
+ y := `exits:
+ north:
+ room: 5
+ always_blocked: true
+ south: 3
+ east:
+ room: 7
+ hidden: true
+`
+ var room struct {
+ Exits map[ExitDir]ExitDef `yaml:"exits"`
+ }
+ if err := yaml.Unmarshal([]byte(y), &room); err != nil {
+ t.Fatalf("unmarshal: %v", err)
+ }
+ if len(room.Exits) != 3 {
+ t.Fatalf("expected 3 exits, got %d", len(room.Exits))
+ }
+ n := room.Exits[North]
+ if !n.AlwaysBlocked {
+ t.Error("north exit should have AlwaysBlocked=true")
+ }
+ if n.Room != 5 {
+ t.Errorf("north target = %d, want 5", n.Room)
+ }
+ s := room.Exits[South]
+ if s.Room != 3 {
+ t.Errorf("south target = %d, want 3", s.Room)
+ }
+ if s.AlwaysBlocked {
+ t.Error("south exit should not have AlwaysBlocked")
+ }
+ e := room.Exits[East]
+ if !e.Hidden {
+ t.Error("east exit should have Hidden=true")
+ }
+ if e.AlwaysBlocked {
+ t.Error("east exit should not have AlwaysBlocked")
+ }
+}