aboutsummaryrefslogtreecommitdiff
path: root/internal/world/room.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-27 21:25:20 -0400
committerhistoria <[not public]>2026-06-27 21:25:20 -0400
commit87dacfbb3dd16e7f55a82361eace98f9a39d75c8 (patch)
treed548f75a37b5b8e960c5e5d111237e172650bb59 /internal/world/room.go
parent83f8f5447ec3baf85314ce7343f0e339d28bcc15 (diff)
downloadthehouseoficarus-87dacfbb3dd16e7f55a82361eace98f9a39d75c8.tar.gz
feat: room-specific objects can be defined inline in room yaml
Diffstat (limited to 'internal/world/room.go')
-rw-r--r--internal/world/room.go55
1 files changed, 52 insertions, 3 deletions
diff --git a/internal/world/room.go b/internal/world/room.go
index 8f13b82..8b8830e 100644
--- a/internal/world/room.go
+++ b/internal/world/room.go
@@ -1,8 +1,11 @@
package world
import (
+ "strings"
+
"gopkg.in/yaml.v3"
"thehouseoficarus/internal/behavior"
+ "thehouseoficarus/internal/object"
)
type ExitDir string
@@ -125,8 +128,54 @@ func (e EnterStep) IsTimed() bool {
e.TakeItem != "" || e.Teleport != 0 || e.Heal != 0
}
+// RoomObject is either a reference to a file-backed object definition (only
+// `id`/wander fields set) or a fully inline object definition (Inline != nil).
+// An entry is treated as inline when it carries any passive content field
+// (name, description, aliases, inroom_description, color, hidden, on_look).
+// Inline objects are room-scoped: their identity (ID, used as the ObjState
+// DefID) is derived from the normalized name; `id:` is reserved for references.
type RoomObject struct {
- ID string `yaml:"id"`
- WanderRooms []int `yaml:"wander_rooms"`
- WanderInterval float64 `yaml:"wander_interval"`
+ ID string
+ WanderRooms []int
+ WanderInterval float64
+ Inline *object.ObjectDef
+}
+
+func (ro *RoomObject) UnmarshalYAML(value *yaml.Node) error {
+ type rawRef struct {
+ ID string `yaml:"id"`
+ WanderRooms []int `yaml:"wander_rooms"`
+ WanderInterval float64 `yaml:"wander_interval"`
+ }
+ var ref rawRef
+ if err := value.Decode(&ref); err != nil {
+ return err
+ }
+ ro.WanderRooms = ref.WanderRooms
+ ro.WanderInterval = ref.WanderInterval
+
+ var def object.ObjectDef
+ if err := value.Decode(&def); err != nil {
+ return err
+ }
+ inline := def.Name != "" || len(def.Description) > 0 || def.InRoomDescription != "" ||
+ len(def.Aliases) > 0 || def.Color != "" || def.Hidden || def.OnLook != nil
+ if inline {
+ // Identity derives from the name. def.ID still holds any explicit `id:`
+ // the builder wrote; it is left in place only so validation can flag it
+ // as a stray field (runtime resolution overrides the copy's ID anyway).
+ ro.ID = NormalizeObjectName(def.Name)
+ ro.Inline = &def
+ return nil
+ }
+ ro.ID = ref.ID
+ return nil
+}
+
+// NormalizeObjectName lowercases, trims, and collapses internal whitespace,
+// keeping spaces (not underscores) so the word-prefix matcher treats the name
+// as a single token in its `_`-split fallback. It is the canonical derivation
+// of an inline object's ObjState DefID from its name.
+func NormalizeObjectName(name string) string {
+ return strings.Join(strings.Fields(strings.ToLower(name)), " ")
}