top expert

a biting cat website

let’s make IF #15: disabling unwanted commands

Since only four commands are meant to do anything, how much time do we want to spend on commands like *PUT LIGHT IN YELLOW*?

last time, on let’s make IF…

I’m back, after skipping last week’s second post. Why did I skip it? I was getting my own work ready for a bit of playtesting. Look for a couple of posts containing my suggestions about playtesting (your game or someone else’s) very soon!

Last time, I gave general instructions for replacing default responses from the Standard Rules, using my own “default responses template” as a guide. To keep things simple, I’ve copied all of that extension’s rules into our current source code and commented it out. When we need something from it, we can just move it, uncommented, into the main body of our project code. As always, you can find this week’s source at the bottom of this post.

Since I didn’t cover it: do you know where to find these responses yourself? Just open up the Standard Rules (file>open installed extension>graham nelson>standard rules from the top-left dropdown menu in the IDE). This is a good habit to get into. For instance, perhaps you need to know when the response to a “jump” command happens? It’s in the SR. How about taking something before eating it? And so on. It’s worth spending some time in there, even if it doesn’t all make sense. About that jumping response. Let’s do a “find” for the text “jumping”. Here’s what we get.

Report an actor jumping (this is the report jumping rule):
	if the actor is the player:
		if the action is not silent:
			say "[We] [jump] on the spot." (A);
	otherwise:
		say "[The actor] [jump] on the spot." (B).

We know how to read this, don’t we? We have two conditions. In the first, the actor (the character doing the jumping) is the controllable character, AKA the “player.” In the second case, an NPC is jumping. Because we have a named rule (“the report jumping rule”) and a letter in parentheses after printed text, we can call each response by name

the report jumping rule response (A)

is a way to refer to the first of two printed texts. We can replace it with a simple declaration:

the report jumping rule response (A) is "I'm not jumping! No way.".

Note that the default rule uses substitutions to handle different pronouns and verb tenses. We can be more specific in our rule, because it only needs to work in one game–ours!

As a last note, be aware that you can treat these responses like any other text, using formatting, substitutions, and conditions to create reactive, compelling responses. As this project hopefully attests, Inform 7 is great for this kind of thing, so use those features when they make sense!

disabling stuff we don’t want.

In a game with only four verbs to progress the action, how much time do we want to spend on other verbs? For some, we can write low-effort rules or responses that players will enjoy. Others will not be so easy, and will not add much. For instance, “burning” has a default response that we can write quickly. It will reflect our authorial voice and we don’t have to worry about it leading to strange outcomes or messages. Since I’ve copied every response into our source, I’ll just cut-paste the burning response and put in in a new “book” of our project (organization is important!).

Volume 9 (default responses)


Book 1 (actions)

The block burning rule response (A) is "This dangerous act [would achieve] little.".

I’ll put revised action responses in book 1 of Volume 9. This is still the default. What should take it’s place? Anything you want, of course. Important considerations:

  • Avoid repetitive snark! If players are going to see a message again and again, a snarky message tends to become very frustrating for players.
  • Be careful with snark in general! There’s a tradition–or exaggerated perception of a tradition–of snarky messages in parser IF. A little goes a long way, and, often, none will go even further. Be aware of player patience and balance things appropriately.
  • Match the narrative voice. This is why you are probably doing this in the first place, isn’t it? Rewritten responses are a way to make sure that the text of your game is a cohesive whole.
  • Be sure the response will always apply. It can be hard to write one response that is always applicable. If cases change in-game, consider revision or adding conditions to your messages.
  • Make sure the information is useful. If something will never work, let the player know. Don’t make them think trying later will be a good idea.

Burning is a throwaway verb, in this case, so I just want to do something short that discourages future attempts.

The block burning rule response (A) is "You know it isn't safe to play with fire.".

The more developed our narrator is, the more in-character our responses can be.

What about other cases, though? A particularly grievous offender is the action “inserting it into,” which includes two nouns, which means it will try to disambiguate before getting to our rejection response. You recall that we added a placeholder response for actions we had flagged as “performing a productive action”:

before doing something:
	unless performing a productive action:
		say "That's not productive!" instead.

The road to that before response can be a long one. Here’s some play from the current source.

>put
(on the table)
That's not productive!

>put yellow
(in the table)
That's not productive!

>put light
(in the table)
That's not productive!

>put me
(in the table)
That's not productive!

Come hell or high water, Inform is going to find a noun for our error message. It doesn’t help us or our players, which isn’t a dig against Inform 7, as we are definitely getting away from Inform 7’s general usage.

disabling or redirecting input at the parser level.

We could do a lot of things, here. Rahter than wait for action processing, we could just kill the command grammar at the parser level. One option would be to do a new understand for the action as a whole:

understand nothing as wearing.

This will get rid of our first response above. Unfortunately, “put” as a command is affiliated with many actions, so we will be chasing them all down. Here’s our new output:

>put
(down the table)
That's not productive!

It may not always be clear what action is in play. We can use a debug command, *ACTIONS*, for that.

>actions
Actions listing on.

>put
(down the table)
[dropping the table]
That's not productive!
[dropping the table - ended without result]

It looks like dropping is next! Do we want to disable dropping? Let’s say that we don’t. We could go after the command instead.

understand the command "put" as something new.

Note that we can’t get granular with this declaration. It isn’t possible to say

understand the command "put [something] on [something]" as something new.

Only one word–the verb–is permitted in this understand phrase, and it completely wipes “put” from Inform’s command vocabulary. None of these will work anymore: “put on jacket”, “put hat on table”, or “put wallet in pocket”. Once we use this simple understand phrase, we must (re)write new “understand” declarations for any use of “put” in our work. In this case, though, that isn’t a big deal–we don’t care about using “put” at all.

Still, this is something you need to be very careful with in your own projects. Players are very used to established terms and synonyms, so taking them away is a risk.

In either case, though, there is an issue. Should these two commands generate the same feedback?

>put yellow on table
That's not a verb I recognize.

>adl;sjkhfads
That's not a verb I recognize.

Sigh. I should note here that many players will not care about this distinction, so tailor your effort to the time you have. Fiddling around with this kind of thing makes zero sense for a speed IF work, or for something with a looming deadline. However, for those with more time on their hands, we may want different messages. I know that I do. Why? The first case is a command players will expect to work. The other is not. It seems they should get different responses, doesn’t it?

a detour to nowheresville.

How can we customize responses while preempting the parser’s disambiguation attempts? This is rather high effort, so we need to focus on actions that can’t be dealt with in interesting (a relative term) customized responses. “Put” is probably the greatest offender, though there are a few others. Let’s start with “put” and a new, catch-all action where select junk verbs can go. Typing this will get repetitive, so let’s do something very simple.

failing is an action applying to nothing.
sfailing is an action applying to one thing.
dfailing is an action applying to two things.

before failing (this is the zero nouns failure rule):
	say "[the failure response]" instead.
	
before sfailing (this is the single noun failure rule):
	say "[the failure response]" instead.
	
before dfailing (this is the double noun failure rule):
	say "[the failure response]" instead.

to say the failure response:
	say "To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.".

Why all of these actions? Inform has a lot of built-in behavior that is usually very useful. It will attempt to guess what nouns we intend to use. It will ask us when it can’t guess. However, we don’t want any of that! For that reason, we have three different actions defined, depending on whether the player enters one, two, or zero nouns. Whichever they choose, the output will be the same, a generic “failure” response that guides players to using the right commands. How would we use it with “put”?

understand "put" as failing.
understand "put on/in/-- [something]" as sfailing.
understand "put [something] in/on/--" as sfailing.
understand "put [something] on/in/-- [something]" as dfailing.

what does the “on/in/–” construction mean? By using it, we are saying that Inform can accept either on, in, or nothing (“–” means nothing). Because our inputs account for every permissible number of nouns, Inform never asks for clarification or guesses about possible nouns. Here’s the output:

>put
To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.

>put blue
To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.

>put on blue
To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.

>put blue red
To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.

>put red on blue
To advance the game, choose one of four cards: *O*,*G*,*B*,*R*.

…and so forth.

As a postscript: you might wonder why we can’t manipulate a parser error into handling every case. There is no “current action,” since the parser has no current action yet. We could do an “after reading a command” rule to check for specific words in the player’s input, effectively bypassing the parser, but that has risks of its own. Besides the risk of missing something or getting something wrong, we might have to worry about managing a long list of possibilities. Where would they go? A table? Things could get overcooked (and fragile) rather quickly. If we really only mean to treat a few verbs this way, let’s go with these “failing” actions. They’ll show up in our debugging commands (*RULES* and *ACTIONS*), something parser errors cannot do. Which others should we look at? The main culprits are–in my opinion–actions applying to two nouns. Perhaps we should chase those down. Do we really have to read every line of the Standard Rules? The answer is no! Let’s have a look at the Index.

Have we talked about the index? That’ll be a good place to pick up next time, as we continue to customize input for our game.

PWW Current Source

next.

Next time: having a look at the index, disabling more verbs, and adding more default responses.

Categories: , ,

One response to “let’s make IF #15: disabling unwanted commands”

  1. let’s make IF #16 – top expert Avatar

    […] let’s make IF #15: disabling unwanted commands […]

    Like

Leave a comment