diff options
| author | historia <[not public]> | 2026-07-09 05:27:10 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-07-09 05:27:10 -0400 |
| commit | c705ae942573984784ef501bf8198f61f5206ddd (patch) | |
| tree | c964066f3a244002bf75cb50a877630f46496f81 /internal/game | |
| parent | 74153c7814fc4cef988066ef04e38731a943bc12 (diff) | |
| download | thehouseoficarus-c705ae942573984784ef501bf8198f61f5206ddd.tar.gz | |
refactor: simplify yaml, remove support for old scalar fields
Diffstat (limited to 'internal/game')
| -rw-r--r-- | internal/game/act.go | 28 | ||||
| -rw-r--r-- | internal/game/cmd_room_remove_test.go | 62 | ||||
| -rw-r--r-- | internal/game/core_course.go | 60 | ||||
| -rw-r--r-- | internal/game/core_course_test.go | 45 | ||||
| -rw-r--r-- | internal/game/core_flags.go | 7 | ||||
| -rw-r--r-- | internal/game/core_flagstore.go | 10 | ||||
| -rw-r--r-- | internal/game/map_test.go | 48 | ||||
| -rw-r--r-- | internal/game/sys_triggers.go | 5 |
8 files changed, 99 insertions, 166 deletions
diff --git a/internal/game/act.go b/internal/game/act.go index ddeed04..91f05a8 100644 --- a/internal/game/act.go +++ b/internal/game/act.go @@ -7,6 +7,7 @@ import ( "strings" "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" @@ -332,7 +333,7 @@ func flagMatches(present bool, val, want any, not bool) bool { if want == nil { match = present && isTruthy(val) } else { - match = present && valuesEqual(val, want) + match = present && engine.ValuesEqual(val, want) } if not { return !match @@ -340,31 +341,6 @@ func flagMatches(present bool, val, want any, not bool) bool { return match } -// valuesEqual compares two any-typed values, normalizing numeric types (int, -// int64, float64) so that e.g. int(3) == int64(3) == float64(3). Non-numeric -// types fall back to ==. -func valuesEqual(a, b any) bool { - ai, aok := numericValue(a) - bi, bok := numericValue(b) - if aok && bok { - return ai == bi - } - return a == b -} - -// numericValue returns the value as a float64 if it is a numeric type. -func numericValue(v any) (float64, bool) { - switch x := v.(type) { - case int: - return float64(x), true - case int64: - return float64(x), true - case float64: - return x, true - } - return 0, false -} - func isTruthy(v any) bool { switch x := v.(type) { case nil: diff --git a/internal/game/cmd_room_remove_test.go b/internal/game/cmd_room_remove_test.go index 1868c30..a13af8a 100644 --- a/internal/game/cmd_room_remove_test.go +++ b/internal/game/cmd_room_remove_test.go @@ -85,9 +85,9 @@ func reloadRoom(t *testing.T, g *Game, id int) *world.Room { func TestRoomRemoveSuccessPull(t *testing.T) { dir := t.TempDir() - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: {room: 2}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -113,9 +113,9 @@ func TestRoomRemoveSuccessPull(t *testing.T) { func TestRoomRemoveDiagonalPull(t *testing.T) { dir := t.TempDir() - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n northeast: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n northeast: 3\n southwest: 1\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n southwest: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n northeast: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n northeast: {room: 3}\n southwest: {room: 1}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n southwest: {room: 2}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -145,9 +145,9 @@ func TestRoomRemoveNoExit(t *testing.T) { func TestRoomRemoveNotInsertChain(t *testing.T) { dir := t.TempDir() // B does not lead back to A via west. - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: {room: 2}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -162,8 +162,8 @@ func TestRoomRemoveNotInsertChain(t *testing.T) { func TestRoomRemoveDeadEndFarRoom(t *testing.T) { dir := t.TempDir() // B leads back to A but has no forward east exit. - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n west: 1\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n west: {room: 1}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -177,10 +177,10 @@ func TestRoomRemoveDeadEndFarRoom(t *testing.T) { func TestRoomRemoveOtherExitsInB(t *testing.T) { dir := t.TempDir() // B has east (fwd), west (back), AND up (extra). - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n up: 4\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: 2\n") - writeRemoveRoomFile(t, dir, 4, "name: D\nexits:\n down: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n up: {room: 4}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: {room: 2}\n") + writeRemoveRoomFile(t, dir, 4, "name: D\nexits:\n down: {room: 2}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -194,8 +194,8 @@ func TestRoomRemoveOtherExitsInB(t *testing.T) { func TestRoomRemoveFarReciprocityBroken(t *testing.T) { dir := t.TempDir() // C's west does not point back to B. - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -210,10 +210,10 @@ func TestRoomRemoveFarReciprocityBroken(t *testing.T) { func TestRoomRemoveExtraInboundEdge(t *testing.T) { dir := t.TempDir() // A clean chain A-east->B-east->C, but an unrelated room 5 also points to B. - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: 2\n") - writeRemoveRoomFile(t, dir, 5, "name: E\nexits:\n north: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: {room: 2}\n") + writeRemoveRoomFile(t, dir, 5, "name: E\nexits:\n north: {room: 2}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -228,12 +228,12 @@ func TestRoomRemoveExtraInboundEdge(t *testing.T) { // pulls room 6 onto room 5's cell, which must be rejected. func TestRoomRemoveOverlap(t *testing.T) { dir := t.TempDir() - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n south: 4\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n south: 6\n west: 2\n") - writeRemoveRoomFile(t, dir, 4, "name: D\nexits:\n east: 5\n north: 1\n") - writeRemoveRoomFile(t, dir, 5, "name: E\nexits:\n west: 4\n") - writeRemoveRoomFile(t, dir, 6, "name: F\nexits:\n north: 3\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n south: {room: 4}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n south: {room: 6}\n west: {room: 2}\n") + writeRemoveRoomFile(t, dir, 4, "name: D\nexits:\n east: {room: 5}\n north: {room: 1}\n") + writeRemoveRoomFile(t, dir, 5, "name: E\nexits:\n west: {room: 4}\n") + writeRemoveRoomFile(t, dir, 6, "name: F\nexits:\n north: {room: 3}\n") g := newRemoveGame(t, dir) sess := newRemoveSession(&player.Player{Name: "tester", RoomID: 1}) @@ -275,7 +275,7 @@ exits: blocked_message: "A rock blocks the way." hidden: true `) - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") writeRemoveRoomFile(t, dir, 3, `name: C exits: west: @@ -310,9 +310,9 @@ exits: // moved to A and notified. The caller stays in A. func TestRoomRemoveRelocatesPlayersInB(t *testing.T) { dir := t.TempDir() - writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: 2\n") - writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: 3\n west: 1\n") - writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: 2\n") + writeRemoveRoomFile(t, dir, 1, "name: A\nexits:\n east: {room: 2}\n") + writeRemoveRoomFile(t, dir, 2, "name: B\nexits:\n east: {room: 3}\n west: {room: 1}\n") + writeRemoveRoomFile(t, dir, 3, "name: C\nexits:\n west: {room: 2}\n") g := newRemoveGame(t, dir) caller := newRemoveSession(&player.Player{Name: "builder", RoomID: 1}) diff --git a/internal/game/core_course.go b/internal/game/core_course.go index 031eff5..6394b99 100644 --- a/internal/game/core_course.go +++ b/internal/game/core_course.go @@ -21,21 +21,17 @@ type ObstaclePhase struct { } // ObstacleDef is the YAML representation of a single agility obstacle. -// Two equivalent forms are supported: -// - Legacy: Messages (exactly 3) + TicksPerPhase + fail at phase index 1. -// - Preferred: Phases, an explicit ordered list with per-phase delays and -// an optional fail_check flag (at most one phase should carry it). +// Phases is the ordered list of advancement steps, each with a per-phase +// delay and an optional fail_check flag (at most one phase should carry it). type ObstacleDef struct { - RoomID int `yaml:"room_id"` - Verb string `yaml:"verb"` - XP int `yaml:"xp"` - FailDamage [2]int `yaml:"fail_damage"` - FailChance *float64 `yaml:"fail_chance,omitempty"` - TicksPerPhase float64 `yaml:"ticks_per_phase"` - Messages []string `yaml:"messages"` - Phases []ObstaclePhase `yaml:"phases"` - ExitDir string `yaml:"exit_dir"` - OnFailRoom int `yaml:"on_fail,omitempty"` + RoomID int `yaml:"room_id"` + Verb string `yaml:"verb"` + XP int `yaml:"xp"` + FailDamage [2]int `yaml:"fail_damage"` + FailChance *float64 `yaml:"fail_chance,omitempty"` + Phases []ObstaclePhase `yaml:"phases"` + ExitDir string `yaml:"exit_dir"` + OnFailRoom int `yaml:"on_fail,omitempty"` } type CourseConfig struct { @@ -140,33 +136,13 @@ func (cs *CourseStore) GetObstacle(roomID int) *ObstacleInfo { } // resolvePhases converts an ObstacleDef into a normalized PhaseInfo list. -// Preferred form: explicit Phases. Legacy form: Messages with a shared -// TicksPerPhase and the failure check at the middle (index 1) phase. func resolvePhases(obs ObstacleDef) []PhaseInfo { - if len(obs.Phases) > 0 { - phases := make([]PhaseInfo, 0, len(obs.Phases)) - for _, p := range obs.Phases { - phases = append(phases, PhaseInfo{ - Message: p.Message, - Delay: p.Delay, - FailCheck: p.FailCheck, - }) - } - return phases - } - msgs := obs.Messages - phases := make([]PhaseInfo, 0, len(msgs)) - for i, m := range msgs { - var delay float64 - if i == 0 { - delay = 0 - } else { - delay = obs.TicksPerPhase - } + phases := make([]PhaseInfo, 0, len(obs.Phases)) + for _, p := range obs.Phases { phases = append(phases, PhaseInfo{ - Message: m, - Delay: delay, - FailCheck: i == 1, + Message: p.Message, + Delay: p.Delay, + FailCheck: p.FailCheck, }) } return phases @@ -197,12 +173,6 @@ func (cs *CourseStore) resolveExitTarget(roomID int, dir string) int { return 0 } switch x := v.(type) { - case int: - return x - case int64: - return int(x) - case float64: - return int(x) case map[string]any: if r, ok := x["room"]; ok { switch y := r.(type) { diff --git a/internal/game/core_course_test.go b/internal/game/core_course_test.go index 64ec8ad..93f49f5 100644 --- a/internal/game/core_course_test.go +++ b/internal/game/core_course_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -func TestResolvePhasesPrefersExplicitPhases(t *testing.T) { +func TestResolvePhases(t *testing.T) { obs := ObstacleDef{ RoomID: 5, Verb: "climb", @@ -15,9 +15,6 @@ func TestResolvePhasesPrefersExplicitPhases(t *testing.T) { {Message: "middle", Delay: 2, FailCheck: true}, {Message: "end", Delay: 1.5}, }, - // Legacy fields set as a decoy; should be ignored when Phases present. - TicksPerPhase: 99, - Messages: []string{"ignored1", "ignored2", "ignored3"}, } got := resolvePhases(obs) if len(got) != 3 { @@ -34,28 +31,6 @@ func TestResolvePhasesPrefersExplicitPhases(t *testing.T) { } } -func TestResolvePhasesLegacyMigration(t *testing.T) { - obs := ObstacleDef{ - RoomID: 7, - Verb: "jump", - TicksPerPhase: 2, - Messages: []string{"a", "b", "c"}, - } - got := resolvePhases(obs) - if len(got) != 3 { - t.Fatalf("expected 3 legacy phases, got %d", len(got)) - } - if got[0].Message != "a" || got[0].Delay != 0 || got[0].FailCheck { - t.Errorf("legacy phase 0 wrong: %+v", got[0]) - } - if got[1].Message != "b" || got[1].Delay != 2 || !got[1].FailCheck { - t.Errorf("legacy phase 1 must carry fail_check at index 1: %+v", got[1]) - } - if got[2].Message != "c" || got[2].Delay != 2 || got[2].FailCheck { - t.Errorf("legacy phase 2 wrong: %+v", got[2]) - } -} - func TestCourseStoreLoadsWithExplicitFailChance(t *testing.T) { dir := t.TempDir() coursesDir := filepath.Join(dir, "courses") @@ -85,8 +60,14 @@ obstacles: verb: jump xp: 14 fail_damage: [1, 3] - messages: ["p0", "p1", "p2"] - ticks_per_phase: 1 + phases: + - message: "p0" + delay: 0 + - message: "p1" + delay: 1 + fail_check: true + - message: "p2" + delay: 1 `) if err := os.WriteFile(filepath.Join(coursesDir, "testcourse.yaml"), yaml, 0644); err != nil { t.Fatal(err) @@ -116,16 +97,16 @@ obstacles: t.Errorf("first obstacle should have no completion xp, got %d", o1.CompletionXP) } - // Obstacle 2: legacy migration, derived fail chance (nil) + // Obstacle 2: explicit phases, derived fail chance (nil) o2 := cs.GetObstacle(102) if o2 == nil { t.Fatal("expected obstacle for room 102") } if len(o2.Phases) != 3 || !o2.Phases[1].FailCheck { - t.Errorf("legacy obstacle phases not migrated: %+v", o2.Phases) + t.Errorf("obstacle 2 phases wrong: %+v", o2.Phases) } if o2.FailChance != nil { - t.Errorf("legacy obstacle should have nil (derived) fail_chance, got %v", *o2.FailChance) + t.Errorf("obstacle 2 should have nil (derived) fail_chance, got %v", *o2.FailChance) } if o2.CompletionXP != 50 { t.Errorf("last obstacle should carry completion_xp, got %d", o2.CompletionXP) @@ -137,4 +118,4 @@ obstacles: if cs.GetObstacle(999) != nil { t.Error("expected nil for unrelated room") } -}
\ No newline at end of file +} diff --git a/internal/game/core_flags.go b/internal/game/core_flags.go index 5e1c812..c78f3c3 100644 --- a/internal/game/core_flags.go +++ b/internal/game/core_flags.go @@ -1,6 +1,9 @@ package game -import "thehouseoficarus/internal/player" +import ( + "thehouseoficarus/internal/engine" + "thehouseoficarus/internal/player" +) func getPlayerFlagInt(p *player.Player, key string) int { if p.Flags == nil { @@ -37,7 +40,7 @@ func (g *Game) setPlayerFlag(p *player.Player, key string, val any) { p.EnsureFlags() old, existed := p.Flags[key] p.Flags[key] = val - if !existed || !valuesEqual(old, val) { + if !existed || !engine.ValuesEqual(old, val) { g.firePlayerFlagTrigger(p, key, val) } } diff --git a/internal/game/core_flagstore.go b/internal/game/core_flagstore.go index 18578b7..5dd8d00 100644 --- a/internal/game/core_flagstore.go +++ b/internal/game/core_flagstore.go @@ -1,6 +1,10 @@ package game -import "sync" +import ( + "sync" + + "thehouseoficarus/internal/engine" +) // GlobalFlagChangeCallback is invoked when a global flag value actually changes // (old value differs from new, or new flag is created with a truthy value). @@ -39,7 +43,7 @@ func (f *GlobalFlagStore) Set(name string, value any) { cbs := f.callbacks f.mu.Unlock() - if !existed || !valuesEqual(old, value) { + if !existed || !engine.ValuesEqual(old, value) { for _, cb := range cbs { cb(name, value) } @@ -52,7 +56,7 @@ func (f *GlobalFlagStore) SetAll(m map[string]any) { for k, v := range m { old, existed := f.flags[k] f.flags[k] = v - if !existed || !valuesEqual(old, v) { + if !existed || !engine.ValuesEqual(old, v) { changed[k] = v } } diff --git a/internal/game/map_test.go b/internal/game/map_test.go index 2975551..d13cbdc 100644 --- a/internal/game/map_test.go +++ b/internal/game/map_test.go @@ -46,14 +46,14 @@ func TestMapConnectorGlyphs(t *testing.T) { }{ { name: "bidirectional bar", - room1: "name: One\nexits:\n east: 2\n", - room2: "name: Two\nexits:\n west: 1\n", + room1: "name: One\nexits:\n east: {room: 2}\n", + room2: "name: Two\nexits:\n west: {room: 1}\n", wantPresent: "-", wantAbsent: []string{"X", "<", ">"}, }, { name: "one-way east arrow", - room1: "name: One\nexits:\n east: 2\n", + room1: "name: One\nexits:\n east: {room: 2}\n", room2: "name: Two\n", wantPresent: ">", wantAbsent: []string{"X", "-", "<"}, @@ -61,7 +61,7 @@ func TestMapConnectorGlyphs(t *testing.T) { { name: "forward blocked, reverse open -> X (shortest path is blocked)", room1: condEast, - room2: "name: Two\nexits:\n west: 1\n", + room2: "name: Two\nexits:\n west: {room: 1}\n", flagOpen: false, wantPresent: "X", wantAbsent: []string{"-", "<", ">"}, @@ -77,15 +77,15 @@ func TestMapConnectorGlyphs(t *testing.T) { { name: "conditional unblocked -> bar", room1: condEast, - room2: "name: Two\nexits:\n west: 1\n", + room2: "name: Two\nexits:\n west: {room: 1}\n", flagOpen: true, wantPresent: "-", wantAbsent: []string{"X", "<", ">"}, }, { name: "outward open, inward blocked -> outward arrow (dist rules)", - room1: "name: One\nexits:\n east: 2\n", - room2: "name: Two\nexits:\n west: 1\n north: 3\n", + room1: "name: One\nexits:\n east: {room: 2}\n", + room2: "name: Two\nexits:\n west: {room: 1}\n north: {room: 3}\n", room3: condSouth, flagOpen: false, // dist[room1]=0, dist[room2]=1, dist[room3]=2. @@ -96,21 +96,21 @@ func TestMapConnectorGlyphs(t *testing.T) { }, { name: "bidirectional diagonal NE-SW", - room1: "name: One\nexits:\n northeast: 2\n", - room2: "name: Two\nexits:\n southwest: 1\n", + room1: "name: One\nexits:\n northeast: {room: 2}\n", + room2: "name: Two\nexits:\n southwest: {room: 1}\n", wantPresent: "/", wantAbsent: []string{"X", "\\"}, }, { name: "bidirectional diagonal NW-SE", - room1: "name: One\nexits:\n northwest: 2\n", - room2: "name: Two\nexits:\n southeast: 1\n", + room1: "name: One\nexits:\n northwest: {room: 2}\n", + room2: "name: Two\nexits:\n southeast: {room: 1}\n", wantPresent: "\\", wantAbsent: []string{"X", "/"}, }, { name: "one-way NE arrow", - room1: "name: One\nexits:\n northeast: 2\n", + room1: "name: One\nexits:\n northeast: {room: 2}\n", room2: "name: Two\n", wantPresent: "/", wantAbsent: []string{"X", "\\"}, @@ -134,15 +134,15 @@ func TestMapConnectorGlyphs(t *testing.T) { { name: "diagonal conditional unblocked -> bar", room1: condNE, - room2: "name: Two\nexits:\n southwest: 1\n", + room2: "name: Two\nexits:\n southwest: {room: 1}\n", flagOpen: true, wantPresent: "/", wantAbsent: []string{"X", "\\"}, }, { name: "criss-crossed diagonal paths show X", - room1: "name: One\nexits:\n east: 2\n south: 3\n southeast: 4\n", - room2: "name: Two\nexits:\n southwest: 3\n", + room1: "name: One\nexits:\n east: {room: 2}\n south: {room: 3}\n southeast: {room: 4}\n", + room2: "name: Two\nexits:\n southwest: {room: 3}\n", room3: "name: Three\n", room4: "name: Four\n", wantPresent: "X", @@ -187,10 +187,10 @@ func TestMapConnectorGlyphs(t *testing.T) { // both bar glyphs and arrow glyphs. func TestMapDiagonalOneWayCrossing(t *testing.T) { dir := t.TempDir() - writeTempRoom(t, dir, 1, "name: One\nexits:\n north: 3\n northeast: 2\n") + writeTempRoom(t, dir, 1, "name: One\nexits:\n north: {room: 3}\n northeast: {room: 2}\n") writeTempRoom(t, dir, 2, "name: Two\n") - writeTempRoom(t, dir, 3, "name: Three\nexits:\n southeast: 4\n") - writeTempRoom(t, dir, 4, "name: Four\nexits:\n northwest: 3\n") + writeTempRoom(t, dir, 3, "name: Three\nexits:\n southeast: {room: 4}\n") + writeTempRoom(t, dir, 4, "name: Four\nexits:\n northwest: {room: 3}\n") g := &Game{Deps: Deps{World: world.New(dir)}} sess := &net.Session{Player: &player.Player{Options: map[string]any{"unicode": true}}} @@ -396,10 +396,10 @@ func TestMap3DDisconnectedComponent(t *testing.T) { // tower2base→up→tower2 (1,0,0). Tower 2 is at the same z=0 as tower 1 but // unreachable via horizontal exits. The 3D map should still show it. dir := t.TempDir() - writeTempRoom(t, dir, 1, "name: Tower One\nexits:\n down: 2\n") - writeTempRoom(t, dir, 2, "name: Bridge\nexits:\n east: 3\n up: 1\n") - writeTempRoom(t, dir, 3, "name: Tower Two Base\nexits:\n up: 4\n west: 2\n") - writeTempRoom(t, dir, 4, "name: Tower Two\nexits:\n down: 3\n") + writeTempRoom(t, dir, 1, "name: Tower One\nexits:\n down: {room: 2}\n") + writeTempRoom(t, dir, 2, "name: Bridge\nexits:\n east: {room: 3}\n up: {room: 1}\n") + writeTempRoom(t, dir, 3, "name: Tower Two Base\nexits:\n up: {room: 4}\n west: {room: 2}\n") + writeTempRoom(t, dir, 4, "name: Tower Two\nexits:\n down: {room: 3}\n") g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()} mg := mapGlyphsForPlayer(false) @@ -423,8 +423,8 @@ func TestMap3DDifferentZExcluded(t *testing.T) { // Room 1 at (0,0,0) with up to room 2 at (0,0,1). Room 2 is at z=1, // different from the player's z=0 level — should NOT show on the map. dir := t.TempDir() - writeTempRoom(t, dir, 1, "name: Ground\nexits:\n up: 2\n") - writeTempRoom(t, dir, 2, "name: Upper\nexits:\n down: 1\n") + writeTempRoom(t, dir, 1, "name: Ground\nexits:\n up: {room: 2}\n") + writeTempRoom(t, dir, 2, "name: Upper\nexits:\n down: {room: 1}\n") g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()} mg := mapGlyphsForPlayer(false) diff --git a/internal/game/sys_triggers.go b/internal/game/sys_triggers.go index 2e8b877..6a1e224 100644 --- a/internal/game/sys_triggers.go +++ b/internal/game/sys_triggers.go @@ -8,7 +8,6 @@ import ( "thehouseoficarus/internal/engine" "thehouseoficarus/internal/net" "thehouseoficarus/internal/player" - "thehouseoficarus/internal/world" ) func (g *Game) TriggerSeqTick() { @@ -150,7 +149,7 @@ func (g *Game) executeGlobalTriggerStep(step *behavior.StepAction, roomID int, f g.applyStepAction(nil, nil, step, roomID, scopeGlobal, flagValue) } -func (g *Game) spawnTriggerMob(sess *net.Session, p *player.Player, cfg *world.SpawnMobConfig, roomID int) { +func (g *Game) spawnTriggerMob(sess *net.Session, p *player.Player, cfg *behavior.SpawnMobConfig, roomID int) { if cfg.ID == "" { return } @@ -166,7 +165,7 @@ func (g *Game) spawnTriggerMob(sess *net.Session, p *player.Player, cfg *world.S sess.WriteLine(g.colorize(sess, "broadcast", mobDisplayName(inst, true)+" appears!")) } -func (g *Game) spawnWorldTriggerMob(cfg *world.SpawnMobConfig, roomID int) { +func (g *Game) spawnWorldTriggerMob(cfg *behavior.SpawnMobConfig, roomID int) { if cfg.ID == "" { return } |
