Preference an action during a scene

Here, by using ‘any’ before ‘distant elusive landmark’ in [any distant elusive landmark] you’ve made the token into a scope routine rather than a simple object filter- so the priority of both grammar lines is equal and they will be listed in source order.

If you simply omit ‘any’, no object out-of-scope will match the token, so the grammar line will only match distant objects (and therefore potentially be chosen ahead of room-navigating) if you place them in scope by some other means, e.g. by an ‘After deciding the scope’ rule.

Looking more closely at your code (oops, sorry!) I see that all your object grammar tokens are prefaced by ‘any’ so they will be listed (and therefore prioritised for parsing) in source-code order. So if by default you want landmark_navigating to be parsed in preference to room_navigating, you’ll need to have their ‘Understand…’ phrases defined in that order in your source.

As a couple of asides:

(i) ‘go’, ‘walk’ and ‘run’ are synonyms, which means that grammar lines that are identical other than the verb are redundant- any of these three synonyms beginning a typed command will match a grammar line defined with 'Understand “go…” ’

(ii) there is a typo in

	"go back/- to/around/near/by/-- [any room]",

there is a missing second hyphen in back/-, meaning the parser will literally try to match ‘back’ or ‘-’ as the second word of this grammar line, so in terms of what the player is likely to type,only ‘go back…’ will work

I’m afraid that doesn’t do it either. (See code below.) I think @severedhand is correct about the specificity determining the precedence. However, as I stated before, the following code seems to yield the desired behavior (regardless of reordering of grammar, action definitions, or the Sentinel tree and Limbo). I don’t see the behavior exhibited in the OP’s original transcript (preferring room to landmark navigating). This is probably due to some conditions created by code not yet posted.

For example, in the original transcript, looking in the Dark Woods yields extra lines, beginning with, “Wait, in the distance, you can just make out a white tree…” Whatever is in the code that causes that might be changing the priority of the nouns. (For example, moving the white tree in and out of the location or scope.)

Also:

I’m surprised this even compiles, since it’s missing an object. The DTPM rules are for disambiguating objects, not actions. It really only allows actions in the rule header to restrict when they are being checked, but they are just trying to determine the noun or second noun.

1 Like

Hmmm. mea culpa, it seems that not all scope routines are created equal with regard to precedence after all- although some are. I’m not sure if the full rules are anywhere documented, but some experimentation suggests at least that

(i) other things being equal, scope routines derived from tokens with a filtered noun take precedence over the rest (so [any open door] will take precedence over [any door], [any person], [any room] etc.)
(ii) scope routines derived from tokens which are a sub-kind of a kind appearing in an otherwise identical token already in the grammar table take precedence and are inserted into the grammar table immediately beforehand (so [any man] takes precedence over and is inserted immediately before [any person], which takes precedence over and is inserted immediately before [any thing])
(iii) Grammar lines with scope routines derived from tokens containing different kinds (that are not sub-kinds of each other) but that are otherwise identical are inserted in source code order.
(iv) as an (apparently unique) rule, the scope routine from [any object] has lower precedence than otherwise identical grammar lines containing [something] or [someone] and is inserted below these

So the reason that source code order makes no difference in this case is that [any distant elusive landmark] refers to a filtered noun, so its scope routine is given precedence over [any room] (which refers to an unfiltered noun) regardless of where they appear in source.

1 Like

This should work:

Don’t use “any room”; explicitly add rooms to scope and those landmarks that are visible. Have “go” correspond to the same action for both cases, but dispatch to landmark-navigating if the noun is a landmark. Or, if it works out, leave them the same action with a separate Carry out navigating to a room: and Carry out navigating to a landmark:.

A landmark is a kind of thing.

Navigating to is an action applying to one visible thing.
landmark-navigating to is an action applying to one visible thing.

Understand the command "go" as something new.
Understand "go to/-- [landmark]" as navigating to.
Understand "go to/-- [room]" as navigating to.

before navigating to a landmark, instead try landmark-navigating to the noun.

The Tree House is a room.
The Shattered Tree is a landmark.

The Bridge is a room.
The Rock is a landmark.

After deciding the scope of the player:
  repeat with r running through rooms begin;
    place r in scope;
  end repeat;
  place the shattered tree in scope;

carry out navigating to: say "navigate to [noun].".
carry out landmark-navigating to: say "landmark-navigate to [noun].".

Possibly you’ll want a Does the player mean navigating to a landmark: it is likely. but I think just listing the landmark-case’s Understand line first will take care of it.

1 Like

Okay, here’s a more functional version that demonstrates the challenge I’m having:

Part - Room_Navigating

A person can be discouraged_from_compass_navigating or not discouraged_from_compass_navigating.

Room_navigating is an action applying to one thing.
Understand
	"go back/- to/around/near/by/-- [any room]",
	"return to [any room]",
	"walk to/-- [any room]",
	"run to/-- [any room]",
	"follow [any room]" 
	as room_navigating.

Check room_navigating:
	if the noun is the location, say "Well, happily you're already here." instead;

Carry out room_navigating:
	let initial location be the location;
	let the destination be the noun;
	if the initial location is the destination,
		say "." instead;
	let heading be the best route from the initial location to the destination;
	say "(DEBUG room_navigating: heading toward [noun] is [heading])[line break]";
	if heading is nothing:
		say cant_find_that instead;
	else:
		now player is not discouraged_from_compass_navigating;
		try going heading.

Part - Elusive_Landmarks and Landmark_navigating

An elusive_landmark is a kind of thing.

The_distance is a container.
The_distance is in Limbo.
[ Definition: an elusive_landmark is distant if it is in the_distance. ]

landmark_navigating is an action applying to one visible thing.
Understand
	"go to/near/by/-- [any elusive_landmark]",
	"walk to/near/by/-- [any elusive_landmark]",
	"run to/near/by/-- [any elusive_landmark]",
	"landmark_navigate [any elusive_landmark]"
	as landmark_navigating.

Check landmark_navigating:
	if the noun is touchable:
		say "Well, that's right here." instead;
	if the noun is not in the_distance:
		say cant_find_that instead;

To say cant_find_that:
	say "You're no longer sure how to get there.";

Carry out landmark_navigating:
	say "You head toward the [noun].";
	move_within_dark_woods;
    try looking.

To move_within_dark_woods:
    let distant_thing be a random elusive_landmark in the_distance;
    let next_thing be a random elusive_landmark in Limbo;
    let past_thing be a random elusive_landmark in location;
    now distant_thing is in location;
    now next_thing is in the_distance;
    now past_thing is in Limbo;

The can't reach inside rooms rule does nothing if landmark_navigating.

The can't reach inside rooms rule response (A) is "You can't get there from here."

Part - Rooms & Stuff

Dark Woods is a room.
"[dark_woods_desc].".

To say dark_woods_desc:
    let distant_thing be a random elusive_landmark in the_distance;
    say "It's dark and woody. You see [the distant_thing] in the distance";

The white tree is an elusive_landmark in The_distance.
Understand "tree" as white tree.

The madrone tree is an elusive_landmark in Dark Woods.
The tree stump is an elusive_landmark in Limbo.

Top of the Tree is a room [west of Dark Woods].
Understand "tree" as Top of the Tree.

And running it:

>look
[looking]
Dark Woods
It’s dark and woody. You see the white tree in the distance.
You can see a madrone tree here.
[looking - succeeded]

>go to white tree
[landmark_navigating the white tree]
You head toward the white tree.
[(1) looking]
Dark Woods
It’s dark and woody. You see the tree stump in the distance.
You can see a white tree here.
[(1) looking - succeeded]
[landmark_navigating the white tree - succeeded]

>go to white tree
[landmark_navigating the white tree]
Well, that’s right here.
[landmark_navigating the white tree - succeeded]

>go to tree
[room_navigating Top of the Tree]
(DEBUG room_navigating: heading toward Top of the Tree is nothing)
You’re no longer sure how to get there.
[room_navigating Top of the Tree - succeeded]

You can see that rather than landmark_navigating, it is prioritizing room_navigating with the ambiguous target “tree”.

And as Peter queried, does the order in the source determine which it privileges: I reversed the position within the source of “Part - Room_Navigating” and “Part - Landmark_Navigating,” and voila! It privileges Landmark_Navigating.

Though frustratingly, “go tree” still privileges “room_navigating Top of the Sentinel Tree” rather than “white tree”.

>go to tree
[Rule “Response Assistant reset responses list rule” applies.]
[Rule “ignore beta-comments rule” applies.]
[Rule “new_blank_line_replacement rule” applies.]
[Rule “declare everything initially unmentioned rule” applies.]
[room_navigating Top of the Sentinel Tree]

OK, here is your grammar table for the synonyms ‘Go’ ‘Run’ ‘Walk’:

Verb 'go' 'walk' 'run' 
	* -> Go 
	*  noun=Noun_Filter1 -> Go 
	* noun -> Enter 
	* SlashGPR1  scope=Scope_Filter1 -> A_room_navigating 
	* SlashGPR2  scope=Scope_Filter2 -> A_room_navigating 
	* SlashGPR3  scope=Scope_Filter3 -> A_landmark_navigating 
	* SlashGPR4  scope=Scope_Filter4 -> A_landmark_navigating 
	* SlashGPR5  scope=Scope_Filter5 -> A_landmark_navigating 
	* 'into' / 'in' / 'inside' / 'through' noun -> Enter 
	* 'back' / '-//' SlashGPR6  scope=Scope_Filter6 -> A_room_navigating;

This illustrates another rule of grammar line precedence, which appears to trump others already discussed- before sorting on token precedence ( and then subsequently on whether or not a condition is attached, such as ‘when the player is in the Lab’) grammar lines are arranged in ascending order of the number of leading prepositions/alternate prepositions/prepositional parsing routines (SlashGPRx) after the verb.

so:

    "walk to/-- [any room]" (1 prepositional parsing routine, matching 'to/--') and
    "run to/-- [any room]" (1 prepositional parsing routine matching 'to/--')

come before

     "go back/- to/around/near/by/-- [any room] (1 alternate preposition matching 'back/-' (note persisting typo so this is an alternative between 'back' and '-' ( '-//' is arcane I6 code for 'the single character '-') rather than a prepositional parsing routine matching 'back/--') and 1 prepositional parsing routine, matching 'to/around/near/by/--' - so total of 2 (possible) leading prepositions

Note how

 'into' / 'in' / 'inside' / 'through' noun -> Enter 

which has just 1 leading alternate preposition also takes precedence despite having a low-precedence token (noun).

Note that this is the reverse of the example given in WI 17.22 for building new tokens rather than a grammar table. When building a new token possible matches are considered in descending order of number of possible prepositions (the example given being that ‘on top of’ (3 prepositions) comes before ‘on/in/inside’ (1 alternate preposition)).

I think the upshot of all this is that trying to manipulate the precedence of grammar lines to achieve specific game effects is complicated, fiddly and poorly documented/understood, so its best not to rely on it- at least in part because the precedence rules the compiler uses may change without warning or notice.

I think the correct approach must be to not have two separate actions here, but to channel all your grammar lines into one action, and then once that action has left the rarified and arcane workings of the parser and emerged as an action, use Before/Instead/Check/Carry Out/After/Report rules, whose workings are transparent and where you have more control, to separate out and channel your action how you want- into other actions if you like, e.g.

Before going an elusive landmark:
	try landmark_navigating the noun instead.

Note that landmark_navigating can be an ‘untypable’ action with no ‘Understand’ phrases of its own, just existing to receive redirections like the one above.

2 Likes

How would that action look? To minimize the effects on other actions (like swimming or jumping) which also use some of the same verbs, I’d prefer it only matched an elusive_landmark or a room, but

Room_or_landmark_navigating is an action applying to one thing.
Understand
	"go back/-- to/near/by/-- [any room or elusive_landmark]",
	"walk back/-- to/near/by/-- [any room or elusive_landmark]",
	"run back/-- to/near/by/-- [any room or elusive_landmark]",
	"return to/near/by/-- [any room or elusive_landmark]",
	"follow [any room or elusive_landmark]" 
	as room_or_landmark_navigating.

is not legal syntax.

well, it’d look like my example above where I took the same tack that Dr. Bates advised, right down to noting that it could be one action or two.

1 Like

As I understand your essential question, it’s how to get “tree” interpreted by default as the white tree during this scene, but in general to have a room such as Top of the Sentinel Tree preferred.

If that’s the case, then having separate landmark_navigating and room_navigating actions is inherently part of the problem. No matter how you arrange things, the grammar line for one of the actions will come before that of the other. (The same, unfortunately, applies to different specialized grammar lines for a single action.)

Your original approach to use DTPM rules can work only if the parser is trying to decide which object is the noun of a single action, and the rules are checked only while the player’s command is being evaluated to see whether it can be interpreted as validly requesting that action. It is important to understand that DTPM can only differentiate between objects that are in scope because they match to a word or words used in the player’s command. It can’t add things to scope, it can only give a preference (or dispreference) for things already decided to be in scope. [EDIT: Reading back over this, I see that I neglected to clarify an important point here: What is being evaluated when the DTPM rules are checked is a single grammar line. Thus, all of the objects to be weighted with respect to each other by DTPM rules must have been brought into scope at the same time.]

Although you can have one action decide to invoke another, this is not strictly necessary. The same action can execute different logic based on the nature of the noun and/or second noun. All you need to do is structure the rule preambles appropriately for check, carry out and other rules.

The following reworks things a bit in light of the above. Note that I reinserted some DTPM rules that depend on the state of the discouraged_from_compass_navigating property for the player. The conditional logic can be modified as you like to make use of scenes or whatever. The test me sequence shows how the command >GO TO TREE is interpreted based on the current situation.

Lost in the Woods
"Lost in the Woods"

Part - Room_Navigating

A person can be discouraged_from_compass_navigating or not discouraged_from_compass_navigating.

Navigating is an action applying to one object.

Definition: an object is navigable if (it is a room and it is not the location) or (it is an elusive_landmark and it is not in the location).

Understand
	"go back/- to/around/near/by/-- [any navigable object]",
	"go to/near/by/-- [any navigable object]",
	"return to [any navigable object]",
	"walk to/near/by/-- [any navigable object]",
	"walk to/-- [any navigable object]",
	"run to/near/by/-- [any navigable object]",
	"run to/-- [any navigable object]",
	"follow [any navigable object]"
	as navigating.

Does the player mean navigating a room when the player is discouraged_from_compass_navigating:
	it is unlikely.

Does the player mean navigating a distant elusive_landmark when the player is discouraged_from_compass_navigating:
	it is likely.


After waving hands:
	if the player is discouraged_from_compass_navigating:
		now the player is not discouraged_from_compass_navigating;
	otherwise:
		now the player is discouraged_from_compass_navigating;
	showme whether or not the player is discouraged_from_compass_navigating.

Check navigating a room:
	if the noun is the location, say "Well, happily you're already here." instead;

Carry out navigating a room:
	let initial location be the location;
	let the destination be the noun;
	if the initial location is the destination,
		say "." instead;
	let heading be the best route from the initial location to the destination;
	say "(DEBUG room_navigating: heading toward [noun] is [heading])[line break]";
	if heading is nothing:
		say cant_find_that instead;
	else:
		now player is not discouraged_from_compass_navigating;
		try going heading.

Part - Elusive_Landmarks and Landmark_navigating

An elusive_landmark is a kind of thing.

The_distance is a container.
The_distance is in Limbo.
Definition: an elusive_landmark is distant if it is in the_distance.

Check navigating an elusive_landmark:
	if the noun is touchable:
		say "Well, that's right here." instead;
	if the noun is not in the_distance:
		say cant_find_that instead;

To say cant_find_that:
	say "You're no longer sure how to get there.";

Carry out navigating an elusive_landmark:
	say "You head toward the [noun].";
	move_within_dark_woods;
	try looking.

To move_within_dark_woods:
	let distant_thing be a random elusive_landmark in the_distance;
	let next_thing be a random elusive_landmark in Limbo;
	let past_thing be a random elusive_landmark in location;
	now distant_thing is in location;
	now next_thing is in the_distance;
	now past_thing is in Limbo;

The can't reach inside rooms rule does nothing when navigating.

The can't reach inside rooms rule response (A) is "You can't get there from here."

Part - Rooms & Stuff

Dark Woods is a room.
"[dark_woods_desc].".

To say dark_woods_desc:
	let distant_thing be a random elusive_landmark in the_distance;
	say "It's dark and woody. You see [the distant_thing] in the distance";

The white tree is an elusive_landmark in The_distance.
Understand "tree" as white tree.

The madrone tree is an elusive_landmark in Dark Woods.
The tree stump is an elusive_landmark in Limbo.

Top of the Tree is a room [west of Dark Woods].
Understand "tree" as Top of the Tree.

Test me with "go to tree / wave / go to tree / g".
4 Likes
Room_or_landmark_navigating is an action applying to one thing.
Understand
	"go back/-- to/near/by/-- [any room],
	"go back/-- to/near/by/-- [any elusive_landmark],
	etc.
	etc.
	as room_or_landmark_navigating.

You could have all of these go through the Going action without having a new Room_or_landmark_navigating action and then just start processing at the Before stage (as in the example I gave)

1 Like

True, but you can make grammar lines conditional so that they swap in and out of parser consideration, e.g. ‘Understand “blow up [something]” as detonating when the player is in the mine. Understand “blow up [something]” as inflating when the player is in the balloon factory.’

Although as already stated, I think the whole approach of manipulating grammar line precedence/consideration like this is probably flawed and best avoided.

Otis’ "[any navigable object]" above is a clever way to express allowed things in one grammar token, and it obviates the need for putting things in scope manually as in my example.

I think the easiest way to handle this would be to do something like this. (Sorry, I don’t have time right now to put a properly functional version together, or indeed to test whether or not this is nonsense.)

Understand [COMMANDS] as landmark_navigating when [SCENE] is happening.
Understand [COMMANDS] as room_navigating.
Understand [COMMANDS] as landmark_navigating.

I think that should lead to the grammar lines for landmark_navigating taking priority during SCENE, but not at other times.

Sadly not, unless all the [COMMANDS] are identical for room_navigating and landmark_navigating, since the presence of a condition has the lowest priority of all apart from source text order when the compiler is ordering grammar lines.

There are hacky ways of forcing priority on the compiler, but as suggested earlier in this thread, IMHO this whole approach really isn’t a good way to try to implement game mechanics.

The compiler orders things the way it does to optimise sensible parser responses to a wide range of input, which is probably at odds with interfering to drive game mechanics.

As is generally the case with Inform, if you’re fighting the system you’re probably missing a better way of achieving your goal.

I’m experimenting with combining room_navigating and landmark_navigating. Then since this added more and longer grammar lines, climbing_something took precedence and had to be combined as well. So the strategy of one navigation action to rule them all ends up having tons of grammar lines and tons of conditions (though Otis’ Carry out navigating a room could help).

Navigating is an action applying to one thing.
Understand
	"go back/-- to/near/by/-- [any reachable room]",
	"go back/-- to/near/by/-- [any elusive_landmark]",
	"walk back/-- to/near/by/-- [any reachable room]",
	"walk back/-- to/near/by/-- [any elusive_landmark]",
	"run back/-- to/near/by/-- [any reachable room]",
	"run back/-- to/near/by/-- [any elusive_landmark]",
	"return to/near/by/-- [any reachable room]",
	"return to/near/by/-- [any elusive_landmark]",
	"follow [any reachable room]",
	"follow [any elusive_landmark]",
	"climb on/onto/in/into/over/through/under/-- [visible thing]", 
	"climb up in/into/on/onto/-- [visible thing]",
	"hop on/onto/in/into/over/through/under/-- [visible thing]", 
	"hop up in/into/on/onto/-- [visible thing]",
	"scale on/onto/in/into/over/through/under/--  [visible thing]", 
	"scale up in/into/on/onto/-- [visible thing]",
	"jump on/onto/in/into/over/through/under/-- [visible thing]", 
	"jump up in/into/on/onto/-- [visible thing]",
	"cross up/on/onto/in/into/over/through/under/-- [visible thing]",
	"go up/on/onto/in/into/over/through/under/to/-- [visible thing]"
	as navigating.

This approach violates my sense of programming elegance, and it might be hard to manage. This is a possibility, but is it a good idea? Is it the most elegant, modular, extensible approach? Originally I wanted to find a solution to my small problem without digging in deeply to these already working solutions, but now that I have, I’m willing to consider what a good approach would be.

I’ve just clocked that there is an inbuilt debugging verb for looking at grammar lines (of course there is!)

showverb go

does the trick!

1 Like

I’m not sure what you’re gaining by combining actions together that don’t share verbs (and therefore can’t be ambiguous to the parser)?

As a separate issue, it’s probably not good style to introduce constraints to your grammar tokens (such as [visible thing] instead of [thing]) unless there really is no other way of achieving what you want.

General rule of thumb is to keep things as broad as possible at parser level so that any vaguely sensible player input is accepted by the parser, then sort out details in action-processing where you have complete and transparent control of logic and responses.

The parser not matching [visible thing] gets you the default blank ‘You can’t see any such thing’ response, whereas ‘Before navigating something invisible:’ allows you to take full control.

As a further aside, the differences between [thing] (a thing in scope for the actor) and [visible thing] (a thing visible to the player) are subtle, unless the actor is not the player… (see here)

EDIT PS The differences between [visible thing] as a grammar token (as in 'Understand “destroy [visible thing]” as destroying) and ‘visible thing’ in an action definition (as in ‘Destroying is an action applying to one visible thing’) are not so subtle. The former means ‘a thing the player can see’ (thing here having the sense of ‘an instance of the thing kind, or of one of its sub-kinds, e.g. people or women or doors or containers)’, the latter means ‘any object in the universe, including rooms, regions, directions and objects out-of-play, and (confusingly) whether the player or anyone else can see them or not’.

Christ, that would have been good to know. I recently discovered scope. Where are these documented?