aboutsummaryrefslogtreecommitdiff
path: root/internal/world
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-09 05:27:10 -0400
committerhistoria <[not public]>2026-07-09 05:27:10 -0400
commitc705ae942573984784ef501bf8198f61f5206ddd (patch)
treec964066f3a244002bf75cb50a877630f46496f81 /internal/world
parent74153c7814fc4cef988066ef04e38731a943bc12 (diff)
downloadthehouseoficarus-c705ae942573984784ef501bf8198f61f5206ddd.tar.gz
refactor: simplify yaml, remove support for old scalar fields
Diffstat (limited to 'internal/world')
-rw-r--r--internal/world/grid_test.go38
-rw-r--r--internal/world/insert_remove_test.go68
-rw-r--r--internal/world/mob.go2
-rw-r--r--internal/world/room.go26
-rw-r--r--internal/world/room_test.go9
-rw-r--r--internal/world/trigger.go4
-rw-r--r--internal/world/trigger_store.go24
7 files changed, 62 insertions, 109 deletions
diff --git a/internal/world/grid_test.go b/internal/world/grid_test.go
index c777f90..005f60f 100644
--- a/internal/world/grid_test.go
+++ b/internal/world/grid_test.go
@@ -39,9 +39,9 @@ func hasConflictKind(conflicts []GridConflict, kind string) bool {
func TestBuildGridConflictsClean(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n south: 3\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n south: 4\n")
- writeGridTestRoom(t, dir, 3, "exits:\n east: 4\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n south: {room: 3}\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n south: {room: 4}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n east: {room: 4}\n")
writeGridTestRoom(t, dir, 4, "name: corner\n")
w := New(dir)
@@ -52,9 +52,9 @@ func TestBuildGridConflictsClean(t *testing.T) {
func TestBuildGridConflictsOverlap(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n south: 3\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n south: 5\n")
- writeGridTestRoom(t, dir, 3, "exits:\n east: 4\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n south: {room: 3}\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n south: {room: 5}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n east: {room: 4}\n")
writeGridTestRoom(t, dir, 4, "name: four\n")
writeGridTestRoom(t, dir, 5, "name: five\n")
@@ -67,9 +67,9 @@ func TestBuildGridConflictsOverlap(t *testing.T) {
func TestBuildGridConflictsTwist(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n south: 4\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n")
- writeGridTestRoom(t, dir, 4, "exits:\n east: 3\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n south: {room: 4}\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n")
+ writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 3}\n")
writeGridTestRoom(t, dir, 3, "name: three\n")
w := New(dir)
@@ -81,8 +81,8 @@ func TestBuildGridConflictsTwist(t *testing.T) {
func TestBuildGridConflictsDiagonalClean(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n northeast: 2\n")
- writeGridTestRoom(t, dir, 2, "name: two\n exits:\n southwest: 1\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n northeast: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "name: two\n exits:\n southwest: {room: 1}\n")
w := New(dir)
if conflicts := BuildGridConflicts(1, loadGridRoom(w)); len(conflicts) != 0 {
@@ -97,8 +97,8 @@ func TestBuildGridConflictsDiagonalClean(t *testing.T) {
// confirm the (clean) post-edit world has no conflicts.
func TestBuildGridConflictsHypotheticalInsert(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "name: one\nexits:\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "name: two\nexits:\n west: 1\n")
+ writeGridTestRoom(t, dir, 1, "name: one\nexits:\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "name: two\nexits:\n west: {room: 1}\n")
w := New(dir)
newRoom := &Room{Name: "new", Exits: map[ExitDir]ExitDef{
@@ -145,12 +145,12 @@ func TestBuildGridConflictsHypotheticalInsert(t *testing.T) {
// (1,1,0). The helper must report an overlap without anything being written.
func TestBuildGridConflictsHypotheticalRemoveOverlap(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n south: 4\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n west: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n south: 6\n west: 2\n")
- writeGridTestRoom(t, dir, 4, "exits:\n east: 5\n north: 1\n")
- writeGridTestRoom(t, dir, 5, "exits:\n west: 4\n")
- writeGridTestRoom(t, dir, 6, "exits:\n north: 3\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n south: {room: 6}\n west: {room: 2}\n")
+ writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n")
+ writeGridTestRoom(t, dir, 5, "exits:\n west: {room: 4}\n")
+ writeGridTestRoom(t, dir, 6, "exits:\n north: {room: 3}\n")
w := New(dir)
load := func(id int) (*Room, bool) {
diff --git a/internal/world/insert_remove_test.go b/internal/world/insert_remove_test.go
index 3be3222..15d752e 100644
--- a/internal/world/insert_remove_test.go
+++ b/internal/world/insert_remove_test.go
@@ -9,8 +9,8 @@ const insertSentinel = 9999
func TestInsertGridConflictsCleanNSEW(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n west: 1\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n west: {room: 1}\n")
w := New(dir)
if c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 {
t.Errorf("clean east insert: expected no conflicts, got %+v", c)
@@ -19,8 +19,8 @@ func TestInsertGridConflictsCleanNSEW(t *testing.T) {
func TestInsertGridConflictsCleanDiagonal(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n northeast: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n southwest: 1\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n northeast: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n southwest: {room: 1}\n")
w := New(dir)
if c := InsertGridConflicts(1, Northeast, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 {
t.Errorf("clean NE insert: expected no conflicts, got %+v", c)
@@ -29,8 +29,8 @@ func TestInsertGridConflictsCleanDiagonal(t *testing.T) {
func TestInsertGridConflictsCleanUpDown(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n up: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n down: 1\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n up: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n down: {room: 1}\n")
w := New(dir)
if c := InsertGridConflicts(1, Up, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 {
t.Errorf("clean up insert: expected no conflicts, got %+v", c)
@@ -73,14 +73,14 @@ func TestInsertGridConflictsCleanUpDown(t *testing.T) {
// beyond-set (reachable from 1 via south, not via east/2), so it's an overlap.
func TestInsertGridConflictsOverlap(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n south: 4\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n west: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n west: 2\n")
- writeGridTestRoom(t, dir, 4, "exits:\n east: 5\n north: 1\n")
- writeGridTestRoom(t, dir, 5, "exits:\n east: 6\n west: 4\n")
- writeGridTestRoom(t, dir, 6, "exits:\n east: 7\n west: 5\n")
- writeGridTestRoom(t, dir, 7, "exits:\n north: 8\n west: 6\n")
- writeGridTestRoom(t, dir, 8, "exits:\n south: 7\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n")
+ writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n")
+ writeGridTestRoom(t, dir, 5, "exits:\n east: {room: 6}\n west: {room: 4}\n")
+ writeGridTestRoom(t, dir, 6, "exits:\n east: {room: 7}\n west: {room: 5}\n")
+ writeGridTestRoom(t, dir, 7, "exits:\n north: {room: 8}\n west: {room: 6}\n")
+ writeGridTestRoom(t, dir, 8, "exits:\n south: {room: 7}\n")
w := New(dir)
// Sanity: the pre-edit world must be clean.
@@ -101,11 +101,11 @@ func TestInsertGridConflictsOverlap(t *testing.T) {
// insert helper must surface a twist conflict.
func TestInsertGridConflictsTwist(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n south: 4\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n west: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n west: 2\n south: 5\n")
- writeGridTestRoom(t, dir, 4, "exits:\n east: 5\n north: 1\n")
- writeGridTestRoom(t, dir, 5, "exits:\n north: 3\n west: 4\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n south: {room: 5}\n")
+ writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n")
+ writeGridTestRoom(t, dir, 5, "exits:\n north: {room: 3}\n west: {room: 4}\n")
w := New(dir)
c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w))
@@ -120,7 +120,7 @@ func TestInsertGridConflictsTwist(t *testing.T) {
// geometrically clean insert.
func TestInsertGridConflictsOneWayFarReciprocal(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n")
writeGridTestRoom(t, dir, 2, "exits:\n") // no west exit back to 1
w := New(dir)
if c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 {
@@ -131,9 +131,9 @@ func TestInsertGridConflictsOneWayFarReciprocal(t *testing.T) {
func TestRemoveGridConflictsCleanPull(t *testing.T) {
dir := t.TempDir()
// 1 east→2 east→3, with reciprocals. Removing 2 pulls 3 to (1,0,0). Clean.
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n west: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n west: 2\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n")
w := New(dir)
if c := RemoveGridConflicts(1, East, loadGridRoom(w)); len(c) != 0 {
t.Errorf("clean pull should produce no conflicts, got %+v", c)
@@ -142,9 +142,9 @@ func TestRemoveGridConflictsCleanPull(t *testing.T) {
func TestRemoveGridConflictsDiagonalPull(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n northeast: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n northeast: 3\n southwest: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n southwest: 2\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n northeast: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n northeast: {room: 3}\n southwest: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n southwest: {room: 2}\n")
w := New(dir)
if c := RemoveGridConflicts(1, Northeast, loadGridRoom(w)); len(c) != 0 {
t.Errorf("clean diagonal pull should produce no conflicts, got %+v", c)
@@ -155,12 +155,12 @@ func TestRemoveGridConflictsDiagonalPull(t *testing.T) {
// removing 2 pulls 6 onto 5's cell.
func TestRemoveGridConflictsOverlap(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n south: 4\n")
- writeGridTestRoom(t, dir, 2, "exits:\n east: 3\n west: 1\n")
- writeGridTestRoom(t, dir, 3, "exits:\n south: 6\n west: 2\n")
- writeGridTestRoom(t, dir, 4, "exits:\n east: 5\n north: 1\n")
- writeGridTestRoom(t, dir, 5, "exits:\n west: 4\n")
- writeGridTestRoom(t, dir, 6, "exits:\n north: 3\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n")
+ writeGridTestRoom(t, dir, 3, "exits:\n south: {room: 6}\n west: {room: 2}\n")
+ writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n")
+ writeGridTestRoom(t, dir, 5, "exits:\n west: {room: 4}\n")
+ writeGridTestRoom(t, dir, 6, "exits:\n north: {room: 3}\n")
w := New(dir)
if c := BuildGridConflicts(1, loadGridRoom(w)); len(c) != 0 {
@@ -177,8 +177,8 @@ func TestRemoveGridConflictsOverlap(t *testing.T) {
// world this cannot introduce a conflict.
func TestRemoveGridConflictsDeadEnd(t *testing.T) {
dir := t.TempDir()
- writeGridTestRoom(t, dir, 1, "exits:\n east: 2\n")
- writeGridTestRoom(t, dir, 2, "exits:\n west: 1\n")
+ writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n")
+ writeGridTestRoom(t, dir, 2, "exits:\n west: {room: 1}\n")
w := New(dir)
if c := RemoveGridConflicts(1, East, loadGridRoom(w)); len(c) != 0 {
t.Errorf("dead-end removal should produce no conflicts, got %+v", c)
diff --git a/internal/world/mob.go b/internal/world/mob.go
index a9e2f7e..45b0fb8 100644
--- a/internal/world/mob.go
+++ b/internal/world/mob.go
@@ -645,7 +645,7 @@ func (s *MobStore) RollIdleDescription(inst *MobInstance) {
inst.WanderTickCounter = 0
}
-func (s *MobStore) SpawnTransient(def *MobDef, cfg *SpawnMobConfig, roomID int, owner string) *MobInstance {
+func (s *MobStore) SpawnTransient(def *MobDef, cfg *behavior.SpawnMobConfig, roomID int, owner string) *MobInstance {
s.mu.Lock()
defer s.mu.Unlock()
diff --git a/internal/world/room.go b/internal/world/room.go
index 08e18a4..8ae2d13 100644
--- a/internal/world/room.go
+++ b/internal/world/room.go
@@ -83,19 +83,6 @@ type ExitDef struct {
AlwaysBlocked bool `yaml:"always_blocked,omitempty"`
}
-func (e *ExitDef) UnmarshalYAML(value *yaml.Node) error {
- if value.Kind == yaml.ScalarNode {
- var n int
- if err := value.Decode(&n); err != nil {
- return err
- }
- e.Room = n
- return nil
- }
- type raw ExitDef
- return value.Decode((*raw)(e))
-}
-
type Room struct {
ID int `yaml:"id"`
Name string `yaml:"name"`
@@ -117,19 +104,6 @@ type RoomMob struct {
WanderInterval float64 `yaml:"wander_interval,omitempty"`
}
-func (rm *RoomMob) UnmarshalYAML(value *yaml.Node) error {
- if value.Kind == yaml.ScalarNode {
- var s string
- if err := value.Decode(&s); err != nil {
- return err
- }
- rm.ID = s
- return nil
- }
- type raw RoomMob
- return value.Decode((*raw)(rm))
-}
-
// RoomObject is either a reference to a file-backed object definition (only
// `id`/wander fields set) or a fully local object definition (Local != nil).
// An entry is treated as local when it carries any passive content field
diff --git a/internal/world/room_test.go b/internal/world/room_test.go
index 1ad974e..855eba5 100644
--- a/internal/world/room_test.go
+++ b/internal/world/room_test.go
@@ -27,11 +27,13 @@ objects:
- id: workbench
- name: window
hidden: true
- description: "A small window."
+ description:
+ - text: "A small window."
- id: control
name: instrument panel
aliases: [cockpit]
- description: "A panel."
+ description:
+ - text: "A panel."
`
// rebuild the path index so LoadRoom can find the room file
writeRoom(t, dir, body)
@@ -98,7 +100,8 @@ func TestExitDefUnmarshalAlwaysBlocked(t *testing.T) {
north:
room: 5
always_blocked: true
- south: 3
+ south:
+ room: 3
east:
room: 7
hidden: true
diff --git a/internal/world/trigger.go b/internal/world/trigger.go
index e7f3b75..de07c18 100644
--- a/internal/world/trigger.go
+++ b/internal/world/trigger.go
@@ -2,10 +2,6 @@ package world
import "thehouseoficarus/internal/behavior"
-// SpawnMobConfig is an alias for the behavior.SpawnMobConfig so callers that
-// historically referenced world.SpawnMobConfig continue to compile.
-type SpawnMobConfig = behavior.SpawnMobConfig
-
type TriggerDef struct {
ID string `yaml:"id"`
OnPlayerFlag string `yaml:"on_player_flag"`
diff --git a/internal/world/trigger_store.go b/internal/world/trigger_store.go
index 04d77f4..e50ae81 100644
--- a/internal/world/trigger_store.go
+++ b/internal/world/trigger_store.go
@@ -9,6 +9,7 @@ import (
"gopkg.in/yaml.v3"
"thehouseoficarus/internal/behavior"
+ "thehouseoficarus/internal/engine"
)
type TriggerStore struct {
@@ -262,7 +263,7 @@ func (ts *TriggerStore) valueMatches(want, got any) bool {
if want == nil {
return true
}
- return valuesEqual(want, got)
+ return engine.ValuesEqual(want, got)
}
func (ts *TriggerStore) SnapshotPlayerSeqs() []*PlayerTriggerSeq {
@@ -311,27 +312,6 @@ func (ts *TriggerStore) AllGlobalTriggers() []*TriggerDef {
return out
}
-func valuesEqual(a, b any) bool {
- ai, aok := numericValue(a)
- bi, bok := numericValue(b)
- if aok && bok {
- return ai == bi
- }
- return a == b
-}
-
-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 (ts *TriggerStore) AllRoomTriggers() map[int][]*TriggerDef {
ts.mu.Lock()
defer ts.mu.Unlock()