package game import ( "thehouseoficarus/internal/net" "thehouseoficarus/internal/world" ) // exitDisplay summarizes how an exit appears to a player: whether it is listed // at all (and traversable by the map BFS / walk pathfinder), whether movement // is refused (and the look listing should tag it "(blocked)"), and whether the // listing should tag it "(HIDDEN)". // // It is the single source of truth shared by the look listing, the standalone // `exits` command, `look `, movement, the map connector state, the // `verbs` command, and the walk pathfinder — replacing the per-callsite inline // checks that previously disagreed (e.g. gods saw a "(blocked)" tag in look // even though they can traverse and the map renders the link open). // // Semantics: // - Hidden exit: visible only once discovered (gods always discover). When // visible it is tagged "(HIDDEN)". A nil player (background render) never // discovers, so hidden exits are absent. // - God mode: exits are visible and never blocked (matches map rendering). // - always_blocked: absolute — blocks movement/listing/map regardless of any // condition. The condition is NOT evaluated when always_blocked is set. // - condition: blocks when present and failing for this player. type exitDisplay struct { Visible bool Blocked bool TagHidden bool } func (g *Game) exitDisplayState(sess *net.Session, roomID int, dir world.ExitDir, exit world.ExitDef) exitDisplay { var ed exitDisplay p := sessPlayer(sess) if exit.Hidden { // exitDiscovered already returns true for gods; nil player never discovers. if p != nil && g.exitDiscovered(p, roomID, dir) { ed.Visible = true ed.TagHidden = true } return ed } ed.Visible = true if p == nil || p.GodMode { return ed } if exit.AlwaysBlocked { ed.Blocked = true return ed } if exit.Condition != nil && !g.checkCondition(sess, exit.Condition) { ed.Blocked = true } return ed }