The hidden secrets of Inform 7

Here’s another I6 snippet zarf taught me: You can figure out what action the parser is trying to process even before it’s done, like this:

To decide which action name is the action to be: (- action_to_be -).

This can be useful for customizing parser error messages for a particular action, or customizing the disambiguation question for a particular action, or to allow a word to be used as a synonym for an object when trying a certain specified action.

This is undocumented, which technically means it could disappear without warning in future versions of Inform, but that would only happen if the parser internals get rewritten, and that doesn’t seem likely to happen for a while.

And one of those threads reminds me that this is sort of a hidden secret, or at least something one experienced author didn’t know about: You can write an Understand line with no verb, so the player can invoke the action just by typing the noun:

 Understand "[something]" as examining.

(There are some things that can get weird with this, because in some contexts Inform checks to see whether you’ve issued a command by testing the first word against a list of verbs–specifically, if you issue a command “JANE, ROCK” the parser won’t understand this as “JANE, EXAMINE ROCK,” and if you enter a noun-only command in response to a disambiguation question, Inform will treat that as a response to the question rather than a new command–though that’s probably a good thing anyway.)

1 Like

This isn’t as neat technically, but it’s one of those things where I wondered why I didn’t try it before.

Emily Short’s Property Checking extension is a wonderful extension to make sure that your things are basically implemented. You can also tweak it pretty easily for your own specific uses.

I was looking at it again and noticed this possible extension:

[code]chapter scling

scling is an action out of world.

understand the command “scl” as something new.

understand “scl” as scling.

carry out scling:
say “List of scenery:[line break]”;
repeat with QQ running through visible scenery:
say “–[QQ][line break]”;
the rule succeeds;
[/code]

This simply prints out all the scenery you can view now. So you will know if scenery mentioned in a room description actually exists, or that scenery you lovingly crafted is mentioned in a room description. This has helped me tabulate a lot of things & made programming testing go more easily. The code also catches backdrops, which can be moved among rooms, so that’s helpful.

While you can use the SHOWME command, this isolates something that people can often overlook, and it helped me be much more efficient when programmer-testing an old project. So I hope it helps others.

1 Like

One easy trick I did for my IF comp entry this year is… you know when you have some tables with ambiance messages, the gameplay could become pretty busy. Sometimes you have an important paragraph of text stolen by a pesky albatross or something. So, in the “director” code that show the tables you can test what important actions are being processed that turn and “do nothing” and with that prevent the ambiance messages to show up in those important actions:

Every turn during Muertos: if we are qbc responding with: do nothing; otherwise if we are talking to: do nothing; ... ...

Ruber.

1 Like

Here are some miscellaneous things I found lying around.

This finesse helps avoid runtime errors.

if x provides the property examined: say "[x] is if x is examined]un[end if]examined."; else: say "[x] is unexaminable."

The code below shows the value of a variable without having to type say “variable x is [x].” The command “showme” is also useful as a debugging command.

to show-critical-variables: showme xxx; showme yyy; showme zzz;

On a similar note, the “whether or not” syntax is handy for me. Here’s where passing a truth state as a parameter is useful–well, for me, to show if an option is on or off.

[code]let important-option be a truth state.

carry out optflipping:
now important-option is whether or not important-option is true;
say “You’ve toggled important-option [on-off] of important-option.”;
the rule succeeds;

to say on-off of (t - a truth state):
say “[if t is true]on[else]off[end if]”[/code]

Should that be “now important-option is whether or not important-option is false”? And I think the close bracket in the next say statement should be before the period.

Nitpicking aside, that’s a very cool point that I hadn’t thought of.

1 Like

Oops, you’re right. I’m a bit embarrassed by that. I thought I checked the code before cutting and pasting…

I’ll add another one. I enjoy being able to test certain verbs, but it’s a pain to keep typing them in. So I thought I’d show how I run quick and dirty tests. Running one of these brings a little variety to the general programmer regression tests you have to do. It’s not just about going through a walkthrough

[code]volume specific verb tests - not for release

… (define variables and toggles here)

think-every-turn is a truth state that varies.

chapter thinkting

thinkting is an action out of world.

understand the command “thinkt” as something new.

understand “thinkt” as thinkting.

carry out thinkting:
now think-every-turn is whether or not think-every-turn is true;
showme think-every-turn;
the rule succeeds;

every turn (this is the test module rule):
if think-every-turn is true, try thinking;
if hint-every-turn is true, try hinting;
if smell-every-turn is true, try smelling;
if listen-every-turn is true, try listening;
if inv-every-turn is true, try taking inventory; [there are others of course]
if pronoun-every-turn is true, try requesting the pronoun meanings; [this is the equivalent of the PRONOUN command]
[/code]

For the “pronoun” test, I noticed Climbingstars wasn’t the only one who shared it. You did too…

I found it immediately handy long ago, and I bet others will too.

To set the/-- pronoun it to (O - an object): (- LanguagePronouns-->3 = {O}; -).
To set the/-- pronoun him to (O - an object): (- LanguagePronouns-->6 = {O}; -).
To set the/-- pronoun her to (O - an object): (- LanguagePronouns-->9 = {O}; -).
To set the/-- pronoun them to (O - an object): (- LanguagePronouns-->12 = {O}; -).

I find setting pronouns particularly useful if you want to focus the player on scenery, or you want to make sure “it” is not out of play, or “it” changes, e.g.

USE BROOM
The broom sweeps the floor. You find a penny under the dust. You pick it up.

X IT
(player probably means the penny)

There are good hint testing modules that are a lot more robust than the code above, and they may well have inspired my code and I forgot about it. But this lets you construct what you want with brute force. I like to razz folks I test for to add a “hint-every-turn” rule so they can be sure it doesn’t misfire.

Oh, one other thing. I also harp on my testees to change the “you can’t go that way” message. Here’s how to check it’s not the default.

volume direction testing - not for release

thataway is a direction. thisaway is a direction. thataway is the opposite of thisaway.

direction-test is a truth state that varies.

every turn when direction-test is true (this is the test a direction that can't work rule):
  try going thataway;

Also, it’s useful to have verbs for “end the game” and “end the game finally”. This helped me immensely with testing fixes to end of game menus. Of course, if you have an activity (e.g. listing what you missed) you can define a command for that, too, in-game, but these are useful quick and dirty verbs.

[code]chapter ending

ending is an action applying to nothing.

understand the command “end” as something new.

understand “end” as ending.

carry out ending:
end the story;
the rule succeeds;

chapter wining

wining is an action applying to nothing.

understand the command “win” as something new.

understand “win” as wining.

carry out wining:
end the story finally;
the rule succeeds;
[/code]

1 Like

And one more thing, why not.

If Inform throws a weird sounding parser error, e.g.

“I only understood you as far as wanting to VERB.”

There’s an easy way to change that.

rule for printing a parser error when the latest parser error is i beg your pardon error: say "EH? WHAT?"

If you get the wording wrong, poke around in Standard Rules.i7x.

A command parser error is a kind of value. The command parser errors are didn't understand error, only understood as far as error, didn't understand that number error, can only do that to something animate error, can't see any such thing error, said too little error, aren't holding that error, can't use multiple objects error, can only use multiple objects error, not sure what it refers to error, excepted something not included error, not a verb I recognise error, not something you need to refer to error, can't see it at the moment error, didn't understand the way that finished error, not enough of those available error, nothing to do error, noun did not make sense in that context error, referred to a determination of scope error, and I beg your pardon error.

This is another thing I harp on to people I test for, to give the game flavor even if things go wrong. It helps me when I write, too.

Good trick. I have to admit though, I always find it hard to tailor some of those messages without knowing in what circumstances they apply. Some of these are pretty obtuse (quick, when does the aren’t holding that error occur? What about the didn’t understand the way that finished error?).

In 18:35 the documentation suggests this little trick:

Rule for printing a parser error: say "The [latest parser error] happened."; continue the activity.

You can add this as a debug rule under “Not for release.” I’d also bold that message so it will pop out in a transcript.

1 Like

That’s fine, but I meant the other way around: for a given parser error, how do I make that happen so I can test it?

Looking at Parser.i6t, it appears that several of these parser errors are currently out of use (6M62). These are

said too little error
aren’t holding that error
can only use multiple objects error
excepted something not included error
not something you need to refer to error
didn’t understand the way that finished error

I’m not sure whether the noun did not make sense in that context error ever fires under its own name; I’ve only seen its response text under the auspices of the referred to a determination of scope error, which has no response text of its own.

Here is some code which generates the others. Several of these have variant response texts, though, especially the nothing to do error which has quite a few. All the response texts can be found in Section SR2/14 of the Standard Rules. They can be referred to and changed directly without going via rules for the “printing a parser error” activity.

Orchard is a room. 
An apple is a kind of edible thing. There are two apples in Orchard.
Counting is an action applying to one number. Understand "count [a number]" as counting.

Before printing a parser error: say "The [latest parser error]: ".

Test me with "put apple elppa / jump apple / count apple / take elppa / eat apple and elppa / take him / kiss apple / 
osculate apple / eat apple then take it / take two apples / take all from me / push apple it / / me, again / , hello / 
elppa, hello / apple, hello / me apple, hello".
1 Like

Much obliged.

I spent a while recently trying to get plain numbers out of my values, and just now struck on a tidy solution.
When defining the value, we can say:
“An area is a kind of value. 1 square mile specifies an area with parts number.”
The parts syntax introduced in §15.15 is intended for values with multiple numbers, but also works here.
Now to get our number of square miles as a plain number, we can refer to the “number part of” whatever our value is called.

[size=85]Apologies if this is considered a necropost, but since I7 hasn’t updated I feel like this thread is still relevant, and I’d love to see more tips posted.[/size]

1 Like

Another way to do that is to divide by the unit. So 47 square miles divided by 1 square mile is 47.

1 Like

While i don’t quite like practicing necromancy, sometimes the truth can only be found from the long buried.

What does -to say-, do exactly? How is it different from the notion of Carry out?

I’m struggling to flip some flags in the quip-based conversations extension, to enable some quips outside of a before-after situation (even in those, really). Sometimes a simple to say, with the declaration works. Others it does… not.

Franky i’m struggling to articulate the question because the problem itself has me stumped. I don’t see a common pattern as to why some actions are not carried out in “to say” or “carry out”.

Carry out doesthisworking:
	enable the whatdo quip;
	enable the whydo quip;

Check talking to the character:
	if the location is tutorialarea:
		if charactetalk is true:
			try doesthisworking.

and the quips refuse to turn into the ON state. but binding them to say, jumping they do so immediately!

I’m utterly confounded on this.

2 Likes

Oh, I dimly remember struggling with this two years ago when I wrote a game with this extension – I unfortunately don’t fully remember exactly what the issue was or how I got around it, but I want to say that there was some timing issue with when quips get enabled or disabled, so that I wound up either doing that at the end of the previous round, or maybe using before rules? Apologies if that winds up being a red herring, it’s been a while and I’ve had a kid in the interim so my brain is kinda mush.

EDIT: oh, and to your actual question: to-say statements are basically like functions, you can call them in your code anytime you want and they’ll do exactly what they say. “Try Xing”, on the other hand, has the player carry out an action, running through all the associated rules (check and carry out ones included). So if you want to do something small and code-focused, like setting quips, a to-say statement – or just defining a new phrase – is likely better than going through the action infrastructure.

2 Likes

Yep the issue has popped up out of nowhere and the timing is odd. Creating a unique action that is tried silently works; in the very first room, while it does not in any other room. I wish there was a way to debug everything but ACTIONS is proving… not particularly useful.

1 Like

(Added an edit to the above, dunno if you saw it).

Hrm, that’s confusing – if you have sample code I might be able to take a look (dependent on how long my son’s nap lasts it could be quickly or not until tonight :slight_smile: ).

Apologies if this is a dumb question, but do you know about the RULES testing command? If ACTIONS isn’t getting you the level of detail you need, it can often be helpful.

1 Like

I did not in fact know about the rules command and i’ll be trying it promptly. As for the sample code, i’m afraid that the sheer amount of frustrated cussing due to not understanding makes it a bit unsuitable for uh, human consumption. I will try to sanitize and reply if it keeps being… impossible to work with.

Worst case i’ll just enter the game as a, uh, first view in the back garden and work on it in my pace. :melting_face:

EDIT: The solution, was to link the actual action through conversation nodes/quips from a different character. Something in the priorities was overriding the actual activation, and this seemed to fix it. :yawning_face:

1 Like