Let's Play/Read: Inform 7 manuals (Done for now)

Mike Spivey is the author of A Beauty Cold and Austere, which contains the Sieve of Eratosthenes as a puzzle, and also Junior Arithmancer, which is an arithmetic-heavy IF game. I referenced him in the arithmetic chapter, and he responded somewhere a few dozen posts upthread.

1 Like

Ahh, right, our own Mike Spivey! I thought you were referencing a textbook author or the like.

1 Like

Constant lists are arrays. Mutable lists are, hm, I think they’re stored as “arrays” in a block, but blocks are linked lists? So there’s linked-list behavior, but at a lower level.

If you insert (or delete) an item at the front of list, it has to do the array thing of shifting every item forward (backward) by one.

1 Like

Chapter 22: Advanced Phrases

This is one of the smallest chapters: only 10 sections, and I think only a single example (but I’m wrong almost every time I guess).

Section 22.1 is A review of kinds. We’re going to go meta, so we need to know the four components of kinds:

  1. Base kinds:

object, number, real number, time, truth state, text, snippet, Unicode character, action, scene, table name, equation name, use option, action name, figure name, sound name, external file, rulebook outcome, parser error

With a couple of more hidden ones like ‘verb’ and then any the player made up.

  1. Constructions:
    list of K
    description of K
    relation of K to L
    K based rule producing L
    K based rulebook producing L
    activity on K
    phrase K → L
    K valued property
    K valued table column

Already we can make complex things like:
phrase (phrase number -> (phrase number -> number)) -> nothing

  1. Variables
    We can include variable names in our construction of new kinds:

To hunt for (needle - value of kind K) in (haystack - list of Ks): ...

(Huh, that actually compiles, with a ‘do nothing’ thrown underneath it. I thought it was just placeholder text, but apparently inform takes in a variable that’s a kind and understands its plural automatically!)

Section 4 is Kinds of kind:

value, arithmetic value, enumerated value, sayable value
These aren’t technically kinds, and are only used in matching like this:

To announce (X - sayable value): say "I declare that [X] has arrived."

  1. is Secret Inner Workings, which is stuff used with inline Inform 6 definitions.

Section 22.2 is Descriptions as values:

(This is the kind of section I always skipped due to intimidation. I am only reading this due to self-imposed social pressure)

Here we are referring to Descriptions in the Ch. 6 sense. If you have a description D (like ‘all closed lockable doors’), you can use it in constructions like these:

say "You gaze mournfully at [the list of D].";
let the tally be the number of D;
let the surprise prize be a random D;
repeat with item running through D:

It turns out that you can actually make a variable D and make stuff like that run! the kind of D would be ‘description of objects’ or ‘description of numbers’, etc.

So you can do stuff like this:

To enumerate (collection - a description of objects):
    repeat with the item running through the collection:
        say "-- [The item]."

or if you use a name that sounds goofy (the above makes it sound like the names ‘enumerate’ or ‘collection’ matter):

To exhaustively-detail (MyHeapOfJunk - a description of objects):
    repeat with the item running through MyHeapOfJunk:
        say "-- [The item]."

If you have a description (like ‘even numbers’) you can check if something matches that description:

if 4 matches D, ...

Example 438 is Curare:

To decide which thing is cyclically random (collection - a description of objects):
    let choice be the oldest member of the collection;
    now the last use of the choice is the turn count;
    decide on choice.

A thing has a number called the last use. The last use of a thing is usually 0.

Definition: a thing is old if its last use is 12 or less.

This is a powerful tool, it seems like to me, the ability to customize things like ‘a random such and such’.

Section 22.3 is Phrases as values

Now this is meta: a phrase can itself be a value, so you can have phrases applying to phrases!

Given a Phrase F, you can get inputs out of it, like:
apply F to V;

or

apply F to V and W

or even

Apply F

depending on how many inputs something has.

The number of inputs depends on its ‘kind’. So To decide which text is (T - text) repeated (N - a number) times: ... has kind phrase (text, number) -> text so we could apply that to two inputs.

We haven’t had an example yet of how to name a phrase; I tried something like P is always the phrase To beat up the player, and then I defined the phrase To beat up the player, and it compiled but made P into an object that wasn’t a phrase and wouldn’t let me apply it. So I hope we see later how to name phrases.

Section 22.4 is Default values for phrase kinds.

You can say something like this:

let S be a phrase numbers -> nothing;

This will create a phrase S which by default does nothing. For a phrase K → L, the default value is just the default value of L.

Here is an amusingly absurd example, in a game where ‘colours’ are a kind with ‘red’ as the default:

let R be a phrase numbers -> (phrase numbers -> colours);
showme R;
showme R applied to 3;
showme (R applied to 3) applied to 2;

which produces the following:

"r" = phrase number -> (phrase number -> colour): default value of phrase
number -> (phrase number -> colour)
"r applied to 3" = phrase number -> colour: default value of phrase number
-> colour
"( r applied to 3 ) applied to 2" = colour: red

Section 22.5 is Map, Filter, and reduce. We still haven’t learned how to name phrases, just make blank ones with names or have unnamed ones that do things.

This section explains how instead of using for loops, you can use a modern approach of Mapping, Filtering, and Reducing (I’m not part of language discourse, although I followed a C++ professor on Twitter once who was, so I’m not really aware this).

Mapping plugs a list of things into a function (or, in our case, a phrase):

To decide what number is double (N - a number) (this is doubling):
    decide on N plus N.

doubling applied to {2, 3, 4}

So you just ‘apply’ to a list of values of the correct kind.

You can also chain these functions:

To decide what text is the longhand form of (N - a number)
    (this is spelling out):
    decide on "[N in words]".

To decide what text is the consonant form of (T - text)
    (this is txtng):
    replace the regular expression "<aeiou>" in T with "";
    decide on T.

txtng applied to spelling out applied to doubling applied to {3, 8, 4, 19, 7}

Anyone used phrases applied to lists in their own code? I haven’t (didn’t know this stuff yet).

Now we can filter; given a description, you can restrict a list to things fitting that description:

filter to even numbers of {3, 8, 4, 19, 7}

which outputs {8,4}.

You can combine filtering and mapping/applying:

Definition: a text (called T) is lengthy if the number of characters in it is greater than 6.

let L be the filter to lengthy texts of spelling out applied to {15, 2, 20, 29, -4};
showme L;

which produces {"fifteen", "twenty-nine", "minus four"}.

Finally, there is reduction, which collates the resulting list into a single response of some kind:

To decide what number is the larger of (N - number) and (M - number)
    (this is maximization):
    if N > M, decide on N;
    decide on M.

To decide what text is the concatenation of (X - text) and (Y - text)
    (this is concatenation):
    decide on "[X][Y]".

let X be the maximization reduction of {3, 8, 4, 19, 7};
let Y be the concatenation reduction of txtng applied to spelling out
    applied to doubling applied to {3, 8, 4, 19, 7};

sets X to 19, the highest of the values, and Y to the text “sxsxtnghtthrty-ghtfrtn”

Oh ho! I just noticed (though we did it earlier) that this is how we name phrases! The word ‘reduction’ here isn’t part of the phrase name, you add it after the phrase name when using phrases of the form (value, value)->value, and it works through the list doing that operation repeatedly, first to the first two, then the result of that and the third.

Man, has anyone ever used ‘reduction of’? It seems to have been put in place to satisfy proponents of functional programming:

Is map/filter/reduce always a good idea? Devotees point out that almost any computation can be thought of in this way, and in systems where the work has to be distributed around multiple processors it can be a very powerful tool. (There are programming languages without loops where it’s essentially the only tool.) At its best, it reads very elegantly: one assembles all of the tools needed - definitions of doubling, lengthy, spelling out, concatenation and so on - and then each actual task is expressed in a single line at the end.

Section 22.6 is Generic phrases:

To say (V - value) twice: say "[V]. [V], I say!"

How does this work? V is a value, not a kind! It’s too generic!

But it does indeed work; it basically creates a different phrase for each input. I got this supremely dumb program to run:

To say (V - value) twice: say "[V]. [V], I say!"

When play begins:
	let S be a phrase nothing -> nothing;
	say S twice;

The kinds index tells you if something counts as a ‘value’ or a ‘sayable’ value, etc:

image

(only ‘top level’ kinds have this, and since most player-made kinds are things, you won’t see this until you scroll to the top of ‘things’ or past it.

Section 22.7 is Kind Variables:

You can have a phrase with a kind that takes in a value and returns nothing (just doing its own code):

To triple (V - arithmetic value): say "[V times 3]."

But if you want to return it, you need to know what to return, and we can’t use kinds, since ‘value’ matches all sorts of kinds. So we use the word ‘original’:

To decide which K is triple (original - arithmetic value of kind K):
    decide on 3 times the original.

Here’s another example:

To decide what list of L is (function - phrase K -> value of kind L)
    applied to (original list - list of values of kind K):
    let the result be a list of Ls;
    repeat with item running through the original list:
        let the mapped item be the function applied to the item;
        add the mapped item to the result;
    decide on the result.

(I’m really kind of getting lost here so I’m not commenting much)

Note also the way that the temporary variable “result” is created:

let the result be a list of Ls;

Ordinarily, of course, “L” is not a kind. But within the body of a phrase definition, it means whatever kind L matched against.

These things both compile:

To hunt for (V - value of kind K) in (L - list of Ks): ...
To hunt for (V - K) in (L - list of values of kind K): ...

but apparently behave differently if V is not the same kind as the list but can be used as if it were (like a snippet, which can be used as a text).

So, sorry for all those authors out there who yearned for uniqueness in definition of phrases of the kind
phrase (K, list of Ks) -> nothing

(btw those two examples with K’s and L’s compile if I put ‘do nothing’ after them but not if I name them, even if I only name one and delete the other, so that this gives an error):

To hunt for (V - value of kind K) in (L - list of Ks)
	(this is hunting):
	do nothing;

But deleting ‘this is hunting’ or changing the inputs to normal things like ‘numbers’ gets rid of the error.

Section 22.8 is Matching the names of kinds:
This is for when you have a name of a kind as an input and your going to repeat through it: if your kind isn’t repeatable, you’ll get an error.

For instance:

To assay (name of kind of value K):
    repeat with item running through Ks:
        say "There's [item].";
    say "But the default is [default value of K].";

works well with assay vehicles but fails with assay numbers and descriptions that aren’t kinds (like assay open doors)

Man, this chapter is right where it belongs: at the end of the coding section! It’s obscure and not super practical. Although this particular assaying example could be useful for debugging.

Section 22.9 is In What Oder? which already looks like a section I’d like to skip.

Oh I see, it asks, if the player defines a phrase twice, which one fires?

  1. More specific ones fire first
  2. If both are equally specific, the later-defined one is fired
  3. If one phrase is used in the definition of the other, then it comes before what it’s used in.

Finally, Section 22.10: Ambiguities!

What if for some reason you thought it was fun to define two almost-identical phrases like this:

say the (something - a thing)
say (something - a thing)

and you have this line:

say the dishcloth;

Which phrase fires? The one that has the most words (say the (...))

And that’s it for most programming stuff! The rest is like multimedia, debugging, etc., with I think some heavy I6 stuff in the extensions chapter.

1 Like

Here’s a collection of vagueries the compiler accepts, some of which surprised me:

To x0 (v - value): say "".
To x1 (r - relation): say "".
To x2 (r - rule): say "".
To x3 (r - rulebook): say "".
To x4 (ac - activity): say "".
To x5 (L - list of values): say "".
To x6 (p - property): say "".
To x7 (tc - table column): say "".
To x8 (dv - description of values): say "".
To x9 (n - name of kind of value): say "".

[with I6 inclusion only ]
To y0 (p - phrase): (- 0; -).

Regarding chapter 22, I haven’t really had an occasion to use the more abstract constructs in an actual IF project, but just recently I used the method from 22.8. Matching the names of kinds in a small example:

[...]

A car is a kind of vehicle.

A sedan is a kind of car.
A convertible is a kind of car. 

[...]

To paint (name of kind of value K):
	let palette be the list of colours;
	sort palette in random order;
	repeat with paint-target running through Ks in the carpool:
		now the colour of paint-target is entry 1 of palette;
		remove entry 1 from palette;
        
When play begins:
	paint sedans;
	paint convertibles;

There are doubtlessly other ways to do this, but I felt it made for relatively compact, yet readable code, and it’s very easy to add further kinds of car, like SUVs, hatchbacks, etc., without having to change or duplicate much code.

(In the particular example, I wanted each sedan (etc.) to have a unique colour, but didn’t want to simply paint all cars in one go, because I wanted to re-use colours for different types, so we can have a red sedan and a red convertible, for example.)


These threads have some further examples of how the techniques from chapter 22 might be used:

4 Likes

This appears in the next example (and you discuss it a bit later down), but just to make it explicit:

To foo the bar (this is fooing):

The “this is ___” note is how you give a name to a phrase. To pass that phrase around as a value, you use that name.

Never. But it’s one of those things that’s straightforward-but-tedious to implement given the tools provided, so the standard library might as well do it for us.

The important isn’t the word “original” (you could also call it “V” or “foo” if you wanted)—the important part is that, instead of its type being “value”, its type is now “value of kind K”. This binds “K” to the type of the argument, so you can specify that the phrase returns a “K” and everything is good.

Or in C++ terms:

template<typename K>
K triple(K orig){ return 3*orig; }

This time, the parameter is of type “phrase K → value of kind L”, which binds the types K and L. For the purpose of this one phrase, “K” and “L” are valid names of kinds. Which means “list of L” is also a valid kind, and we can return it.

For a practical example, here’s the only time I’ve ever used descriptions as arguments, or parameterized kinds:

To print a/the/-- list of (T - text) for (D - description of values of kind K), prefacing with is/are and/or disjunctive:
	let N be the number of D;
	if prefacing with is/are:
		say "[if N <= one]is[else]are[end if] ";
	if N is zero:
		say "nothing";
		stop;
	let J be 1;
	push the listing parameter;
	repeat with V running through D:
		set the K being listed to V;
		say T;
		if J is N: [Final one]
			next;
		else if J is N minus 1: [Second-to-last]
			if N > 2 and the serial comma option is active: [Only print a serial comma if there are three or more items]
				say ",";
			say " [if disjunctive]or[else]and[end if] ";
		else: [Any other]
			say ", ";
		increment J;
	pull the listing parameter.

In other words, this is a way to write a nice list of any kind, not just things! I need the argument to be specifically a “description of values of kind K” to bind K, so that I can do things with K variables in the code.

What do I do with those K variables? Well:

To decide which K is the (name of kind of value K) being listed: (- listing_parameter -).
To set the (name of kind of value K) being listed to (V - K): (- listing_parameter = {V}; -).

Type-safety? What’s that? Here we’ve got some horribly unsafe casting: we can stick a value of any kind into a global variable (with “set the [name of K] being listed to [value of kind K]”) and read any kind out of it (with “the [name of K] being listed → K”). Use it responsibly.

3 Likes

Chapter 23 Figures, Sounds and Files

I’ve added sound and music to Quixe before, but only by manually editing the javascript files, never by using Inform’s default stuff. So I’m going to experiment along with this stuff.

Section 23.1 is Beyond text. It just says that if we use Glulx we can add files to things.

Section 23. 2 is How IF views pictures. This is just talking about cultural expectations around IF games and graphics.

In the cultural history of IF, graphics in text adventures have sometimes been looked at with suspicion. Mostly this is because attempts in the 1980s were not very successful, because computer graphics were so poor then (by modern standards). It may be that some people also felt that the takeover of computer games by graphical interfaces was the death knell of IF. But pictures are now rendered in superb quality by computers, and the death of IF turned out to be an exaggeration, so it is time to move on

I’ll admit, I’m not at all a fan of graphical adventure games more than others. I think adventure games can be fun (I really loved the Indiana Jones Atlantis game as a kid) but I have no desire to play Monkey Island or stuff like this. I like the text part of text games, not the world model and puzzles.

The section goes on to suggest hiring artists if you suck at art and that some devices can’t display images or have varying resolutions or color ranges.

Section 23.3 (No examples, this is all talk so far) says that IF story files are complex documents, not like pdfs or photographs. It says that a story file is itself a program for a virtual machine, which runs in the interpreter. (I always thought of the interpreter as the VM, but that’s because I don’t know the nitty gritty).

The last note is that some formats can incorporate images, while others can’t.

Section 23.4 is Gathering the figures.

First, we must use Glulx.

Inform calls pictures ‘figures’.

You have to put them in the Materials folder for your project in the Figures folder (creating one if there isn’t one yet).

For educational purposes, I will use the following public domain image for when the player attacks:

Section 23.5 is Declaring and previewing the figures.

With the images in the right folder, we name them like so:

Figure of Woodlands is the file "Woodlands.png".
Figure 2 is the file "Red Admiral Butterfly.png".

So I’m going to make

Figure of attack is the file "bam.png".

It should show up in the ‘Figures’ tab in the index (another tab I didn’t know existed until today! I should look at all of them some time):

image

Section 23.6 is Displaying the figures.

We can display images. It treats it just like text in that you can scroll away. To divide up the screen and use permanent images, you need fancy Glulx stuff.

To just print the image, we need to say:

display the Figure of Woodlands;

Or, in other words for my example:

display the figure of attack;

Let’s try it out:

The sandbox is a room. The mannequin is in the sandbox.

Figure of attack is the file "bam.png".

Instead of attacking something:
	display the figure of attack;

Man, that’s way too big! I’d need to edit that file size. Let’s resize it (not using inform) and recompile and try again:

image

Okay, that’s better.

Section 23.7 is Recorded sounds.

It warns us:

Sound support is very newly added to the system and work is still in progress. In particular, sounds are not played by Inform for OS X (although it does produce valid blorbed Glulx story files), though they should be audible from within the Inform application for Windows.

We have to use Glulx and not all interpreters support it.

Speaking of which…let’s try our ‘bam’ program in other interpreters first!

Works in gargoyle:

image

If I ‘release along with an interpreter’ and click ‘play.html’ and attack, it doesn’t show up:

image

Hmm, that must be why I ended up hacking my own stuff for the Inform version of Swigian. I know Brain Guzzlers from Beyond put images into Glulx that worked; how did Steph Cherrywell do that?

Anyway back to music, we hae to use AIFF (uncompressed, huge) or Ogg Vorbis. That was to avoid copyright issues for MP3, but I think MP3 is legal to use now after a copyright dispute (but I wouldn’t rely on that info, I just remember really worrying about it 5 years ago).

It then says not to pirate copyrighted music and that music won’t even play on Macs when using Inform 7’s built-in interpreter.

Section 23.8 is Declaring and playing back sounds.

We make a ‘Sounds’ folder in materials and download the sound. I’m using a dial up ogg vorbis sound from Wikimedia, so I also declare this in my code:

Sound of internet is the file "Dial_up_connection.ogg".

This is my figures Index:

image

That’s not promising!

Then we play it:
play the sound of rustling leaves;

I’ll try:

Instead of thinking:
   play the sound of internet;

It works! Both in my Inform 7 interpreter and in Gargoyle.

What about Quixe?

Nope, just says Sound effect number 4 here.

But I have a way to hack music into Quixe. You can check it out by loading my game Absence of Law here and typing ‘sou’:

https://media.textadventures.co.uk/games/wBrLVx-dkUa3_ER_VEQQBg/AbsenceOfLaw/index.html

Section 23.9 is Providing Accessibility text. This is just alt text, and it’s like so:

Figure 2 is the file "butterfly.jpg" ("A red admiral butterfly.").
Release along with cover art ("A cathedral at sunset.").
Fugue is the file "Bach.ogg" ("A church organ playing a Bach fugue.").

Alas, despite adding alt text to my sound, Quixe still just says ’
image

when it plays, even though I specified:
Sound of internet is the file "Dial_up_connection.ogg" ("An old moden dialing up").

Of course Vorple does all these things very well! (but my version does run in an offline local version of the html interpreter).

Section 23.10 is Some technicalities about figures and sounds

Kinds are important in Inform, and names for figures have the kind ‘figure name’. You can use this for variables:

The turn card image is a figure name that varies.

An Old Master is a kind of thing. An Old Master has a figure name called appearance. Figure 1 is the file "Giaconda.jpg". The Mona Lisa is an Old Master. The appearance of the Mona Lisa is Figure 1.

To place (F - a figure name) in the gallery: ...

Sound names have the value ‘sound name’.

In the blorb, things have internally given resource IDs. You can find them with the phrase ‘Glulx resource ID of (figure name)…number’.

And the following mysterious text:

(iv) Glulx hackers may also like to know that whenever Inform 7 builds a project for Glulx, the Inform 6 code it generates always contains a full copy of John Cater’s definitive header file “infglk.h”.

Section 23.11 is Files. It says that Inform files are run in a sandbox, which means it can’t infect the computer through malware. A Z-code game can’t affect any other files at all. But Glulx allows reading and writing to data files, basically like browser cookies.

Section 23.12 is Declaring files.

You declare a file like this:

The File of Glaciers is called "ice".

You can do this even before the file exists.

Filenames should follow these rules:

Quoted filenames should contain only letters and digits, should be 23 characters or fewer, and should begin with a letter. (In particular they can contain no slashes or dots - no subfolders or extensions can be indicated.) The actual filename this translates to will vary from platform to platform, but “ice.glkdata” is typical, stored in some sensible folder.

Each file has an ‘owner’, but you can declare that the file is owned by a different project:

The file of Boundaries (owned by another project) is called "milnor".
The file of Spectral Sequences (owned by project "4122DDA8-A153-46BC-8F57-42220F9D8795") is called "adams".

(We use the IFID to specify the owner, with the IFID given by typing VERSION during play or looking in Contents index, under the Card.)

I’m declaring the following:

The file of Amusing Deaths is called "lolfile".

And I get this in my figures index:
image

My ‘File of Amusing Deaths’ has a kind of value called ‘external file’. We can use text files or binary files. Binary files are declared as so:

The binary File of Glaciation Data is called "icedata".

I’m going to copy this into my project:

image

Section 23.13 is Writing and reading tables to external files.

Tables are focused on as everything else (mostly) can be contained in files. Here’s how we do it:

write File of Glaciation Data from the Table of Antarctic Reserves

All blank rows are ignored.

To load it back:

read File of Glaciation Data into the Table of Antarctic Reserves

you can check it with this:
if the File of Glaciation Data exists, ...

So I’ll try this out.

I’ll add commands for reading and writing to a file.

I’ll have a table of amusing deaths and a table of emptiness. One command will write the table of amusing deaths to an external file, and one command will load it into the table of emptiness and then print everything in that table.

If I try to load before writing, I get this reasonable error:

image

(I could have avoided this by checking if the file was empty)

Trying to write, though, gives me this error:

image

This was my code:

The File of Amusing Deaths is called "lolfile".

The binary File of Glaciation Data is called "icedata".

Table of Stuff
object	name
mannequin	"The mannequin punches you back!"


Table of Emptiness
object	name
--	--

Instead of jumping:
	write File of Amusing Deaths from the Table of Stuff;
	
Instead of going nowhere:
	read File of Amusing Deaths into the Table of Emptiness;
	repeat through the Table of Emptiness:
		say name entry;

So I think maybe having an object is bad? I’ll try to make it just text.

That works with no error for writing. Now to try loading:

image

(sorry the examples are nonsensical, I just wrote whatever popped in my brain).

Hmm, pretty neat! I wonder if this is the technique @Afterward uses for saves for his Fly Fishing game.

Now we have 3 examples!

Example 439 is Alien Invasion Part 23

Carry out selecting difficulty:
    choose row 1 in the Table of Preference Settings;
    now challenge level entry is difficulty understood;
    say "Puzzles will be [challenge level entry] from now on."

The File of Preferences is called "prefs".

When play begins:
    if File of Preferences exists:
        read File of Preferences into the Table of Preference Settings;
        choose row 1 in the Table of Preference Settings;
        say "(The current puzzle difficulty is set to [challenge level entry].)"

Check quitting the game:
    write File of Preferences from the Table of Preference Settings.

Table of Preference Settings
challenge level
easy

Example 440 is Labyrinth of Ghosts

Table of Ghostly Presences

haunted position score at death turns at death manner of death sequence
a grid location a number a number a demise a number
with 19 blank rows.
To have the player (sticky end - a demise):
    let the new sequence number be 0;
    repeat through the Table of Ghostly Presences:
        let S be the sequence entry;
        if S is greater than the new sequence number, let the new sequence number be S;
    increment the new sequence number;
    if the number of blank rows in the Table of Ghostly Presences is 0:
        choose row 1 in the Table of Ghostly Presences;
        blank out the whole row;
    choose a blank row in the Table of Ghostly Presences;
    now the sequence entry is the new sequence number;
    now the manner of death entry is the sticky end;
    now the turns at death entry is the turn count;
    now the score at death entry is the score;
    now the haunted position entry is the coordinates of the location;
    write the File of Ghosts from the Table of Ghostly Presences;
    now the latest demise is the sticky end;
    end the story saying "You have been [latest demise]".

The File of Ghosts is called "ghosts".

When play begins:
    if the File of Ghosts exists, read File of Ghosts into the Table of Ghostly Presences;
    sort the Table of Ghostly Presences in sequence order.

After looking:
    repeat through the Table of Ghostly Presences in reverse sequence order:
        if the haunted position entry is the coordinates of the location, say "You sense the ghostly presence of an adventurer, [manner of death entry] with a score of [score at death entry] in [turns at death entry] turns."

So all your previous deaths stick around permanently. Reminds me of Undertale, remembering what you do unless you delete the game (or DDLC, which I haven’t played).

Example 441 is Rubies, with a scoreboard:

When play ends:
    choose row 10 in the Table of Leaders; [we've sorted the table, so the lowest score will be the one at the bottom]
    if the score is greater than scored amount entry:
        now name entry is the player's forename;
        now the scored amount entry is the score;
    show leaderboard;
    write the File of Leaderboard from the Table of Leaders.

To show leaderboard:
    sort the Table of Leaders in reverse scored amount order;
    say "Current leading scores: [paragraph break]";
    say fixed letter spacing;
    repeat through Table of Leaders:
        if scored amount entry is greater than 0:
            say " [name entry]";
            let N be 25 minus the number of characters in name entry; [here we want to space out the scores so they make a neat column]
            if N is less than 1, now N is 1;
            say N spaces;
            say "[scored amount entry][line break]";
    say variable letter spacing.

To say (N - a number) spaces:
    repeat with index running from 1 to N:
        say " ".

There is a table of leaders too that isn’t copying to here nicely.

Section 23.14 is Writing, reading, and appending text to files.

This just erases a declared file and puts text in it:

write "Jackdaws love my big sphinx of quartz." to the file of Abecedary Wisdom;

If we don’t want to erase, we can just add more to a file (or create it if it doesn’t exist):

append "Jinxed wizards pluck ivy from the big quilt." to the file of Abecedary Wisdom;

This text can contain substitutions and be long.

To read it back, just put the following:

"[text of the File of Abecedary Wisdom]"

You can even copy one file to another:
write "[text of the file of Abecedary Wisdom]" to the file of Secondary Wisdom;

Example 442 is The Fourth Body:

A jotter is a kind of thing. A jotter has an external file called the text file. A jotter can be fresh or used. A jotter is usually fresh. A jotter has a text called the heading.

The currently erased jotter is an object that varies.
To erase (pad - a jotter):
    now the currently erased jotter is the pad;
    write "[heading of the currently erased jotter][paragraph break]" to the text file of the pad;
    now the pad is fresh.

To write in (pad - a jotter):
    append "[the time of day]: [topic understood][line break]" to the text file of the pad;
    now the pad is used.

To read (pad - a jotter):
    say "You read: [paragraph break][text of the text file of the pad]".

Example 443 is similar but with slight variations in how writing down things is handled. Since I didn’t copy that part of the code for the first example, I won’t here either.

Section 23.15 is Exchanging Files with other programs.

To avoid writing into an in-use file, we have a condition called ‘ready’.

if ready to read the file of Invariants, ...

How do we know something is ready? If we used the following phrase:

mark the file of Invariants as ready to read;

(by the way, I tried out the file writing in Quixe and it actually worked! I couldn’t find where it was storing it; cookies? Local storage?)

We can also mark things as not ready to read:

mark the file of Invariants as not ready to read;

These commands let us use non-Inform programs to communicate with Inform! Pretty wild. To do that we need to know some details which are in this section but which I will not copy, basically adding a cool header to the file encoded in ASCII Latin-1.

Example 444 is The Flathead News Network, which uses a background Perl script to fetch real time RSS headlines that update whenever the player looks at the news! Pretty wild stuff, I recommend checking it out.

1 Like

For my project, I included three different resolutions options for each image and let the player pick one. There are some surprising differences in the way images appear in different interpreters. :frowning:

2 Likes

Remember that files can be exchanged between games! (Or between different versions of the same game.) So the rule of thumb is, you can only read and write values that will make sense to a different Inform game. Numbers are fine, text is fine, objects are not—what if the other game doesn’t have the same object, or even any object at all, at that memory address?

This also applies to rules and phrases, though I have no idea why you’d try to save those to files.

If you don’t need the file to be compatible with other versions of your game (which might change memory addresses around), you can circumvent Inform’s type-checker and save objects anyway:

To decide what number is (O - object) serialized: (- {O} -).
To decide what object is (N - number) unserialized: (- {N} -).

But the easier way is just to give objects some property that’s guaranteed to be unique (and stable between versions) and store the value of that property instead. That’s what the ghosts example does with the room coordinates.

3 Likes

Chapter 24: Testing and Debugging

Section 24.1 Checking against the Index

This section says the index is a convenient way to check if you defined things correctly, like forgetting to make something scenery or accidentally creating two of an item.

I traditionally relied on custom things to do this (like printing out the description of every item), but working through this book has shown me how useful the Index is.)

Section 24.2 is Debugging features to use in source

The TEST command is great. I use this all the time to ensure that my game is still completable after changes.

You make new test commands like this:

Test me with "up / kill captain eo".
Test eo with "zap eo" holding the ray gun.
Test dinner with "eat bread / eat soup / eat butter" in the Ship Cafeteria.

Then you can start the game and type TEST ME or TEST EO, etc.

You can also merge tests:
Test megatest with "test me / test eo".

We can also use ‘showme’ in the middle of phrases to see what’s going on:

To say key score:
    let count be the number of keys which are not carried by the player;
    showme count;
    if count is greater than 2 and the player is timid:
        say "You're still missing a lot of keys, bucko!"

I’ve only recently started using SHOWME in this way; I previously would print out stuff like 'The current action is [current action]", or pretty often (I know this is stupide and childish) ‘say “poop”;’, since I knew I’d have to delete that (sorry if that stuck around in any of my games!)

Section 24.3 is High-level debugging commands

This includes SHOWME as an in-game command, which lists tons of stuff like this:

>SHOWME BAT
bat - thing
location: on the table in Locker Room
singular-named, improper-named; unlit, inedible, portable, patterned
printed name: "bat"
printed plural name: none
indefinite article: none
description: none
initial appearance: none

Another useful command I only learned about recently is ACTIONS, which gives output like this:

>ACTIONS
Actions listing on.

>JUMP
[jumping]
You jump on the spot.
[jumping - succeeded]

Something I’ve used for a very long time is RULES, which announces all rules which are running:

>RULES
Rules tracing now switched on. Type "rules off" to switch it off again, or "rules all" to include even rules which do not apply.

>JUMP
[Rule "announce items from multiple object lists rule" applies.]
[Rule "set pronouns from items from multiple object lists rule" applies.]
[Rule "before stage rule" applies.]
[Rule "instead stage rule" applies.]
[Rule "investigate player's awareness before action rule" applies.]
[Rule "player aware of his own actions rule" applies.]
[Rule "check stage rule" applies.]
[Rule "carry out stage rule" applies.]
[Rule "after stage rule" applies.]
[Rule "investigate player's awareness after action rule" applies.]
[Rule "report stage rule" applies.]
[Rule "report jumping rule" applies.]
You jump on the spot.
[Rule "last specific action-processing rule" applies.]

[Rule "A first turn sequence rule" applies.]
[Rule "every turn stage rule" applies.]
[Rule "A last turn sequence rule" applies.]
[Rule "notify score changes rule" applies.]
>

This is very useful in helping to track down problems. For some stuff though it doesn’t print anything, which always frustrated me until I learned (recently) that they are activities, which sadly don’t have an ACTIVITIES command.

Similarly, we have SCENES, which keeps a running list of scenes that are starting, running, or stopping.

RELATIONS and RESPONSES respectively print out all relations (I’ve never used this) and all responses (I use this a ton to figure out what responses to change!)

Finally, RANDOM sets the random generator to a specific seed, which lets the player avoid randomness in testing.

Section 24.4 is Low-level debugging commands

This is stuff like PURLOIN, ABSTRACT, and GONEAR, which respectively move something to the player (purloin sandwich), move something as direction (abstract sandwich to table), and move the player to the location of the object (gonear sandwich).

You can get runtime errors if you type dumb stuff into this.

You can also build-in some of this stuff into testing commands:

Test me with "eat grain" in the Fertile Plain.
(This puts the player in Fertile Plain immediately, like using GONEAR but with less computational power)

Similarly, Test me with "drop table" holding the table. puts the table in the player’s inventory.

VERIFY checks if the storyfile is intact, but it’s pretty rare to use.

TREE lists all object containment. I’ve used it occasionally to check for stray objects that were defined wrong (especially if I mistyped the name and made two of the object).

SCOPE lists objects in scope, which I’m just learning about now.

SHOWHEAP shows how many bytes are free.

TRACE, TRACE 2,…,TRACE 5 give increasingly more detailed info on what the parser is doing when it parses a line (and yet there’s no activity command; why not?)

Section 24.5 is Adding new testing verbs and release for testing

This is just like a brainstorming session for things to add, like jumping to different chapters, status information, and checking which puzzles are satisfied.

If you want testers to have access to testing commands that are pre-made or that you put in ‘not for release’ sections, you can compile Inform with ‘release for testing’, an option in the IDE.

Section 24.6 is Testing for thoroughness, which contains code like I described earlier (I must have borrowed it from here or someone else’s project years ago):

When play begins (this is the run property checks at the start of play rule):
    repeat with item running through things:
        if description of the item is "":
            say "[item] has no description."

It also suggests the Object Response Tests by Juhana Leinonen. I tried downloading it from th public library in the IDE but it doesn’t compile, failing on the phrase ‘try the test-actor taking [the noun]’ and all other similar phrases.

Section 24.7 is Commands for beta-testers:

This just describes the TRANSCRIPT and TRANSCRIPT OFF commands., which allows beta testers to print out their adventures in the game. I know a lot of comp judges like to send in transcripts too, and IFComp automatically records people’s transcripts when people use the default interpreter.

Section 24.8 is Help from the user community, suggesting that people go to th exotic website intfiction.org to get programming advice and find testers. Sounds weird to me.

3 Likes

The version in the Public Library seems to be version 6. Version 7 from the Friends of I7 Github repository should work, I think: extensions/Juhana Leinonen/Object Response Tests-v7.i7x at 10.1 · i7/extensions · GitHub

3 Likes

Thank you, I downloaded that it worked very well!

1 Like

Chapter 25: Releasing

This is a pretty hefty chapter, all about release options. I’ve used ‘with an interpreter’, ‘with a website’, ‘with source’, and that’s about it.

Section 25.1 is just saying that to actually play your game people need a file, to which we can attach things.

Section 25.2 Bibliographic data

Here is some stuff you can add to the general info of an Inform game:

The story title is "Mansfield Perk".
The story author is "Janet Austen".
The story headline is "An Interactive Romance".
The story genre is "Romance".
The release number is 7.
The story description is "In Miss Austen's new interactive novella, Miss Henrietta Pollifax is adopted by the tempestuous landowner Sir Tankerley Mordant, and must make a new life for herself on the rugged moors."
The story creation year is 2005.

We don’t have to explicity declare the story title and author. You can type

"Mansfield Park" by Janet Austen as the first line and that will set the title and author. We wrap the author’s name in quotations if it has punctuation in it.

The only text substitutions allowed are ['] and unicode.

Here are the defaults:

Story title: Untitled
Story author: Anonymous
Story headline: An Interactive Fiction
Story genre: Fiction
Release number: 1

Section 25.3 is Genres

These are the 'standard categories`:

Comedy, Erotica, Fairy Tale, Fantasy, Fiction, Historical, Horror, Mystery, Non-Fiction, Other, Romance, Science Fiction, Surreal

‘Comedy’ is suggested instead of humor do to British/American differences. ‘Other’ is intended for things that aren’t really narrative, like Tetris.

Section 25.4 is The Library Card

This is a metadata file that can be processed by some interpreters and other info. It’s placed in the blorb of a blorbed file (blorb is like a zip for a story file that contains the story file, library card, cover art, etc.)

Section 25.5 is The Treaty of Babel and the IFID.

The treaty of Babel was an agreement in 2006 to create a standardized system for identifying games with a number system. Twine, Inform, and TADS and Dialogue have ways of doing this (I think Dialogue just tells you to go to a website and pick an IFID).

The goal is for it to be unique, like an ISBN.

Section 25.6 is The Release Button and the Materials folder.

Pushing the Release button makes a folder at the same level as the .inform folder and calls the new folder .materials. The author is intended to put images, sounds, etc. in that materials directory.

Releasing creates a Release folder in the Materials folder that gathers everything together. For me at least, any project that’s more than a simple blorb file is uploaded to websites as the whole release folder zipped up.

Section 25.7 is The Joy of Feelies. Feelies refers to early Infocom physical materials that came in the boxed set, like little toys, maps, manuals, etc.

Nowadays ‘feelies’ are often pdfs or images, things like maps or poems or other things.

If you want a feely included in your release folder, you place it in materials first and then includes a line like this:

Release along with a file of "Collegio magazine" called "Collegio.pdf" and a file of "The mating call of the green wyvern" called "Mating Wyverns.mp3".

This gives a description and a filename for each file.

If the feelie is an html page, the convention is to create a folder with the name of the page you want and then put index.html in it.

Like this:

Release along with a file of "Baltrazar's Guide to Magic" called "Guide".

it is expected to sit inside a folder called “Guide”, with its home page being “Guide/index.html”.

Section 25.8 is Cover Art.

From my personal experience, Cover Art really helps with a game getting traction. One of my more popular games in terms of online plays in the last few years is The Magpie Takes the Train, which has excellent cover art that JJ Guest paid for.

Cover art will look best if created at 960 by 960 pixels, but should not be less than 120 pixels in either direction.

For Cover art, put a file called Cover.jpg or Cover.png in the materials folder, and add this kind of line:

Release along with cover art ("A cathedral at sunset.").

Section 25.9 is An introductory booklet and postcard

These two things are guides to how IF works. The introductory booklet is 8 pages long, written by Emily Short, that basically explains how to play a parser game.

The postcard is the same thing but smaller and written by Zarf and Lea Albaugh.

You can say stuff like:
Release along with cover art, the introductory booklet, a file of "Collegio magazine" called "Collegio.pdf" and a file of "The mating call of the green wyvern" called "Mating Wyverns.mp3".

or
Release along with an introductory postcard.

Section 25.10 is A Website.

This makes the standard website you may have seen if you’ve played parser games online, including in this comp. It looks like this:
image
And is created by adding Release along with a website.

(Note that the website alone doesn’t play the game; that’s next section).

Section 25.11 is A Playable web page.

You say Release along with an interpreter, which automatically adds the website too.

The two standard interpreters are Parchment for Z-code and Quixe for Glulx, although parchment also works for Glulx. If you want to use parchment with glulx (which I’ve never tried!) you say:

Release along with the "Parchment" interpreter.

(This brings back fond memories of when I started playing IF and played a lot of games using parchment on iplayif.com on an ipad).

If you have some super fancy interpreter, just put it into the templates subfolder of materials and say:

Release along with the "Urbzig" interpreter.

Section 25.12 Using Inform with Vorple

This section basically says Vorple is cool but has its own website:

Section 25.13 is Website templates

You can name templates for websites and use them. The standard one is called “Standard”, and the only other default one is “Classic”.

If you had a template called ‘platinum’, you could put it in the materials folder in Templates. Here’s where the compiler will look for it (in order):

(a) the "Templates" subfolder of the project's own .materials folder, if this subfolder should exist;
(b) the "Templates" folder in the user's own library - on Mac OS X, this is:
    ~/Library/Inform/Templates
or on Windows:
    My Documents\Inform\Templates
or on Linux:
    /Inform/Templates
(c) the built-in stock of templates, currently only "Standard" and "Classic".

The template should be a folder with the name you’re going to give in quotations, and should have one or more of these things:

Platinum
    index.html
    source.html
    style.css
    (extras).txt

I’d like to see new templates made! We need a library of these things! Man that would be cool!

The easiest template is like so:

Platinum
    style.css

Parser players should crowdfund some money to get people like @lizadaly or @Grim to use their CSS wizardry to make some cool templates.

Section 25.14 is Advanced website templates

The way to make templates is first, take any ‘extras’ like special pages or images and put them in the template folder, and make a file called (extras).txt that does nothing but list the extras like this:

easter.html
egg.png

(By the way, here’s what a game released with the ‘classic’ format looks like:)

Anyway, to make the template, you include index.html and source.html with placeholder text.

I only recently learned about this because Aaron Reed left behind a vast machinery for Spring Thing that includes website templates that get automatically filled by data from excel files using python scripts.

To make a template, you put a reference to the css at the top:

<link rel="stylesheet" href="style.css" type="text/css" media="all" />

And you can use what are essentially text substitutions in HTML to get stuff replaced, like this:

[TITLE] becomes the story title
[AUTHOR] becomes the author's name
[YEAR] becomes the story creation year
[BLURB] becomes the story description
[RELEASE] becomes the release number
[COVER] becomes an image of the cover art (the small 120x120 cover image)
[DOWNLOAD] becomes the download link
[AUXILIARY] becomes the list of feelie-like files, if any
[IFID] becomes the IFID
[STORYFILE] becomes the "leafname" of the story file, e.g., "Bronze.gblorb"
[TEMPLATE] becomes the name of the template used to make the page
[SMALLCOVER] becomes the filename of the cover when used at a smaller size
[BIGCOVER] becomes the filename of the cover when used at full size
[TIMESTAMP] and [DATESTAMP] become the time and date of releasing

In source text, you can also put the following:

[SOURCE] becomes the portion of the source text on this page
[SOURCELINKS] becomes the navigational links
[SOURCENOTES] becomes the footnote matter at the bottom of the source
[PAGENUMBER] and [PAGEEXTENT] are such that the text "page [PAGENUMBER] of [PAGEEXTENT]" produces, e.g., "page 2 of 7"

Both [SOURCE] and [SOURCENOTES] must exist on the page, and [SOURCENOTES] must appear after [SOURCE] does in the file. (Of course the CSS in “style.css” might move the copy around on screen, but that’s another matter.)

You guys will be proud of me…I made my own template!

In my templates folder in my top-level Inform folder, I added a folder called ‘Ugly’. Inside it, I made an index.html file whose entire contents were this:

<link rel="stylesheet" href="style.css" type="text/css" media="all" />

<body>
[TITLE]

[COVER]

</body>

I added release along with an "Ugly" interpreter to the code.

And…are you ready for the results?

image

I plan on copyrighting this ‘Ugly’ template and licensing it to other authors, so please don’t steal :triumph:

I think I’ll stop there for the day so casual browsers can easily see my gorgeous website, and also because the rest of this chapter has super complex stuff about making a map in Inform.

4 Likes

Okay!

Chapter 25, cont.

Section 25.15 is Republishing xisting works of IF. This is actually pretty cool! It’s a way to take old Inform games (including Inform 6) and release them with a website, feelies, etc. even without access to the source code. You just type:

Release along with an existing story file called "Zork1_sg.z5".

which works as long as a story file of that name is in the .materials folder. If you don’t provide a storyname, it looks for Story.z8.

You have to have the settings panel set to Z-machine to do this.

So here’s how you could use the Inform 7 IDE to rerelease Curses (example in the text):

"Curses" by Graham Nelson

The story genre is "Fantasy".

The story headline is "An Interactive Diversion".

The story creation year is 1993.

The release number is 16.

The story description is "It's become a matter of pride now not to give up. That tourist map of Paris must be up here somewhere in all this clutter, even if it has been five years since your last trip. And it's your own fault. It looks as if your great-grandfather was the last person to tidy up these lofts..."

Release along with cover art and an existing story file.

Section 25.16 is pretty cool, I tried it out last night: Walkthrough solutions.

So if you type Release along with a solution, it makes a walkthrough for you!

Sort of.

What it does is it makes a walkthrough as long as your Skein in the Index makes it to some pre-determined point.

The way you choose that point is by annotating a ‘knot’ (or more than one knot) with three asterisks: ***

Then Inform will provide a walkthrough with the skein commands that go there. If you have more than one annotated ending knot or it it branches for any other reason, the walkthrough will branch:

Solution to "Memoirs of India" by Graham Nelson

Choice:
INVENTORY -> go to branch (1)
EAST -> go to branch (2)

Branch (1)
DROP MANUSCRIPT
SOUTH

Branch (2)
INVENTORY ... Always a good idea
GIVE MANUSCRIPT TO THOMAS

And this is all in a text file.

I found this very convenient, and used it to create the walkthrough I sent out to my most recent tester last night. I always hated the skein because my nonlinear games have so many different starts that it gets really tangled, but knowing I can mark a single best point is nice.

Section 25.17 is Releasing the source text

You just type:
Release along with the source text.

If not making a website, this just makes a plain text file.

If making a website, it make a cool tree of webpages based on your heading structure.

Comments in the source that start with an asterisk will be printed as footnoted.

Thus comments thus:

Hercules is a demigod.[* We're using Greek spellings so he ought to be Heracles, but players are so much more familiar with Hercules.]

will be printed more like so:

Hercules is a demigod.[1]
...
Note
[1]. We're using Greek spellings so he ought to be Heracles, but players are so much more familiar with Hercules.

Source text is automatically linked from the webpage if both are corrected. This can be made hidden with:

Release along with the private source text.

You can also Release along with the library card which takes the metadata from the gblorb and puts it into a separate xml file.

Section 25.18 is Improving the index Map.

I like using the index map, because it shows me if I forget to put some room in a region or if I didn’t connect it to other rooms or made a duplicate.

Apparently that map can be output into a cool printed map! I didn’t know it!

It says,

The map-maker is one of the most complex parts of Inform, even though it actually contributes nothing to the final story file: the problem of how to draw up a "correct" map from the source text is by no means easy to solve.

I’ve never tried using it for this purpose before; has anyone else used an Inform-generated map before?

So you can alter the way the Index map is drawn by commands that only alter the physical position of rooms on the map and not the actual in-game connection between the two.

So you can say stuff like:
Index map with Didcot mapped southeast of Abingdon.

or

Index map with Beach Hut Interior mapped west of Sweeping Sands.

So I’ll try this with a copy of my game Swigian that I had on my computer. This is what the map looks like without intervention on one of the levels:

image

I then added this line of code:
Index map with Darkness mapped west of Mead Room and Rocky Summit mapped north of Mother.

and got this result back:

image

Pretty nice! The two stray rooms are now closer together.

Section 25.19 is Producing an EPS Format map.

So the ‘index map with’ stuff actually has 4 possible inputs, not just what we saw!

You can index a map with the following things:

[room A] mapped [direction] of [room B]
EPS file
rubric [text] ... and some optional details ...
[setting] of [whatever] set to [value]

The second one is invoked by typing Index map with EPS file.

This creates a barebones file in .materials called Inform Map.eps that is supposed to be ugly and hard to display because the intent is that it will be modified.

I just tried using this feature. Unfortunately, the resulting .eps could not be imported into GIMP or Libre Office Draw, both giving errors like ‘Image filter not found’, ‘input/output errors’, etc.

I finally got it to work using a web-based EPS viewer which converted it to PDF for me. Here’s a screenshot of part of it:

Section 25.20 is Settings in the map maker. Apparently there are 35 named settings! Each level has their own independent 24 settings.

You can select room size like so, with the numbers referring to 1/72nd of an inch:

Index map with room-size set to 36 and room-size of level 2 set to 28 and room-size of the Hall of Kings set to 52.

I tried those exact same setting in my game (except making my room Mother larger since I don’t have a Hall of Kings). It didn’t change the in-Index map, but it did change the EPS map:

But I didn’t notice any changes to level 2 and stuff, even when I went back and made them only ‘4’, so I wonder if I just misunderstood what a level is. I even tried setting level 2 to 100 and nothing happened. Sad!

Out other options include room-outline-thickness. And we can mess with regions and kinds of rooms.

Index map with room-outline-thickness of the first room set to 2.

A rivery room is a kind of room. Index map with room-colour of rivery rooms set to "Navy" and room-name-colour of rivery rooms set to "White".

Northern Oxfordshire is a region. Hampton Poyle and Steeple Barton are in Northern Oxfordshire. Index map with room-name-font of Northern Oxfordshire set to "Helvetica-Oblique".

I was able to get a few of these to work in my game:
image
(Here you see the navy rooms, one of which is not navy because I forget to include it.)

I’m not really seeing the different font (it’s in the EPS file, just doesn’t show up here in the blue regions in the top). The navy coloring and the thicker line around the first room of the game (not shown here) also do show up in the in-interpreter Index map.

Section 25.21 is Table of map-maker settings, which is just a list, including things like subtitle and title size, font, colour, etc., and the thickness of routes (and route-stiffness, an integer for a Bezier spline curve scale factor.):

Section 25.22 is Kinds of value accepted by the map maker.

This just explains the previous section. It has this useful info about fonts which might explain the result I had with font changes:

Font names are in double-quotes: "Helvetica", etc. Note that Inform makes no effort to look for such fonts: if we give the name of a font we haven't got, the result will probably be that the map's EPS file will be displayed in various applications with Courier (which looks like bad typewriting) substituted. All fonts are by default equal to the global "font" setting (by default equal to "Helvetica"), so changing "font" for the whole map affects everything not explicitly specified as having a different font.

The shape of the box can be changed, with the only options being ‘circle’, ‘square’, and ‘rectangle’.

It mentions that the only real use of the Bezier curve is going around a corner, with stiffness values starting a 100 and going between limits of around 1 and 250.

This is the list of possible colors:

Summary

“Alice Blue”
“Antique White”
“Aqua”
“Aquamarine”
“Azure”
“Beige”
“Bisque”
“Black”
“Blanched Almond”
“Blue”
“Blue Violet”
“Brown”
“Burly Wood”
“Cadet Blue”
“Chartreuse”
“Chocolate”
“Coral”
“Cornflower Blue”
“Cornsilk”
“Crimson”
“Cyan”
“Dark Blue”
“Dark Cyan”
“Dark Golden Rod”
“Dark Gray”
“Dark Green”
“Dark Khaki”
“Dark Magenta”
“Dark Olive Green”
“Dark Orange”
“Dark Orchid”
“Dark Red”
“Dark Salmon”
“Dark Sea Green”
“Dark Slate Blue”
“Dark Slate Gray”
“Dark Turquoise”
“Dark Violet”
“Deep Pink”
“Deep Sky Blue”
“Dim Gray”
“Dodger Blue”
“Feldspar”
“Fire Brick”
“Floral White”
“Forest Green”
“Fuchsia”
“Gainsboro”
“Ghost White”
“Gold”
“Golden Rod”
“Gray”
“Green”
“Green Yellow”
“Honey Dew”
“Hot Pink”
“Indian Red”
“Indigo”
“Ivory”
“Khaki”
“Lavender”
“Lavender Blush”
“Lawn Green”
“Lemon Chiffon”
“Light Blue”
“Light Coral”
“Light Cyan”
“Light Golden Rod Yellow”
“Light Grey”
“Light Green”
“Light Pink”
“Light Salmon”
“Light Sea Green”
“Light Sky Blue”
“Light Slate Blue”
“Light Slate Gray”
“Light Steel Blue”
“Light Yellow”
“Lime”
“Lime Green”
“Linen”
“Magenta”
“Maroon”
“Medium Aquamarine”
“Medium Blue”
“Medium Orchid”
“Medium Purple”
“Medium Sea Green”
“Medium Slate Blue”
“Medium Spring Green”
“Medium Turquoise”
“Medium Violet Red”
“Midnight Blue”
“Mint Cream”
“Misty Rose”
“Moccasin”
“Navajo White”
“Navy”
“Old Lace”
“Olive”
“Olive Drab”
“Orange”
“Orange Red”
“Orchid”
“Pale Golden Rod”
“Pale Green”
“Pale Turquoise”
“Pale Violet Red”
“Papaya Whip”
“Peach Puff”
“Peru”
“Pink”
“Plum”
“Powder Blue”
“Purple”
“Red”
“Rosy Brown”
“Royal Blue”
“Saddle Brown”
“Salmon”
“Sandy Brown”
“Sea Green”
“Sea Shell”
“Sienna”
“Silver”
“Sky Blue”
“Slate Blue”
“Slate Gray”
“Snow”
“Spring Green”
“Steel Blue”
“Tan”
“Teal”
“Thistle”
“Tomato”
“Turquoise”
“Violet”
“Violet Red”
“Wheat”
“White”
“White Smoke”
“Yellow”
“Yellow Green”

It mentions that when doing ‘offsets’ (one of the options), you need to give two numbers like
"Index map with room-offset of Botley set to 10&-30."

I tried this:


Index map with title set to "Awesome map" and subtitle set to "This is complex."

But it didn’t change the Index map or the output. In fact, the .eps file doesn’t even contain the words ‘awesome’ or ‘complex’.

An even bigger issue to me is that the output truncates room names to make them fit, so even the .eps file only has abbreviations.

So so far this whole complex system just isn’t producing useful output for me, being incompatible with most problems and not transmitting vital information. I may be deeply misunderstanding it, though, so feel free to suggest fixes.

Section 25.23 is Titling and abbreviation.

This section deals with my two complaints! It says ‘subtitle’ should be used like this:

Index map with subtitle of level -1 set to "Tunnels and Sewers".

Hmm, so I changed my commands to:


Index map with title set to "Awesome map".

Index map with subtitle of Level 1 set to "This is complex."

But still nothing, not in the Index or the EPS file.

(I’m using 6M62 btw).

It also says room name abbreviations are necessary so they don’t spill over. You can adjust this with the setting ‘room-name-length’.

It has a few examples:

Example 445 is Baedeker:

Dome is a room. North of Dome is North Chapel. South of the Dome is South Chapel. West of the Dome is Western End. Quiet Corner is northwest of the Dome, north of Western End, and west of North Chapel. Loud Corner is east of North Chapel, northeast of Dome, and north of Eastern End. Eastern End is north of Dim Corner and east of Dome. Dim Corner is southeast of Dome and east of South Chapel. Ruined Corner is southwest of Dome, west of South Chapel, and south of Western End.

The church door is east of Eastern End and west of the Courtyard. The church door is a door.

Index map with
    room-shape set to "square" and
    room-size set to 60 and
    room-name-size set to 9 and
    room-name-length set to 13 and
    route-thickness set to 20 and
    room-outline set to off and
    map-outline set to off and
    route-colour set to "White" and
    room-colour set to "White" and
    room-shape of Dome set to "circle" and
    room-size of Dome set to 80 and
    EPS file.

When I run this code and display it, I get this:

The image shown in the manual says that with some manipulation by Adobe we can get this:

image

Example 445 is Port Royal 5. I’ll again show the output I get and the one shown in the textbook.

Mine:
image

There’s (after editing):
image

The example 447 is Bay Leaves and Honey Wine.

Mine:

Theirs:

(The room names are white, which is why they aren’t showing up in my version).

Section 25.24 is Rubrics

You can add any text you want anywhere with stuff like this!

Index map with rubric "Here Be Wyverns" size 16 font "Helvetica-Oblique" colour "Thistle" at 150&0 from Cloud-Cuckoo-Land.

I’ve been a bit frustrated by this chapter, so I will not attempt this.

Does this stuff work better on other computers or with 10.1? The title and subtitle and room sizes per level just aren’t working for me.

2 Likes

I’ll be honest, I’ve never even tried the examples from this chapter. I don’t have a good vector graphics program so I use Trizbort to make maps instead (which tends to be pretty serviceable, though nowhere near as pretty as the ones here).

3 Likes

Chapter 26: Publishing

This is probably the lightest chapter at all, but has some good stuff in it.

Section 26.1: Finding a readership

This is the eternal struggle, right?

This section mentions that interactive fiction means a lot of things to a lot of people, and that choice-based mobile games are really popular right now.

Although it is not a typical tool for choice-based mobile games, Inform has been used to produce commercial works, both parser-based and not. Users are very welcome to sell works created by Inform with no royalty or requirement for rights clearance. It’s also widely used in education, and as a prototyping tool for other kinds of stories, such as interactive narratives that will ultimately take another (not text-based) form.

Section 26.2 is Editing and Quality Assurance

It says that if you think of IF as story, editing is important, and if you think of it as a game, beta testing is good, and gives this sound counsel:

Whatever the background, it’s good practice to have your work checked by other people before you release it. Other players can identify issues from typos to missing hints to thematic incongruities.

Play-testers can often be recruited by placing an ad on intfiction.org.

Section 26.3 is A Page of its Own

One option for publishing an Inform game is to just host your own website.

One option for sharing your work with the world is to set up a web page and a copy of the story file on a private web host. That host should ideally be as stable as possible, so that the URL is likely to remain fixed for what might be a long period. Freeware stories have a long period of viability relative to commercial games, which means that players may still be hearing about and checking out a story years after its initial release. A stable address helps everyone with links, and makes it easier for search engines to direct people.

For distribution platforms, it recommends itch.io over Steam or app stores.

Section 26.4 is The IF Archive

Because of the portable underlying format, however, games written in Inform are unusually stable and maintainable. Inform projects written in the early 90s can still be played – indeed, can be played on platforms that did not exist when the games were written.

This is true, and one reason I care a lot about archiving games: because we can! Flash may die, and console stores may obsolesce, but Inform games really last well, since you generally have to just port the interpreter once to put almost all games onto a new platform (excluding those using highly technical features like quote overlays or multiple windows).

It describes the IFArchive has a mirrored collection of if games, maps, walkthroughs, etc., and that its main focus is long-term archiving, not advertisement.

Uploading a work to the IF Archive is not too difficult, and can be done in two ways. One way is to use the archive’s web form at:

https://upload.ifarchive.org/cgi-bin/upload.py

The other is to create a new page at the Interactive Fiction Database, at:

https://ifdb.org/

It’s then possible to upload the story file to the IF Archive from IFDB. This is easiest all round, since it allows both IFDB and IF Archive to be updated at once.

I believe this is an error; I’m not aware of any way to use the IFDB interface to upload to IF Archive. If it’s there then I sure feel silly for not using it!

Given the recent flurry of several mini-controversies regarding archiving (of which I’ve instigated at least one), this is interesting:

Committing a story to the Archive is meant to be permanent. While the maintainers will happily replace older versions of stories with new improved releases, they are less eager to remove stories entirely. If that doesn’t seem appealing, or if we do not want our story to be treated as freeware with essentially unlimited distribution, the Archive may not be a good choice. But it is deeply valued by the IF community, and has saved many works which could otherwise easily have been lost forever. Many contributions important in the history of IF were made by people who are now not easy to trace, and whose websites are long gone. But their work lives on.

I heartily endorse these words. Write for the ages!

SEction 26.5 is IFDB: The interactive fiction database. It says this website is similar to IMDB or the iTunes music store. It allows people to read reviews or also play directly in the browser.

IFDB is community-editable, like Wikipedia, though editors are required to create an account and log in first – this is free, of course. A standard form is provided for creating a new record (accessible by selecting the option to add a story listing). More or less the same information that appears on Inform’s library card in the Contents index needs to be copied over: there’s space for the author name, story title, genre, and so on. IFDB will also ask for an IFID, a code identifying the story uniquely. Inform generates one of these automatically for each project, and it, too, is on the Library Card. It can always be found by typing VERSION into the compiled story and looking at the line that says

The download link should give the most stable URL available. If you have not yet uploaded your story to the IF Archive, you may do so by selecting the “Upload it to the IF Archive” link instead of pressing the “Add a Link” button. The benefits of submitting your story to the IF Archive in this manner are two-fold. One, IFDB will fill in much of the information required by the IF Archive for you. Two, the link to your story will not appear until the IF Archive maintainers move it to its permanent home in the archive, at which point the download link will be automatically updated and presented on the story page

This again. Is this true? I’ve got to see this.



I have never noticed this button in my life. I am IFDB’s most prolific user and an admin. I have added dozens of games to IFDB. Ever single time, I have skipped over this form.

I feel very dumb right now.

Wow.

A final quote from this text while I am recovering mentally:

Some awards for interactive fiction, such as the annual XYZZY Awards, require a game to have an IFDB entry as an eligibility requirement.

Section 26.6 is Competitions, Exhibitions, and Jams.

Wow, this includes a reference to ParserComp! Neat!

One very common way to get players for IF is to enter the story into an IF competition. The annual IF Competition, often just called IFComp, is the most prestigious and has the widest field, but the Spring Thing, ParserComp, EctoComp, and other events also catch people’s attention. Entering a competition is a path of least effort for authors promoting their new work, because the competition organizer usually takes care of hosting and archiving submitted stories, promoting the competition as a whole, collecting votes, and encouraging players to post reviews.

It references IFWiki for a list of events on the front page.

It mentions that longer games may not be a good fit for competitions (one reason I’m not going to release my 10+ hour game in a competition).

It mentions the XYZZY Awards as an annual event for games listed on IFDB, and suggests itch.io jams.

It finally references procjam for heavily procedurally generated projects.

Section 26.7 is Meetups and conferences. It suggests checking this url:

and Emily Short’s blog.

Section 26.8 is A Short Concluding Homily

I will just reproduce this in full, since I feel these are the true last words of the manual. We have another (fairly hefty) chapter coming up, but it’s not about writing your own game. So here are some ‘final’ words:

It’s natural to want to make a huge splash with a story, but in the IF community, instant widespread adulation for any work is pretty uncommon.

For one thing, players tend to play when they get around to it… which may be weeks, months, or even years after the initial release. Reviews trickle rather than flooding in. Appreciation builds slowly. And sometimes works that placed unspectacularly in a competition, or seemed to be overlooked in the annual XYZZY Awards, gradually come to be regarded as classics because of some pioneering technique.

So it’s wise (if difficult) not to judge a story’s success entirely by its immediate feedback. Even after its debut, a story can often use a little care and attention if it’s to reach all its potential fans – whether that means building further releases, posting hint files or walkthroughs, developing new websites, or approaching outside reviewers.

I think this was even true for Curses, Graham Nelson’s game that is my favorite out of the 2.5K+ games I’ve tried.

3 Likes

Steam discourages free games; Itch encourages them. If you’re not charging money, your clear choices are Itch, ifarchive.org, your own web site, or (why not) multiple of the above.

(Mobile app stores encourage “free-to-play” games but are also drowned in them, mostly the kind that try to suck money out of you anyway. Your free-as-in-ifarchive game will be lost in the noise.)

If you are charging money and expect to sell a meaningful number of copies – hundreds, long-term – it is worth considering Steam. Creating a Steam storefront page is a giant hassle but then money trickles in without further effort. (Mind you, if you do that, you should also make an Itch storefront page and charge the same amount.)

Of course, that money trickling in is reported to the government. So then you’re looking at Schedule C (for US taxpayers) or the equivalent. Research this before diving in.

4 Likes

By the way, as this let’s play is coming to a close, I’ve peaked through the Recipe Book, and it looks like it’s essentially just all the examples from Writing with Inform grouped by various classifications (e.g. complex NPC behavior).

Since I already touched on every example, should I just skip the recipe book and finish with Writing with Inform? Or go through the recipe book with an emphasis on trying out each of the examples as games?

While most RB sections do little more than list the examples with brief (perhaps even superbrief) descriptions, sometimes they’re pretty substantial, like Chapter 6: Commands. I’d be interested in what you had to say about them, and whether your view of any of the examples has changed.

1 Like