The hidden secrets of Inform 7

Thanks, Hanon and jrb,

I’ve been hearing too much about the Epistemology extension to ignore it. In what I’m working now, I think the “after printing the name” is enough, but I will keep the extension in mind for future projects.

As far as I know there’s no way of writing rules for the testing commands in I7; they’re hard-wired in I6. They don’t really count as “actions” at all (even as out-of-world actions); their implementation bypasses almost all of the normal action-processing, and “the current action” and other global variables are not set. This was the best way I could come up with for testing whether something’s name was being printed by some legitimate rule or by the SHOWME command. (There’s sure to be a better way of doing it with an I6 inclusion, but that’s beyond my scope.)

I see!

Well, I am certainly no the one to know about I6… :smiley:

Today I found this bit of awesome code in Mike Ciul/capmikee’s Lost Items extension (inform7.com/extensions/Mike%20Ci … rce_9.html):

[code]Converting parser error to action is a truth state that varies.

Before printing a parser error (this is the not yet converting parser error to action rule):
Now converting parser error to action is false.

After printing a parser error when converting parser error to action is true (this is the prevent extra line breaks when converting parser error to action rule):
say run paragraph on.

Before doing anything when the printing a parser error activity is going on (this is the now converting parser error to action rule):
Now converting parser error to action is true.[/code]

This is handy for if you want to redirect a parser error to an actual action. In other words, if there are tricky things “after reading a command” can’t catch, or if you want to run a rule in a

rule for printing a parser error when the latest error is the i beg your pardon error: decrement the score; say "I'm subtracting a point, because I'm mean."; follow the notify score changes rule;

1 Like

Here are two Inform 6 snippets that seem to go over well when I share them individually. I think Zarf originally posted these, though I added the debug flags to nag the tester to transcript ASAP. (I’ve forgotten to before.)

[code]Include (-
[ CheckTranscriptStatus;
#ifdef TARGET_ZCODE;
return ((0–>8) & 1);
#ifnot;
return (gg_scriptstr ~= 0);
#endif;
];
-).

To decide whether currently transcripting: (- CheckTranscriptStatus() -)

volume testing

debug-state is a truth state that varies.

section debug - not for release

when play begins: now debug-state is true;

volume beta testing

[mark this not for release once you get close to release, or judges will be asked for a transcript first thing.]

when play begins: if debug-state is false, try switching the story transcript on;

[/code]

If you want to see how close your z5/z8 file is to becoming z8/gblorb:

Include (- Switches z; -) after "ICL Commands" in "Output.i6t".
1 Like

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