[The Default Behavior of DOWN and] Program Entry Point and Commanding NPCs

I have been having two problems with the following code:

(intro)
    (try [look])

(current player #player)
(#player is #in #land)
    
#land

(room *)
(singleton *)
(name *) land
(look *)
    You are on land.
(from * go #up to #air)

#air

(room *)
(singleton *)
(name *) air
(look *)
    You are high in the sky.
    
#balloon-animal

(item *)
(name *) balloon animal
(animate *)
(actor supporter *)
(* is #in #land)

(perform [tell * to go $Dir])
    (* is in room $Room)
    (from $Room go $Dir to room $)
    (let * go $Dir)

And here is a transcript of a session:

Land
You are on land.

> get on balloon
You get onto the balloon animal.

> balloon, go up
The balloon animal disappears up.

> look
Land (on the balloon animal)
You are high in the sky.

I was not expecting to see “Land” with the description of the air when the PC is in the air. (If I go up without the balloon animal’s assistance, I see “Air” as expected.)

The other problem is that when I compile the code, I get this:

Warning: A query is made to '(program entry point)', but there is no matching rule definition.

And if I run it in a web browser, I see nothing, not even a command prompt. And the problem is not just with my code. When I compile the code of the minimal story found in The Dialog Manual, I encounter the same problem. This is a new development; such code used to compile into a playable game without complaint.

1 Like

The only thing I can think of for this is, make sure you’re including the latest version of the standard library on the command line? You’ll get that error if the library isn’t included (since the library defines (program entry point) for you).

1 Like

Nice catch! I had somehow left the library off the command line.

That resolves the second problem. On the other hand, the first problem persists.

1 Like

Thanks for pointing this out! The library caches certain properties, such as the current room of the player, rather than recomputing them every time they’re needed. But here, the cache was not updated properly when something changed.

I’ll have to fix the library so it detects this case. In the meantime, after you (let * go $Dir), you can (update environment around player).

Unrelated suggestion: If you mark the balloon animal as a (vehicle $), then GO UP (or U) has the player ride the balloon up, instead of first getting off it.

2 Likes

Thank you for another quick response! Updating the vehicle around the player is a great stopgap solution.

I am sorry to say it seems there is another problem in the library. After making only the changes you recommended I found that the library understands “d” to mean “exit (the vehicle)” rather than “steer the vehicle down”, as seen in this transcript:

Land
You are on land.

> get on balloon
You get onto the balloon animal.

> u
You drive the balloon animal up.

Air (on the balloon animal)
You are high in the sky.

You see a balloon animal here.

> d
You get off the balloon animal.

> look
Air
You are high in the sky.

You see a balloon animal here.

> d
You climb down.

Land
You are on land.

There are certainly situations in which this behavior would be preferred, but I am not sure it should be the default.

1 Like

Very interesting point! I’ve been mulling over this for a while now, and would appreciate a wider discussion.

This is how it works now: If the player is on a supporter or in a container, then the [leave] action (understood from e.g. LEAVE, EXIT, or GET OFF) will move them to the enclosing object, typically a room. Meanwhile, directions such as UP, DOWN, or OUT are understood as the [go $Dir] action.

The library redirects [go #out] to [leave] if the player is in a container. This makes sense because if you GET IN a cardboard box, then you expect GET OUT (or just OUT) to revert that.

The library redirects [go #down] to [leave] if the player is on a supporter, for similar reasons: If you GET UP ON TABLE, then you expect to be able to GO DOWN again.

And there is even a redirection from [go #up] to [leave] if the player is in or on a (seat $), because after you GET ON BED or GET IN ARMCHAIR, you may want to GET UP again.

All of these redirections behave in the same way if the supporter or container is a vehicle. One possible way forward is to change the rules to only apply to non-vehicles. And yet, after you GET IN CAR, wouldn’t you want to GET OUT? After you MOUNT HORSE, wouldn’t you want to GET DOWN?

Another option is to redirect only when there is no obvious exit in the given direction. In that case, if you are sitting in the car and type GET OUT, then you will drive out of the garage, but typing the same thing when the car is on the driveway will make you leave the vehicle.

And the latter behaviour might only make sense for vehicles. When GET UP ON BALLOON ANIMAL is followed by GET DOWN, the latter is probably an instruction to drive the vehicle. Whereas if you climb down into a submarine and then GET INTO BED, then GET UP should perhaps take you out of the bed, but not out of the submarine. And should a subsequent UP drive the submarine?

Yet another option is to ask for clarification: Did you want to 1. get off the balloon animal, or 2. go down. But that could easily get annoying in the long run.

It seems pretty clear that these decisions should be under the story author’s control, somehow. But what would be a sensible default?

Comments, suggestions?

1 Like

The more I think about this, the more I think the default behavior should remain the same. The player is going to appreciate as many synonyms as possible, and there are few modern IF works that require the player to use a vehicle and require them to move vertically, much less do so at the same time. It was easy for me to catch the behavior of DOWN I had not anticipated, but if my work required no vertical movement, even extensive beta testing might not have suggested I should make DOWN a synonym of GET OUT.

To my mind the one strike against the current default is that it will require some authors to override the behavior of the library. I appreciate that in Dialog, the library is not a “black box” (as you once put it, Linus) as it is in other systems. Even so, overriding library behavior can be intimidating for a new author. (I say this as someone who has published an IF work written using TADS 3 and adv3lite and is now learning to write using Dialog.)

Of the three options, I would be the least likely to keep disambiguation as the default. But of course I cannot speak for others.

1 Like

You could also print a parenthetical message in ambiguous cases, or only the first time.

>OUT
You drive the car out of the garage.
(If you wanted to get out of the car, try “exit”.)

3 Likes

I think I’ve figured out a good default behaviour now. The problem with the old solution is that it first resolves the ambiguity to a standard action, and then potentially redirects that to another standard action, after loosing vital information about how the command was worded. That makes it difficult for the story author to override the default behaviour in a clean way.

It’s better to deal with the ambiguity at the parser level. The idea is that a direction like DOWN will always be understood as referring to [go #down], but sometimes also as [leave $]— namely if the player is on a supporter.

Since the command can be parsed in two ways, the likelihood of each interpretation is considered. If there is no exit down, then [go #down] is deemed unlikely, and disregarded. So the player can only be asked a disambiguating question on those rare occasions where e.g. the player is on a supporter and there is also an exit down, or inside a container when there is also an exit out. And here’s the kicker: The story author can easily resolve those ambiguities by tweaking the likelihood of actions, taking the full story-specific situation into account. Thus:

(unlikely [leave #balloon-animal])
        (current room #air)

or:

(unlikely [leave #submarine #up])
        (#player is #on #bunk)

Again, this only affects ambiguous cases. If the player on the balloon animal types GET OFF, or LEAVE ANIMAL, it doesn’t matter that the action is considered unlikely, because there is no other way to interpret it.

3 Likes

I love this solution! Thank you, once again, for all your hard work, Linus!

1 Like

Fixed in standard library 0.40.

2 Likes