Best Practices for Inform 7 Games

Apologies if this has been covered before - I had a search of the forums and and was a little surprised to find nothing turned up - but I’m curious what people consider the best practices for writing parser games with Inform 7. I imagine the overwhelming majority of this would be equally applicable to any other language, but I also imagine it would be more helpful to have specific examples of how to implement these things.

I’m still comparatively new to parser IF in general (I’ve written three or four pretty small games), but I’ve picked up enough useful feedback from a couple of IFComp entries that I’m starting to get an idea what people expect from these things (and imagine there are further expectations I don’t know about). Suggestions have included things like an EXITS command (which I don’t know how to implement but gather should list what’s N/E/S/W/etc. of the player’s current location) and a list of AMUSING things to do (possibly provided at the end). The other big suggestion was that I could replace the default responses to all verbs: again, I don’t know exactly how to do that but the knowledge it’s supposedly fairly trivial gives me something to aim for. I think I’ve also seen people trying to use some kind of TRANSCRIPT command while testing, but although the Inform 7 documentation says Inform “includes” this command it doesn’t appear to do anything by default.

Essentially, if you were giving advice to a completely hypothetical just-barely-beyond-beginner-level Inform 7 author, what features would you recommend that they add to their game, and what defaults would you recommend they change? What would add the maximum amount of polish with the minimum amount of effort? Bonus points if you can give a quick example of the code necessary to make it happen, or can point to the source code of a simple game that does these basics particularly well.

6 Likes

First off, congrats on your games, they may be relatively small and simple but I’ve certainly enjoyed them!

…they’re also even more impressive than I thought, because you’ve been testing without transcripts? Wow, that seems very challenging. The way it should work is that when you type TRANSCRIPT or SCRIPT ON, the interpreter should pop up a window that allows the tester to save a text file of the session. Then they can share that with you and you can see exactly what they typed, what worked, what they struggled with, what synonyms you might want to add… plus it’s an easy way to have testers take notes as they go, since you can ask them to just write an asterisk then type any comments directly in (the asterisk makes them easier to find later). What interpreter have you been using that doesn’t behave that way?

As for changing the default responses, here’s the first bit of documentation for that. And here’s a link to one of my games that has source code available, so you can see which responses I modified - you can just copy and paste that section and rejigger accordingly and you should be covered for like 90% of situations (my code is pretty terribly organized but the section is near the top, you can just ctrl-f for “response”).

I think we’ve had an earlier thread with more general tips, might try to dig that up too for other ideas. But hope the above is helpful!

5 Likes

Yes, this, or, to expand to a general principle: I don’t enjoy experiencing gameplay that feels like a reading comprehension exam. It’s kind to make important information that is not meant to be concealed readily apparent/available, especially during return visits. In my games (RTE and works in progress), I just capitalize directions in room descriptions (and put them between asterisks so screen readers will pick up on them).

Yeah, I think a larger or more ambitious work should aim for this. At least most or many. Writing custom parser errors is trickier, but also worth considering. I have a lot of fun doing this kind of thing; it helps me get into the headspace of the narrator and/or protagonist. You can type “responses all” in the Inform 7 IDE if you’d like to see every active one. It’s straightforward:

The can't take yourself rule response (A) is "[if the player is the entropist]The attractive and convincing primeoid shell encasing me isn't going anywhere.[otherwise]No. I literally and figuratively can't take you."

Note that you can make these messages conditional, which adds a lot of potential.

These are all of the custom messages for RTE. It’s long; don’t look unless you’re really interested. This isn’t all necessary of course, I think that even a few customizations can give a strong sense of polish.

RTE messages.txt (16.7 KB)

Other:
I think the status line is often a missed opportunity. Even if your game doesn’t feature a traditional scoring system, there’s probably something good to do with it. Exist listing, if nothing else.

Don’t be afraid to shut down combinatorial explosion. I sometimes see a writer wax poetic about the nature of freedom and the harzards of freedom and agancy, but my experience is this:

Players want a credible sense of freedom. They don’t want “existential freedom: the game.” It’s fine to manage your nouns with rules like

instead of prying something with the screwdriver:
	say "Mere posession of a screwdriver doesn't give you the right to break your neighbor's nice things.".

(less snark, but you get the idea.) Let people know what’s possible and what isn’t.

Just as general advice for a new author: try to use tables when possible until you’ve mastered them. They’re just so handy.

The repeat the ending source is here.

5 Likes

Some I7-specific advice: the biggest benefit of I7 over other languages is that it can produce very readable code. Aim for your code to read like English, which will make it easier for you to skim later and figure out what’s going on. Remember that each line of code is usually read many more times than it’s written!

For example, Inform doesn’t care what articles you use with nouns except the very first time you declare them. These bits of code are equivalent:

A desk is in Study.
Instead of taking desk: say "It's too big."
A book is on desk.
There is a desk in the Study.
Instead of taking the desk: say "It's too big."
On the desk is a book.

A lot of people prefer the first style, cutting out extraneous words. Why use “the” if it doesn’t mean anything? But I think it’s good style to include it, because the more English-y your code reads, the easier it’ll be to skim later. Your brain has years and years of practice skimming English to find the most important bits. Using a couple extra words to tap into that skill is a good tradeoff, in my opinion!

6 Likes

I agree that it is worth the effort to make readable code. It’s easier to troubleshoot, easier to search and—this is important to me, too—easier to share with people.

I prefer using readable names for values. Using phrases, and writing rules individually.

You may prefer different things, but write code that’s easy for you to read. Inform 7 is very accommodating in this respect.

Also:
It’s worth trying to use the entire action processing sequence (before, instead, check, carry out, after, report). You can do a lot with instead, but that will hold you back later. Lots of threads on that here.

5 Likes

The reasoning for this is that most of the commands people type in your game (or any Inform game) are errors: trying to find exits, experimenting with actions, mistyping, getting things wrong. So the error responses are your game, in a sense. If you don’t change them, then the majority of your game sounds like Graham Nelson’s default voice (which can work, but usually doesn’t).

Another small point is that if you don’t put something at the end of a paragraph or on a separate line, people probably won’t notice it. Which is good if you’re hiding something, and bad if you want them to pay attention.

6 Likes

I’ve been scared of tables, but I see that you’ve done a series on them, so I’m going to buckle down and try to learn them for my next game!

6 Likes

hope it’s useful! let me know if you have questions about it :slight_smile:

1 Like

…they’re also even more impressive than I thought, because you’ve been testing without transcripts?

Ah - I have actually seen transcripts (at least for Mayor McFreeze - Gum E. Bear was written and tested in such a short space of time that I fear I’d lose all credibility if I owned up to that), but I believe my testers were simply copying and pasting manually.

Also, thank you so much for pointing out the source for Sting! It’s helpful to see this stuff commented up (even if it’s often quite self-explanatory in context). I see you’re using “understand” quite a bit more than I think I have been (particularly when it comes to verbs/actions rather than just nouns) and I wonder if that’s something I should be aiming for to avoid the “Guess how to express X” situation that I imagine is lowering IFComp ratings somewhat.

2 Likes

The reasoning for this is that most of the commands people type in your game (or any Inform game) are errors: trying to find exits, experimenting with actions, mistyping, getting things wrong. So the error responses are your game, in a sense.

Yes, this is a big chunk of the reason why this appeals to me for the Bubble Gumshoe games in particular. I went into the first one thinking that the slightly unconventional route to solving the mystery would be the main appeal and the sugar-noir setting would get a chuckle at best, but in practice the setting seems to be the main draw (and if anything I get the impression people responded better to more traditional puzzles anyway). I’d like to be able to make more of what doesn’t work in game terms still offer something appropriately sugar/noir themed.

4 Likes
  • If you are writing in Inform 7, there’s a really helpful extension called Object Response Tests by Juhana Leinonen that you can use when you are testing your game. You can use it to automatically test Inform’s built-in actions on all the objects in the area, for example, to make sure the responses all make sense.

  • You might find that you can save yourself some work by grouping some actions together. For example, pull, push, and turn are separate actions by default, but if there are no meaningful distinctions in your game between whether you pull, push, or turn something, you could, for instance, redirect two of those actions to the third.

  • There might be some actions you don’t use in your game at all, and you can save yourself some work by writing one response to deal with all attempts to use with that action, like “You don’t need to look under things in this game,” or disabling the action altogether (if it’s a less-commonly-used action, and removing it is unlikely to frustrate players).

  • You can make it so that all things in the game are either “far” or “near,” but “near” by default, so that you can easily write rules to deal with attempts to interact with “far” things. So instead of writing one rule to deal with the player trying to take the sky, and another rule dealing with the player trying to tie the dollar bill to the sun, you can write rules dealing with all “far” things, like

Before doing something when the second noun is far and the action requires a touchable second noun:
 	Say "[The second noun] [are] out of reach." instead.
  • When you are testing your game, in each location, try to interact with each noun that is mentioned in the room description. So if the room description mentions apple trees, a stream, flowing water, distant mountains, etc., type “x apple,” x “trees,” “x stream,” “x flowing water,” “x distant mountains” to make sure they are all understood. You don’t necessarily have to have separate responses for each thing–both “x apples” and “x trees” could lead to the same response about apples hanging from the trees–but the point is that the game should recognize every noun that’s mentioned in the text.

  • If you have a hard time getting a particular piece of code to work, and you finally get it to work, I suggest putting a comment on it to remind yourself why you did it that way. Otherwise, you might come back to it later, forgetting why you did it that way, and think to yourself, “Hmm, why don’t I just do it [way that doesn’t work] instead–that would be better!” and break it again.

  • You can use parentheses to help keep complicated conditions straight. I think I got this tip from Welcome To Adventure: A Quick-Start Guide to Inform 7 - Sibyl Moon Games.

  • If you want to keep track of what changes you’ve made over time, version control can be helpful. Version control with Mercurial and Tortoise HG - Sibyl Moon Games

  • I suggest trying to make responses to failed attempts helpful. For example, if a player tries something that makes sense, but is not quite right, it would be good to nudge the player in the right direction.

10 Likes

Extensions are the easiest way to slap up polish with little to no effort. I recommend perusing them and making note of any that may be of use.

Also, protip, if an extension hasn’t been updated but you still really want to use it, you don’t have to chase the extension author down or figure out how to fix it yourself. You can just roll your Inform version back to the last one that extension worked with. All the old versions are available for free download.

2 Likes

To this end, I often leave in, but comment out, code for failed attempts at doing something – along with additional comments describing why or in what way it didn’t work – to keep me from trying it again at a later date.

4 Likes

This is a really helpful response that gives a lot to go on - thanks! Some of this I’ve found myself doing already from time to time, but a more methodical approach (possibly involving some kind of spreadsheet) might go a long way towards making the world feel complete.

2 Likes

IMHO the best practice is exploiting to the hilt one of I7/10’s strong point, that is, the division in volumes, chapters, parts, etc. of the source code, whose allows easy organisation of the source, dispensing with the need of multiple files for large and very large files.

as working example, I could have posted the contents index of my current major WIP in inform 10 (whose sorely need some love, because I’m concentrating on the other major WIP, written in TADS3), for showing my source organisation in books, volumes &c. but for reasons known only to Lord Inform and/or the devs of the GUI, said index, can’t be cut’n pasted…

Best regards from Italy,
dott. Piergiorgio.

3 Likes

Peruse (and bookmark) the I7 Documentation and Resources post.

7 Likes

The example “Bumping Into Walls” shows how to list exits: 6.9. Going, Pushing Things in Directions (ganelson.github.io)

To make “exits” its own command, you’d add something like

Listing exits is an action out of world.
Understand "exits" as listing exits.

And where the “Bumping Into Walls” example says “Instead of going nowhere,” you would substitute “Report listing exits” or “Carry out listing exits” or something like that.

5 Likes

There’s certainly a lot of useful stuff here - I’ve already found an example of the volumes/chapters/etc. that @Piergiorgio_d_errico describes (and which I’ll definitely be using to break up my next game) - but is there any chance you’d be happy to pick out one or two things that you’d consider particularly useful to a relatively new author? That post itself is just shy of 3,000 words long, and it consists almost entirely of links to other resources: I’m most interested in finding out what key details/features someone well familiar with Inform7 might consider essential for any game, but a newcomer might simply not know to add.

3 Likes

This is a general programming rule: design for reuse. For instance, I needed a self-closing door, so I wrote one for my game. But wait - might I want that somewhere else? Okay, make self-closing doors a kind of door rather than a particular door. But maybe I want to have multiple kinds of doors, for instance one that self-closes from one side and is always locked on the other. Now we want to roll everything out of our game into a separate extension. Pretty soon you have your own collection of extensions that you can just slot in when you need them.

5 Likes

To this end, an Inform-specific code addition for giving players this functionality without it costing a turn can be found in §17.21. Understanding mistakes:

Understand "* [text]" as a mistake ("Noted.").
6 Likes