diff options
| author | historia <[not public]> | 2026-06-27 21:25:20 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-27 21:25:20 -0400 |
| commit | 87dacfbb3dd16e7f55a82361eace98f9a39d75c8 (patch) | |
| tree | d548f75a37b5b8e960c5e5d111237e172650bb59 /internal/game | |
| parent | 83f8f5447ec3baf85314ce7343f0e339d28bcc15 (diff) | |
| download | thehouseoficarus-87dacfbb3dd16e7f55a82361eace98f9a39d75c8.tar.gz | |
feat: room-specific objects can be defined inline in room yaml
Diffstat (limited to 'internal/game')
| -rw-r--r-- | internal/game/act.go | 8 | ||||
| -rw-r--r-- | internal/game/cmd_move.go | 13 | ||||
| -rw-r--r-- | internal/game/cmd_verbs.go | 2 | ||||
| -rw-r--r-- | internal/game/look_entities.go | 2 | ||||
| -rw-r--r-- | internal/game/look_target.go | 6 | ||||
| -rw-r--r-- | internal/game/object_def.go | 33 |
6 files changed, 54 insertions, 10 deletions
diff --git a/internal/game/act.go b/internal/game/act.go index 78f298d..654b65c 100644 --- a/internal/game/act.go +++ b/internal/game/act.go @@ -105,8 +105,12 @@ func (g *Game) startAction(sess *net.Session, verb, target string) { return } var err error - obj, err = g.ObjectStore.Load(chosen.DefID) - if err != nil || !obj.IsInteractable() { + obj, err = g.resolveObjectDef(p.RoomID, chosen.DefID) + if err != nil { + sess.WriteLine(fmt.Sprintf("There's nothing here to %s.", verb)) + return + } + if !obj.IsInteractable() { sess.WriteLine(fmt.Sprintf("You can't %s the %s.", verb, obj.Name)) return } diff --git a/internal/game/cmd_move.go b/internal/game/cmd_move.go index a1b492e..4bf227c 100644 --- a/internal/game/cmd_move.go +++ b/internal/game/cmd_move.go @@ -7,6 +7,7 @@ import ( "thehouseoficarus/internal/engine" "thehouseoficarus/internal/item" "thehouseoficarus/internal/net" + "thehouseoficarus/internal/object" "thehouseoficarus/internal/player" ) @@ -245,9 +246,15 @@ func (g *Game) seedRoomObjects(roomID int) { } g.World.EnsureObjectStates(roomID, ids) for _, obj := range room.Objects { - def, err := g.ObjectStore.Load(obj.ID) - if err != nil { - continue + var def *object.ObjectDef + if obj.Inline != nil { + def = obj.Inline + } else { + var err error + def, err = g.ObjectStore.Load(obj.ID) + if err != nil { + continue + } } g.World.SetObjName(roomID, obj.ID, def.Name) if len(def.Aliases) > 0 { diff --git a/internal/game/cmd_verbs.go b/internal/game/cmd_verbs.go index 2ba1a7e..f2c4a18 100644 --- a/internal/game/cmd_verbs.go +++ b/internal/game/cmd_verbs.go @@ -56,7 +56,7 @@ func (g *Game) executeVerbs(sess *net.Session, args []string, rawInput string) { var sectionGround []string for _, st := range g.World.AllObjInstances(p.RoomID) { - def, err := g.ObjectStore.Load(st.DefID) + def, err := g.resolveObjectDef(p.RoomID, st.DefID) if err != nil || def.Hidden { continue } diff --git a/internal/game/look_entities.go b/internal/game/look_entities.go index f6b58a1..def505a 100644 --- a/internal/game/look_entities.go +++ b/internal/game/look_entities.go @@ -88,7 +88,7 @@ func (g *Game) showRoomObjects(sess *net.Session, p *player.Player, room *world. } for _, objID := range order { count := grouped[objID] - def, err := g.ObjectStore.Load(objID) + def, err := g.resolveObjectDef(p.RoomID, objID) if err != nil { continue } diff --git a/internal/game/look_target.go b/internal/game/look_target.go index c5fb072..743844f 100644 --- a/internal/game/look_target.go +++ b/internal/game/look_target.go @@ -104,7 +104,7 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { byDef := map[string][]world.ObjState{} descByDef := map[string]string{} for _, ist := range rawInstances { - def, err := g.ObjectStore.Load(ist.DefID) + def, err := g.resolveObjectDef(p.RoomID, ist.DefID) if err != nil { continue } @@ -122,7 +122,7 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { if len(presentDefs) > 1 { sess.WriteLine("That's ambiguous, which one?") for _, defID := range presentDefs { - if def, err := g.ObjectStore.Load(defID); err == nil { + if def, err := g.resolveObjectDef(p.RoomID, defID); err == nil { sess.WriteLine(fmt.Sprintf(" %s", def.Name)) } } @@ -133,7 +133,7 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { instances := byDef[presentDefs[0]] objDescText := descByDef[presentDefs[0]] st := &instances[0] - def, _ := g.ObjectStore.Load(st.DefID) + def, _ := g.resolveObjectDef(p.RoomID, st.DefID) if st.DefID == "estate_directory" { g.lookEstateDirectory(sess) diff --git a/internal/game/object_def.go b/internal/game/object_def.go new file mode 100644 index 0000000..e27aeb0 --- /dev/null +++ b/internal/game/object_def.go @@ -0,0 +1,33 @@ +package game + +import "thehouseoficarus/internal/object" + +// resolveObjectDef returns the ObjectDef for a room object instance. File +// objects (the common case) resolve through the cached object store with no +// disk I/O on a hit, and a store miss is just a map lookup; only inline objects +// — which never live in the store — fall through to a freshly-read room, so +// they keep live-edit semantics without slowing file-object lookups. defID is +// the ObjState DefID (a normalized name for inline objects, a file id +// otherwise). +// +// Use this from display or generic-handling sites. Sites that look up a +// specific interactable behavior (gather/use-station/safespot/steal/etc.) may +// call ObjectStore.Load directly: inline objects are guaranteed non-interactable +// and simply fall through those sites' existing error guards. +func (g *Game) resolveObjectDef(roomID int, defID string) (*object.ObjectDef, error) { + def, err := g.ObjectStore.Load(defID) + if err == nil { + return def, nil + } + if room, rerr := g.World.LoadRoom(roomID); rerr == nil { + for i := range room.Objects { + ro := &room.Objects[i] + if ro.Inline != nil && ro.ID == defID { + d := *ro.Inline + d.ID = defID + return &d, nil + } + } + } + return nil, err +} |
