A more limited (just)

Having been reminded of The Impossible Bottle’s hyperlink interface recently, I’m messing around with something like it. At its heart, this goes like this:

(late on every tick)
	(show inline status bar)

(show inline status bar)
	(hyperlinks enabled)
	(inline status bar @inlinebar) {
		(exhaust) *(inline status element)
	}

(inline status element) %% First, the obvious exits
	(link) {look}
	(current room $Room)
	(exhaust) {
		*(from $Room go $Dir to $Target)
		(direction $Dir)
		(if) (door $Target) (or) (room $Target) (then)
			 - (link) (name $Dir)
		(endif)
	}

(global variable (last named object $)) %% (notice player's $) and (forget pronouns out of scope) have been modified to set and clear this respectively
(inline status element) %% Then, the most recently named object
	(last named object $Obj)
	\| (the $Obj)
	(exhaust) *(link viable actions for $Obj)

And then (link viable actions for $Obj) has a bunch of different rules that offer different actions based on the traits of $Obj. If it’s an item that’s not held, for example, it’ll suggest “get”, if it’s an item that is held, it’ll suggest “drop”, if it’s openable and closed, it’ll suggest “open”, and so on.

The problem is, I want to suggest “give” specifically if there’s another person visible. But figuring out whether there’s another person visible requires a multi-query:

(link viable actions for $Obj)
	(held $Obj)
	(current room $Room)
	(current player $Player)
	*($Other has ancestor $Room)
	(animate $Other)
	~($Other = $Player)
	(just) (link action [give $] with $Obj)

But since (link viable actions for $) has been queried in an (exhaust) statement, this multi-query backtracks over all the possible other people and prints the “give” suggestion for each one. I can cut this off with (just), but that also ends the (exhaust), so no more viable actions will be shown!

What I need is a way to cut off the inner multi-query without cutting off the outer one. The best solution I can think of at the moment is to use a collect-statement and make a list of the other people in the room, then check if that’s non-empty, but that feels distinctly inelegant compared to the fundamental system of queries and choice points.

Is there a better way to do this?

In situations like this, the general solution is to move the part that you want to limit (just) part to into another rule. Turn this:

	(held $Obj)
	(current room $Room)
	(current player $Player)
	*($Other has ancestor $Room)
	(animate $Other)
	~($Other = $Player)
	(just) (link action [give $] with $Obj)

into

(link viable actions for $Obj)
	(held $Obj)
	(current room $Room)
	(current player $Player)
	($Room has $ other than $Player)
	(link action [give $] with $Obj)

($Room has $Person other than $Player)
	*($Person has ancestor $Room)
	(animate $Person)
	~($Person = $Player)

Since ($Room has $ other than $Player) is called as simple query, its CP will get deleted upon return and you don’t even need to use (just); therefore it won’t get called backtracked into multiple times by (exhaust) *(link viable actions for $Obj).

Edit: Typo (not in code).
Edit 2: Bah, still using call instead of backtrack, force of habit from function/subroutine based languages.

1 Like