Refusing and Ticking in Parser Fiction

I believe it was Hanon O who first observed that what separates parser fiction from choice fiction is that the former can refuse player input. I have a problem related to that refusal.

Here’s the problem in a nutshell: I am in the early planning phases of a work with a Jewish protagonist and a Jewish setting. There are some actions that a player might try but would be unthinkable for a Jewish protagonist. To give a concise example (not necessarily the most representative example), a player might try to knock a siddur (prayer book) onto the floor; however, even a secular Jewish protagonist isn’t ordinarily going to contemplate treating an object their fellow Jews consider holy with that level of irreverence. How do I handle these cases?

I’ll elaborate on the problem using Dialog as an example, even though it is not a Dialog-specific problem, because Dialog is in all likelihood the system I’ll use to create my work. Assuming I’ll use the standard library, there are three points at which I could report that the action is something that the protagonist cannot or will not do:

  1. If the player is denied at the refuse step, there will be no tick (i.e. time will not be moved forward by one discrete unit), and no further steps will be taken.
  2. If the player is denied at the prevent step, there will be a tick, and no further steps will be taken.
  3. Finally, sometimes it makes sense to deny the player during the perform step, at which point it is the norm for the author to tell the story that there should be a tick.

Linus writes this:

The reason for having two different rules (refuse and prevent), is that it’s generally a good idea to check for reachability first. The action-specific prevent-rules are then free to phrase their failure messages in a way that presupposes reachability (e.g. “the door is locked”, which you wouldn’t know if you couldn’t reach it).

The first sentence suggests that we should let the (prevent $) predicate deny the player, but the second sentence explains why the usual reason doesn’t apply: Going back to the siddur example, the protagonist will never get a response that says, “You can’t do that!” because they would never try to begin with. It seems to me that nothing could be more unreachable than an object the protagonist would never reach for to begin with. And if I decide at some point to make time significant in the game, it seems like I’d be adding insult to injury if I moved time forward one tick while telling the player that their action failed because the protagonist would never think to perform it.

But there are considerations against it. For one, in the standard library there are a number of (prevent $) rule definitions that report moral objections to the proposed action.

If I were using TADS 3, I’d have a similar issue in that I’d have to decide whether to handle this in verify() or check(). The situation isn’t exactly analogous though. The TADS 3 library and adv3lite allow the author to give an action a logical ranking during the verify() step, which seems like a solution well-suited to the problem I have in mind. (I could give knocking a domino onto the floor a higher logical rating than knocking a siddur onto the floor.)

Where would you put the relevant refusal? Note that I’m open to suggestions that would require rewriting portions of the library. I’m very early in the creation process, so if I’m going to get crazy, now would be the time to do so.

(Edited because of all the problems.)

5 Likes

That has been both my own experience in such situations, and that reported to me by testers.

Although, when I’ve wanted this behaviour in Dialog, I’ve always done it with a (prevent [bad action]) rule that then calls (stop), probably through ignorance of any better way to do it…

1 Like

I’m fairly sure there’s a predicate (inhibit next tick) in the library, but it’s not documented so might be an implementation detail rather than something you’re meant to be able to use?

1 Like

Assuming you’re using the standard library, that’s exactly how you should proceed except that there is no need to (stop) (if your prevent rule succeeds, the standard library calls (stop)). Of course, calling (stop) yourself has no consequences besides perhaps slowing your work to a degree that the vast majority of players will find imperceptible.

Thank you for your thoughts!

1 Like

@Pacian mentioned (stop) because that’s what allows you to prevent a tick occurring even when you prohibit the action using a (prevent $) rule rather than (refuse $). The tick occurs inside the stoppable environment, so if you call (stop) yourself, there is no tick.

1 Like

My bad. I momentarily conflated (refuse $) and (prevent $).

Personally, I think the standard library implementation of (refuse $) is very unintuitive, so that might change in a new version at some point! We’ll see if I can come up with a better way to do it.

But yeah, the standard way to stop an action before the protagonist ever attempts it is (refuse $). If you write your own (refuse $) rule, it will also take precedence over the standard library ones, so it will replace (for example) a refusal that the siddur is inside a glass case, or on a high shelf out of reach. If you don’t want that, you can write your own (prevent $) rule which calls (stop) (instead of the usual (tick) (stop)). Both are perfectly fine options and shouldn’t have any weird side effects.

On a design level, I agree that only attempted actions should take time. “Your character would never do that” doesn’t represent any in-game time passing, after all. That’s basically what Dialog tries to capture with the (refuse $) and (prevent $) distinction.

3 Likes