aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_look.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-24 20:58:25 -0400
committerhistoria <[not public]>2026-06-24 20:58:25 -0400
commit9d4b799db4868bcab291b83599ff088763cd4ed6 (patch)
tree252f0fcc779acf35243983d643d6399ee2e0cd0b /internal/game/cmd_look.go
parentd25638d98fe63efdeab570ef77e6a6a97f2d7a60 (diff)
downloadthehouseoficarus-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.go92
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 {