diff options
| author | historia <[not public]> | 2026-06-24 20:58:25 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-06-24 20:58:25 -0400 |
| commit | 9d4b799db4868bcab291b83599ff088763cd4ed6 (patch) | |
| tree | 252f0fcc779acf35243983d643d6399ee2e0cd0b /internal/game/cmd_look.go | |
| parent | d25638d98fe63efdeab570ef77e6a6a97f2d7a60 (diff) | |
| download | thehouseoficarus-9d4b799db4868bcab291b83599ff088763cd4ed6.tar.gz | |
feat: new type of non-violent 'combat': work
Diffstat (limited to 'internal/game/cmd_look.go')
| -rw-r--r-- | internal/game/cmd_look.go | 92 |
1 files changed, 86 insertions, 6 deletions
diff --git a/internal/game/cmd_look.go b/internal/game/cmd_look.go index 98d48fd..266cd15 100644 --- a/internal/game/cmd_look.go +++ b/internal/game/cmd_look.go @@ -62,7 +62,7 @@ func (g *Game) showRoomDescription(sess *net.Session, p *player.Player, room *wo if descWidth <= 0 { descWidth = 70 } - rawLines := wrapText(room.Description, descWidth) + rawLines := wrapText(g.roomDescription(sess, room), descWidth) mode := g.colorMode(sess) roomDescSpec := g.resolveColor(sess, "room_desc") lines := make([]string, len(rawLines)) @@ -72,6 +72,35 @@ func (g *Game) showRoomDescription(sess *net.Session, p *player.Player, room *wo return lines } +// roomDescription resolves the room's effective description for this player, +// picking the first conditional variant whose condition passes, else the base +// Description. +func (g *Game) roomDescription(sess *net.Session, room *world.Room) string { + for _, d := range room.Descriptions { + if d.Condition == nil || g.checkCondition(sess, d.Condition) { + return d.Text + } + } + return room.Description +} + +// resolveObjDesc resolves the description an object shows to this player. For an +// object with conditional Descriptions, the first variant whose condition +// passes wins; if none pass the object is reported as not present (false), so +// look falls through as if it were not there. Objects without Descriptions use +// their plain Description and are always present. +func (g *Game) resolveObjDesc(sess *net.Session, def *object.ObjectDef) (string, bool) { + if len(def.Descriptions) == 0 { + return def.Description, true + } + for _, d := range def.Descriptions { + if d.Condition == nil || g.checkCondition(sess, d.Condition) { + return d.Text, true + } + } + return "", false +} + func (g *Game) showRoomMobs(sess *net.Session, p *player.Player, room *world.Room) []string { mobs := g.MobStore.MobsInRoom(p.RoomID) if len(mobs) == 0 { @@ -91,7 +120,15 @@ func (g *Game) showRoomMobs(sess *net.Session, p *player.Player, room *world.Roo for _, m := range mobs { hp := "" if m.HP < m.MaxHP { - hp = fmt.Sprintf(" [%s/%dhp]", color.Render(g.colorMode(sess), color.Parse("167"), fmt.Sprint(m.HP)), m.MaxHP) + if m.IsTask() { + pct := 0 + if m.MaxHP > 0 { + pct = (m.MaxHP - m.HP) * 100 / m.MaxHP + } + hp = fmt.Sprintf(" [%d%% complete]", pct) + } else { + hp = fmt.Sprintf(" [%s/%dhp]", color.Render(g.colorMode(sess), color.Parse("167"), fmt.Sprint(m.HP)), m.MaxHP) + } } var desc string if combat.IsMobInCombat(m.InstanceID) { @@ -467,6 +504,14 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { sess.WriteLine("You can't see anything that way.") return } + if exitDef.Condition != nil && !g.checkCondition(sess, exitDef.Condition) { + msg := exitDef.BlockedMessage + if msg == "" { + msg = fmt.Sprintf("The way %s is blocked.", exitDir) + } + sess.WriteLine(msg) + return + } g.World.SeedGroundItems(exitDef.Room) g.seedRoomMobs(exitDef.Room) origRoom := p.RoomID @@ -521,8 +566,43 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { return } - instances := g.World.FindObjInstances(p.RoomID, lower) - if len(instances) > 0 { + rawInstances := g.World.FindObjInstances(p.RoomID, lower) + + // Group matched object instances by definition, keeping only those visible + // to this player (an object whose conditional descriptions all fail is + // absent). If more than one distinct object matches, disambiguate. + var presentDefs []string + byDef := map[string][]world.ObjState{} + descByDef := map[string]string{} + for _, ist := range rawInstances { + def, err := g.ObjectStore.Load(ist.DefID) + if err != nil { + continue + } + text, present := g.resolveObjDesc(sess, def) + if !present { + continue + } + if _, seen := byDef[ist.DefID]; !seen { + presentDefs = append(presentDefs, ist.DefID) + descByDef[ist.DefID] = text + } + byDef[ist.DefID] = append(byDef[ist.DefID], ist) + } + + if len(presentDefs) > 1 { + sess.WriteLine("That's ambiguous, which one?") + for _, defID := range presentDefs { + if def, err := g.ObjectStore.Load(defID); err == nil { + sess.WriteLine(fmt.Sprintf(" %s", def.Name)) + } + } + return + } + + if len(presentDefs) == 1 { + instances := byDef[presentDefs[0]] + objDescText := descByDef[presentDefs[0]] st := &instances[0] def, _ := g.ObjectStore.Load(st.DefID) @@ -538,8 +618,8 @@ func (g *Game) doLookTarget(sess *net.Session, input string) { sess.WriteLine(def.Name) } - if def.Description != "" && !strings.Contains(def.Description, "{quality}") { - sess.WriteLine(fmt.Sprintf(" %s", def.Description)) + if objDescText != "" && !strings.Contains(objDescText, "{quality}") { + sess.WriteLine(fmt.Sprintf(" %s", objDescText)) } if def.Safespot != nil { |
