Most common 'mistakes' and 'crutches' for those starting out with inform 7?

Oops, I should have looked before posting, @otistdog and @kamineko basically covered the importance of this understanding without needing an essay to explain it. :stuck_out_tongue:

5 Likes

Before defining a new action, the easiest way to check is to play in the IDE and turn on ACTIONS (by typing “ACTIONS”) and then try the verb you want and any potential synonyms for it to see if the parser already has an interpretation you can use or need to untangle from understand rules first.

The common one is KNOCK ON DOOR. “Knock” is pre-defined as a synonym for ATTACK. If you try knocking on a door, you’ll get the standard refusal for violence (unless you’ve already re-defined ATTACK…but) With Actions on, it will say “Attacking the door - failed.” so you know what action it’s interpreting and can just use that action:

Instead of attacking the door:
    say "You knock politely. Nobody's home."

This has the added advantage of catching ATTACK DOOR, HIT DOOR, KILL DOOR, etc.

RULES also is handy, especially if you name your rules:

Instead of attacking the door (this is the polite visiting rule):
    say "You knock politely. Nobody's home."

That way when RULES is on and you get a despairingly huge list of rules, it will say “The polite visiting rule applies” instead of “The Instead of attacking rule applies” which is much easier to figure out as many rules you wouldn’t think of often are checked and will or will not apply to any action.

7 Likes

The biggest mistakes I made were with punctuation.

If you have an if-statement right after a sentence, it looks bad. For instance:

You see Bob here.[if Bob is angry] He looks angry.[end if]

will end up printing the two sentences on different lines.

So the best thing to to do is:

You see Bob here[if Bob is angry]. He looks angry[end if].

This will print everything on one line.

This comes up way more often than you’d think, and is non-intuitive.

11 Likes

I still struggle mightily with this. Punctuation and brackets make weird line breaks, and even though I mostly grasp the rules, I have trouble applying them while writing, which means I have to comb back through to find every spacing problem caused by the weirdness. I really, really wish I had gotten this down early on.

4 Likes

My reading of the “don’t need to understand how this machinery works” line is just that one doesn’t have to sweat internalizing the details of 19.16. The Laws for Sorting Rulebooks, that in practice knowing “more specific rules go before more general rules” is all you need.

This continues to be a challenge of mine. I still default to thinking in other programming paradigms than rule-based. Even moreso, I’m sure I still haven’t grasped how much potential assertions with every has. ( WI 4.16 Assemblies and body parts, WI 4.17 Names made in assemblies )

3 Likes

Sometimes when the line break things vex me, I just give up and fall back on:

To say ?: say unicode 63.
To say !: say unicode 33.
To say dot: say unicode 46.

Then one can say any of "[?]", "[!]", or "[dot]", and get “?”, “!”, “.” without any line break implications.

11 Likes

Hey, that’s really cool!

3 Likes

Agreed, that section is the dense bit I was talking about, a little unclearly. I’m not overly bothered by the phrasing, the chapter as a whole is fine. I mean that I struggled with a lot of concepts before I read that chapter, and I didn’t read it for some time because I hadn’t yet learned to skip around a bit. I think people who program in several languages will know the feeling of simultaneously recognizing and being unable to imagine the scope of the things possible with a language we’re comfortable in. I didn’t really get that feeling about Inform until I started to grasp rules, and even now I don’t use them where I definitely could. Rule-based programming is cool, but it was unintuitive to me until it was explicitly described.

I know I haven’t lol

3 Likes

Some great contributions here. I always find it really helpful to see where others have stumbled and try and learn from that.

My biggest challenge at the moment in creating my combat system is dealing with many variables all having to harmoniously coexist without breaking something.

My standard action variables are approaching a point where soon it will have a dozen if statements, a dozen let statements, numerous now statements etc. So far I have successfully been able to make this work but as I try to add more adventurous features it is definitely proving to be quite challenging.

I am also tryjng to write it as if it could eventually be adapted to an extension, not because I think it would make a good extension for other people but moreso that most of the code is written in a way where it doesn’t rely on rules that are specific and instead very general and broad. While at first this was a challenge to get my head around, it has made adding new weapons, armour, items and so on a breeze. Simply specify the kind and add the stats and it just works.

I am yet to delve deeply into tables, lists and list creation and truth states.

Numbers and variables are in themselves a bit of a challenge and when hundreds of lines of code are almost all describing an action and variables, it can be quite tricky to keep everything from breaking.

I’m very excited to eventually have my ‘personal extension’ if you will, complete so I can begin applying it to either a rogue like format or (ideally) a crafted narrative which uses the extension in an engaging way.

Every night I have been setting a goal for a feature or two to implement and almost always I get them done, so while progress at times feels a bit slow, it’s progress nonetheless.

1 Like

It took me some time to grok that you can write rules (mostly) wherever in the source text you want and I7 sorts them out at compile-time, with the only caveat that more-specific rules take precedence over less-specific rules, and you can specify vaguely where in the rule stack they go with “first” and “last”.

I think it’s last-in, first out, so if you write in this order:

First check jumping: say "Foo!" instead.
First check jumping: say "Bar!" instead.

…if I remember correctly, the compiler reads the “Foo” rule which is written to the top of the check jumping rulebook, then the “Bar” rule is similarly written to the top before that. The Bar rule would run first and fail the rulebook, so you’d only get the Bar rule to fire.

3 Likes

After I thought I had a decent knowledge of I7, my biggest comeuppance was some basics about texts.

In 6G60, “text” and “indexed text” were separate types one had to convert between. Texts were strings that included adaptive text; indexed texts were plain text strings. In 6L02, they become one thing from a language user point of view while still having separate representations under the hood. In 6M62 and v10, one can still say “indexed text” but it means the same thing as “text”.

Texts containing adaptive texts are Schroedinger’s Boxes: their values are undefined until you open the box and the wave function collapses into some particular string. And that happens every time you open the box. So if you have:

pack-animal is a text that varies.
pack-animal is "[one of]mule[or]llama[cycling]".

when play begins:
  say "'[pack-animal]' is [number of characters in pack-animal] characters long.";

you get "mule" is 5 characters long.

To pin it down, you need the substituted form of <text>. The docs also refer to this as “expanding”, though that’s not the name of the phrase. I’ll use that term in the following.

If you try to compare two texts-with-adaptive-text with “is”, the result is almost always false even if their expanded forms are the same. If you have if t is empty when t is a text-with-adaptive-text, the result is always false, even when the expanded text is empty. Comparing two plain texts with “is” works. Comparing a text-with-adaptive-text to a plain text works (the text-with-adaptive-text gets expanded). Thus the easiest way to test whether a text-with-adaptive-text is empty is if t is "".

So: don’t compare strings variables with “is”. If one side or the other is a text literal (“literal” is programmer-ese for not a variable, but some particular explicit value in your code, a quoted string in this case), e.g., if t is "cat" you’re okay. Otherwise, stick to if t exactly matches the text w.

To tell whether something is a plain text or a text-with-adaptive-text, you can use the substituted or unsubstituted adjectives.

To say phrases can have any code, including code that has nothing to do with output. So there’s a sometimes clever trick where you sneak side-effects into saying things. But keep in mind that these side effects occur every time the text is expanded, not just when it’s output. So if you have:

g is initially 0.

To say gg: increment g; say g; say line break;

when play begins:
say gg;
if "[gg]" is "1", say "gg = 1.";
let q be the substituted form of "[gg]";
say gg;

the output is:

1
4
5 Likes

The rather arcane reason for this (as I suspect you know) is that a ‘text with adaptive text’ is conceptually a function returning a text and Inform considers that two different functions are not the same thing, the results returned by said functions being irrelevant to this non-equivalence.

As a simple conceptual example, 2 squared is not the same thing as 2+2, even though both return 4,or x multiplied by x is not the same as x squared, even though both return x squared.

In Inform this idea is taken one step further, in that Function A is never considered the same thing as Function B, even if both Function A and Function B contain identical code to return 2 squared. This is unsurprising, as it would be difficult for Inform to discern equivalent functionality in function code, and it doesn’t try to.

4 Likes

Similarly, following on from the concept of ‘text with substitution’ as ‘function returning text’, ‘if some-text-with-substitution is empty …’ is asking whether the given function is non-existent, hence it is always false.

3 Likes

There’s an additional ‘gotcha’ here in that texts can be expanded unexpectedly by the internal workings of Inform so that Inform can examine the current result of that expansion for its own purposes. This will unexpectedly run any ‘non-outputting code’ included in your ‘To say …’ phrase. You can trap this unwanted behaviour in your ‘To say …’ code by presaging ‘non-outputting code’ by the almost-undocumented conditional ‘unless expanding text for comparison purposes …’ See here and here.

4 Likes

Or, if you prefer, the slightly more longwinded ‘if the substituted text of t is w’

1 Like

Following on from previous concepts, the exception to this rule would be in situations such as:

	let t be "You are in [location]";
	let w be t;

in which case w & t are two variables referencing the same singly-declared function, so ‘if t is w …’ is the equivalent of ‘if Function A is Function A …’ and is therefore true, whereas after

	let t be "You are in [location]";
	let w be "You are in [location]";

t & w reference two separately declared (albeit identical) functions and ‘if t is w …’ is the equivalent of ‘if Function A is Function B …’ and is therefore false.

4 Likes

A quoted text immediately after the definition of a room or a scene assigns the value of that room or scene’s description property.

A quoted text immediately after the definition of a thing assigns the value of that thing’s initial appearance property. This still sometimes trips me up: I forget and try to assign a thing’s description this way.

So, to populate a thing’s description you need to explicitly say “description”… but one can cut down on the verbosity a little by omitting “of the thing-name”:

Foo is a thing. Description is "Looks like a foo.".

You could also say “The description”, but not “Its description”. The same applies to assigning values to other properties… but note that you couldn’t say “Fixed in place is true.” 'cause Fixed in place is an attribute, not a truth state property.

Also, if an initial appearance is assigned, it will appear until the thing is handled, i.e., if it has ever been held by the player. Ordinarily, people will never be handled, and neither will anything that’s fixed in place (which supporters are by default). So be careful with assigning initial appearances to people, or supporters, or anything fixed in place. (All of this describes default behaviors; one could add code modifying any of it.)

By the way, you can even add text properties called description to other kinds of objects and the compiler will allow you to assign their descriptions with just a quoted text. (But this can’t work with things or subkinds of things, for which it will always be initial appearance.)

A foo is a kind of object. A foo has a text called description. 

Fubar is a foo. "aoeu".
4 Likes

Unless the thing in question is marked as scenery, in which case putting a quoted text immediately after its creation does assign the description property. (Since scenery is not mentioned in room descriptions, it wouldn’t make too much sense to assing it an initial appearance.)

5 Likes

ha, thanks, I didn’t know that!

2 Likes

I’m coming to this late, but I realize there is so much I didn’t know, and I had blind spots about it, and it was okay. But then I find it and don’t know how I lived without it. Or I said “oh, I couldn’t ask for THAT feature, it’d be too much.”

I was glad I found the testing commands early. @DeusIrae mentioning RULES and ACTIONS is a big one. You don’t need to be a debugging whiz to debug. I’d say PRONOUNS is good to know–I wrote a simple testing extension to check the pronouns every move, and it was neat. TEST X WITH “this/that/the other” is good too. PURLOIN and ABSTRACT and GONEAR and SHOWME save so much time if something is broken at the end of your game and you don’t want to run a whole long test script to get there.

I wish there was BANISH in the test suite proper (move something off-stage) but that’s easy enough to implement on your own.

One thing that still trips me up is after/report rules. I might have

after looking in the hub room: say "Wow! The hub room has a lot of places to go!"

after looking: (check stuff)

The 2nd rule doesn’t fire because the 1st and more specific doesn’t continue the action.

I also knew how rules worked roughly but it took a while to put them in order e.g.

the Andrew's less generic default rule is listead instead of the can't wear what's not clothing rule in the check wearing rulebook.

I also always used to keep falling into this:

[the block smelling rule is not listed in any rulebook.]

check smelling: say "Smelling may offer occasional clues, but nothing here." instead;

Without the one line commented, my check smelling rule doesn’t fire.

I’d also echo looking at “rules” in the tabs on the IDE. They tell what order the rules fire in, which can clear up a lot of confusion.

One other thing that really streamlined things was when I realized you could just do this en masse so you didn’t have to worry about all the verbs.

understand the command "jump" as something new

Also I enjoyed reading the standard rules to see what the default verbs were. I learned so much! And at some point I felt more than okay just un-defining some standard verbs.

I’d also like to share some coding I did early this morning. At first I only used “check” rules to block the parser from doing something and never used “after” and I think the before/after of my code when I split something into more readable parts.

So I had one item that had a big lump of code with a bunch of if-then commands inside it for a big description. (the “to say” syntax seemed wrong, because tracking line breaks was tricky.) You will be more likely to see the bug from the “after” code that there’s a bug that got lost in the lumpy code, which I’m not sharing. (I cut out some text.)

But the thing is, I never thought to use “after examining” because this was what you should see while examining! So I had that logic error. Another big one I remember is someone new to Inform creating a dead person as an actual person instead of scenery. The first makes sense logically, but the second is easier to implement given how Inform (quite sensibly) gives people properties.

messy code vs clean code
after examining megaton magneto montage:
       say "CLOSED TODAY: (list).";
       if store b is not figured-out, say "Free samples in store b.";
       if store c is not examined, say "(store c stuff)";
       say "Store H is the bonus area after the initial quest.";
       say "Stores F, I M and R were last game.";
       if store k is in strip or store k is in strip, say "Condemned: stores K and N.";
       say "(stores you can change and enter): P, U, V, W, Y.";
       if store t is in Strip of Profits, say "(text how store t is the final one).";
       say "[line break][engrav-note].";
       if montage-change-warn is false:
               if number of solved regions + number of bypassed regions > 1:
                       say "[line break]It's kind of out of date since you already got solving stuff, but it'll be good enough reference in the future.";
               now montage-change-warn is true;
       continue the action;

So often I was just so glad Inform could do stuff, I wrote code and didn’t really look into it! It’s okay to do that at first, but Inform can let you write better looking code, so you should try to when you can. Don’t force it, though.

I think this is the sort of question that needs to be asked more often than it is on this boards. My answer always seems to change.

For whatever reason, I really dug into the parser error rules first. It was neat you could do things! Other people seem to avoid them, but I’d advise giving them a look, as they can clue the player quite nicely too.

5 Likes