The hidden secrets of Inform 7 thread

I keep seeing interesting threads about Inform 7 where people pull out these crazy tricks (like toggling the ‘scenery’ property on and off or stopping time).

I thought it might be fun to have a thread where people write down cool tricks they’ve discovered that other people may not know. (Advanced authors will probably already know a lot of these, but this thread is for beginning-to-middle range authors like me to learn from).

One thing I didn’t know when writing Color the Truth last year was that Inform treats NPCs and PCs the same, keeping track of their inventory and location, and you can say ‘Now the player is Alice’ and it will change to location to Alice’s location, the inventory to Alice’s inventory, and the ‘x me’ description to Alice’s description, while leaving the former PC somewhere.

One major trick that I feel everyone knew but me is that you can make any text contain Inform code. For instance, if you have cycling text like this:

Carry out pinching the player: say "[one of]Ouch![or]That really hurt![or]That left a bruise![or]No way, man, not again![stopping]"

and want a bruise to appear after the third message, you could either set up a counter (messy) or just do this:

Carry out pinching the player:
   say "[one of]Ouch![or]That really hurt![or]That left a bruise![addbruise][or]No way, man, not again![stopping]" 

The bruise is a thing. "You left a mark!"

To say addbruise:
    now the bruise is part of the player;

The [addbruise] is not printed, it just signals to the compiler that you want to do something, which you define by the ‘to say addbruise’ phrase. I thought this was really cool when I saw it, and I’ve used it a lot for things like responses to standard verbs.

What code tricks do you use that people might not know about?

1 Like

Craig, [addbruise] has left me totally flabbergasted! Thinking about it it looks absolutely obvious, but only after you are told about it! Thanks for the tip!

(It actually simplifies something I had some trouble working around, so I’m doubly grateful!)

Yeah, phrases triggered within quotes is pretty darn awesome. And there was an even cooler trick along the same lines until it was broken by the last major upgrade. I used it in every game up until that point.

There was a single magic line of I6 code that when included in the source text would let you write actual instructions in square braces instead of setting up a “to say” command:

[code]
After attacking the Wicked Witch:
say “‘Oh, now you’ve angered me. I’ll take that broom back!’ she says, snatching it from your grasp.[perform now the Wicked Witch carries the magic broom]”

After wearing the ruby slippers:
say “Now follow the yellow brick road![perform now the player is in Yellow Brick Road][perform now the munchkins are singing][perform now the Wicked Witch is furious]”[/code]

I didn’t know about that. Do you know what change broke it? (And what was the previously magical line of I6?)

Something I often find useful is the “[rule] does nothing” trick. To make effective use of it, you need to be able to track down the particular rules you want to block, using the various tools in the IDE.

Example 1: say we have a character, Tom Thumb, who is small enough to pick up. But Inform won’t let us (“I don’t suppose Tom Thumb would care for that.”) So we first track down which rule is blocking us, using the RULES command in the IDE:

So the “can’t take other people rule” is the culprit. Now the remedy is simple:

The can't take other people rule does nothing when taking Tom Thumb.

Example 2: this came up in a thread the other day—the problem was to stop time when the player was in a Tutorial Room. So we need to know how time works. Sadly the RULES feature is generally less helpful with rules which don’t relate to action processing. So this time we’ll turn to the Index instead. (We need to compile a story, however minimalistic, before we can look at the Index in the IDE.)

In the Rules Index (for “Inform’s general working’s”), we click on the Standards tab. Scrolling a little way down, we come to a section called “The top level”, which lists three rulebooks where various basic things are controlled. There’s a warning: “They can be altered, just as all rulebooks can, but it’s generally better to leave them alone.” We recklessly ignore it. One of the rulebooks here is the “turn sequence rules” which governs the cycle which makes up a turn. And inside that rulebook we find the “advance time rule”, which is clearly the one we’re after. So our solution is:

The advance time rule does nothing when the location is the Tutorial Room.

Regarding the “magic I6 line”: if I remember correctly, it was something like this.

To say @ (P - phrase): (- if(1==1){P} -).

One thing to be careful of with Craig’s [addbruise] trick: if you do something like measuring the length of the string, or comparing it against something else, it’ll set off the effects. A way to avoid this is to wrap your addbruise code in “if expanding text for comparison purposes:”

To say perform/@ (ph - phrase): (- if (0==0) {ph} -).

This causes the compiler to crash with the “I have no bloody idea what happened…” error. I think the code can be in the text, but invoking it with a

say "[perform now Donald Trump is in Prison]" 

type construction causes the noncompile.

I believe it worked in 6L02–I pulled the line from the source of Transparent which was released in 2014. It is not in Baker of Shireton which was 2015, but it’s possible I had started out using it and had to take it out. I know I had to write it out of Easy Doors and update. So it must have been 6M62.

EDIT: I’m wrong. It is in Baker of Shireton, but it can’t compile because Easy Doors no longer has the magic line.

One not so “hidden” secret is how useful the Index is. It’s packed with information.

Changing library messages used to be tricky without an extension or a curated list of them to copy and paste from. Now every message is in the index with a “set” button to copy the code into the source text.

Screenshot 2017-07-27 22.55.58.png

Screenshot 2017-07-27 22.56.16.png

Here I’m pretty sure what’s going on is that the I6 insertion in the say phrase only will get inserted into the compiled I6 source if the say phrase actually gets invoked. If you try this:

[code]Lab is a room.

To say uh-oh: (- this is some total nonsense that would never compile in I6 -).[/code]

then it will compile, but if you look at the compiled Inform 6 (which you can do by clicking “results” and then the “inform 6” tab at the top) you’ll notice that the word “nonsense” doesn’t appear anywhere in the resulting code. But if you try to invoke it:

[code]Lab is a room.

To say uh-oh: (- this is some total nonsense that would never compile in I6 -).

After jumping: say “[uh-oh].”[/code]

the Inform 6 compiler duly gives you the “WTF?” error.

Most people may’ve seen the test commands. The full list is in Tests.i6t in the “Reserved” folder. You may not want to edit it, but you may want to page through it for fun.

SHOWME shows everything about an item
TEST lets you execute a test command e.g. “test x as “n/e/open door”” …
ACTIONS shows details of your action
PURLOIN gives the player an item
ABSTRACT sends an item somewhere
GONEAR moves you close to a room or object
RULES (ON/OFF/ALL) changes what rules are displayed. ALL shows even ones not considered.
TRACE is a bit technical…it traces the stack, but it can be handy.

You may not use all of these, but getting familiar with even half of them REALLY helps with debugging.

Also I’m not sure if the below is in scope as debugging is not really a trick. But debugging is easier than you might worry it is.

[code]volume debugging

debug-state is a truth state that varies. debug-state is false.

every turn when debug-state is true (this is the print debug hints rule):
try in-game-hinting; [where in-game-hinting gives hints based on where you are in the game]

to debug-say (x - text): [this is so that you can have text you are confident will not pop up in release mode, which would annoy the player]
if debug-state is true, say “[x]”

section debug-asap - not for release

when play begins:
now debug-state is false;[/code]

OK, here’s a little simple thing I just figured out while debugging my code. Let’s say one uses the following distinction for items the player has seen or not seen:

A thing can be known or unknown. A thing is usually unknown. After printing the name of a thing (called item): now the item is known.

Here’s the rub: an unknown thing becomes known even by the SHOWME command. Indeed, in the list created by the SHOWME command, a thing only shows up as known (since its name has just been printed).

I am sure there is some rule that can overrule this, but I list it here, just as a little something for people to consider.

If that troubles you, here’s a fix.

After printing the name of a thing (called item) (this is the revealing rule): now the item is known.
The revealing rule does nothing when "[the current action]" is "".

The SHOWME command will be disabled in the publish build for the player, so it shouldn’t be a problem.

I’m uncertain if the built-in “Epistemology” extension by Eric Eve has this quirk. If you’re doing seen/unseen/unknown/known, that’s usually the go-to solution.

No it doesn’t. Epistemology doesn’t use the printing the name activity for marking something seen; it uses the carry out rules for the looking action (and also the opening a container action).

jrb, you lost me! Why “[the current action]” is “” and not “showme” or something?

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;

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".