diff options
Diffstat (limited to 'internal/world')
| -rw-r--r-- | internal/world/correct_audit_fixes_test.go | 18 | ||||
| -rw-r--r-- | internal/world/room.go | 7 |
2 files changed, 25 insertions, 0 deletions
diff --git a/internal/world/correct_audit_fixes_test.go b/internal/world/correct_audit_fixes_test.go new file mode 100644 index 0000000..0ecb87a --- /dev/null +++ b/internal/world/correct_audit_fixes_test.go @@ -0,0 +1,18 @@ +package world + +import ( + "testing" + + "gopkg.in/yaml.v3" +) + +// Regression: a reference-style room object entry (id only) that also carries +// behavior fields silently lost them at runtime, because the loader always +// uses the object file. It must now be rejected at load time. +func TestRoomObjectReferenceRejectsBehaviorFields(t *testing.T) { + src := "id: 1\nname: Test\nobjects:\n - id: chest\n on_use:\n - steps:\n - message: hi\n" + var r Room + if err := yaml.Unmarshal([]byte(src), &r); err == nil { + t.Fatal("reference object entry with on_use was accepted; the behavior would be silently lost") + } +} diff --git a/internal/world/room.go b/internal/world/room.go index e200f32..9b9bef7 100644 --- a/internal/world/room.go +++ b/internal/world/room.go @@ -171,6 +171,13 @@ func (ro *RoomObject) UnmarshalYAML(value *yaml.Node) error { ro.Local = &def return nil } + // A reference entry (no name/description) that also carries behavior + // fields silently loses them at runtime, because the loader always uses + // the object file. Reject it instead of discarding authored behavior. + if def.RemovalItem != "" || len(def.OnUse) > 0 || def.Steal != nil || + def.Gather != nil || def.Talk != nil || def.Safespot != nil { + return fmt.Errorf("room object entry %q cannot carry behavior (on_use/gather/talk/steal/removal_item/safespot); define it in objects/%s.yaml or give the entry a name", ref.ID, ref.ID) + } ro.ID = ref.ID ro.HiddenOverride = ref.Hidden return nil |
