top expert

a biting cat website

let’s make IF S3E1: relations revisited

With “let’s WRITE IF” concluded, what’s next?

spring thing, here we come.

As I’ve mentioned here and elsewhere, I have two small games planned for the 2025 Spring. One is Portrait with Wolf. I’ve written a lot about that in the past few months. As of right now, that project is complete from a Top Expert point of view. I’ve shared code and project templates for readers to make games of their own. You can find them on my itch.io page:

https://kamin3ko.itch.io/lyric-storytelling-widget

https://kamin3ko.itch.io/linear-storytelling-widget

I’m excited to share the completed game with you! I hope you’ll check it out when it releases.

The other game has also been written about extensively here at Top Expert: Marbles, D, and the Sinister Spotlight. It’s been a while, though, so I thought we could back up and review some of its key elements. Like Portrait with Wolf, it uses a lot of variable text, though the implementation details are quite different. My specific goal when starting this project was to learn about relations and scenes. Both always seemed a little mysterious to me, as I don’t often see them discussed online. Relations, in particular, feel a bit intimidating. We may as well start there.

why do I want to relate.

I think the biggest hump to get over, when it comes to relations, is to understand why one would bother with them. At least, that was my initial struggle. Let’s just get this out of the way:

A lot of what relations can do could be accomplished with variables, properties, kinds, and so forth.

By the time we’re ready to investigate relations, most of us will be very comfortable using these other methods:

now the perch status of the parrot is true.
now nest of the parrot is the tropical abode.
now the tropical abode is occupied.

And so forth. If we’re scanning through the chapter on relations in the documentation, it might be natural for us to wonder what we’ll get out of them.

In my assessment, we get a couple of things. The first is a simple and readable way to associate things, texts, or numbers without creating one-off variables and so forth. It makes for consistency, portability (and shareability), and ease of use. Besides: they really aren’t so strange. In fact, we have likely been using them from the very start. These sentences and phrases make sense, don’t they?

now the player is in the secret lab;
if the blue blazer is worn by the player:
the sleeve is part of the jacket.
the ancient elvish sword of great antiquity is carried by the adventurer;

These constructions, called “sentences” in Inform, are all made possible by relations. Several relations are defined in Inform’s Standard Rules, and many beginning authors will have used one or more. So, as you can see, they allow us to characterize things in the game world simply and succinctly. How would we make our own?

making our own relation.

We can think about a new relation in terms of a sentence we would want to write. Consider birds and nests. Maybe we have a game about getting birds to their homes. To start, let’s keep things simple. Getting any bird to any nest is good enough. To get the most out of things, let’s write the sentence two ways. To start, let’s use the nest as the subject.

housing relates one thing (called the roost) to one thing.

OK. The start of our declaration, “housing”, will be the name of our relation: the housing relation. I can give a nickname to the first noun (here, the “roost”). This allows me to use phrases like “roost of the blue jay” in my code. Note that this is a one-to-one, exclusive relationship. A thing can only have one roost, and vice versa.

Next, we need to define the verb(s) we can use in our sentences.

the verb to house implies the housing relation.

This is straightforward, and gives us everything we need to start using the relation in code.

now the nest houses the blue jay.

Until otherwise directed, Inform will remember where the blue jay resides. We can also say things like this, using the “roost” that we defined above.

say "The blue jay currently occupies [the roost of the blue jay]."

Inform is pretty smart about recognizing the verbs we use. However, if we need to define a verb ourselves, we use this format:

the verb to house (she houses, they house, she housed, it is housed) implies the housing relation.

To make the most of things, it is best to make what is called a “reversed” relation. This will allow us to write more sentences using the same concepts.

the verb to perch in (he perches in, they perch in, he perched in, it is perched in) means the reversed housing relation.

What’s different? The nouns have switched places. This enables sentences like

now the blue jay perches in the nest.

It may not be clear why this matters. Readability is one reason. Ease of construction is another. If we try having relations that are not one to one (think about player inventory, where many items can be carried by one person), we may find that some sentences make more sense than others.

At our basic, beginner’s level, it might be as simple as finding the way that works best for us.

experiments.

OK, let’s further the “putting birds in nests” idea. We start, as always, by declaring a room. Let’s go further by putting birds and nests there.

lab is a room.
a bird is a kind of animal.
a nest is a kind of thing.
the tropical abode is a nest in lab. 
the common residence is a nest in lab.
the ground rest is a nest in lab.
an ostrich is a bird in lab.
a parrot is a bird in lab.
a blue jay is a bird in lab.

OK. We have two kinds and some things to play with. Here’s our relations once again:

housing relates one thing (called the roost) to another.
the verb to house (he houses, they house, he housed, it is housed) implies the housing relation.
the verb to perch in (he perches in, they perch in, he perched in, it is perched in) means the reversed housing relation.

Let’s make a custom action where we send birds to nests.

sending it to is an action applying to two things.
understand "send [something] to/-- [something]" as sending it to.

Now, we could send anything to anything, but this relation is only intended for birds and nests. I have options. I could make an instead (less preferred) rule or a check rule (usually recommended). Unless you have something special in mind, I recommend “check” (see Wade’s comment below). A typical “check” would look like this.

check sending something to something:
	unless the noun is a bird and the second noun is a nest:
		say "Birds must be sent to nests; no other combination will work." instead.

However, these days I’ve been trying to use the whole action processing turn. I’ll check things during “carry out” for that reason. This will leave things open for me to use “after” and “report” rules if I want.

carry out sending something to something:
	unless the noun is a bird and the second noun is a nest:
		say "Birds must be sent to nests; no other combination will work.";
	otherwise:
		now the noun perches in the second noun;
		say "Great. Now the [noun] perches in the [roost of the noun]."

Just as we’ve seen with wearing and other common relations, “the noun perches in the second noun” is enough to associate the two things. We can immediately begin referring to them in phrases like “roost of the noun.”

If we want to change the way a nest is listed (room descriptions or inventory), we can tweak that:

after printing the name of a bird (called the avian) while listing contents:
	if the avian perches in something, say " (perched in [the roost of the avian])";

Here’s another action processing usage:

check taking when the noun perches in something:
	say "You don't want to disturb [the noun]'s rest." instead.

As we’ve seen, these relationships can vary text and be used as conditions for action processing rules. Using simple, straightforward sentences to manage relations is a powerful tactic that also makes it easy to standardize and share code.

what’s missing.

Because our relation associates “one thing to one thing,” we have declared that the relationship is exclusive. A bird cannot have more than one nest, and a nest cannot have more than one bird. When we declare this relationship (now the noun perches in the second noun), we are simultaneously negating any other bird-nest that either previously had. If the blue jay is perched in a new nest, the old nest will become empty, and any bird already in the new nest will be evicted.

To work this into a game, we would likely want to report the updated relationship, just like Inform prints “Taken” when the player takes something.

Inventory illustrates why we might want relations that are not one-to-one. A person can carry multiple things, but only one person can carry a given thing. We could associate multiple things with multiple things: perhaps more than one person has multiple job responsibilities, some shared, some unique.

But these permutations can seem complex at first, so we’ll be focusing on one-to-one relationships in future posts.

next.

more relations.

Today’s Code

I update multiple social media accounts when I release new posts, but I’m most active on BlueSky. Get updates on all my stuff (game dev, Top Expert, and Gold Machine) there.

https://bsky.app/profile/bitingcat.bsky.social

My Discord ID is probably “golmac”.

Categories: , ,

2 responses to “let’s make IF S3E1: relations revisited”

  1. Wade Avatar

    I could probably use relations more than I do. This was a helpful reminder that most of Inform’s built-in stuff already is relations.

    I have one suggestion for this episode’s demo, which is that it’s probably preferable to check for the nest/bird combo at the check stage.

    i.e.

    check sending something to something: unless the noun is a bird and the second noun is a nest: instead say “Birds must be sent to nests; no other combination will work.”;

    Once the action reaches the ‘carry out’ stage, it’s considered to have succeeded in Inform’s techincal conception of things. Therefore if you shortly after used a test like ‘if rule succeeded’ after someone tried to put a non-bird in a nest, Inform would believe that the action had actually succeeded. Also, any other carry out rules for this action will still fire, if you add them later.

    Check’s the usual place to block the normal operation of an action if there’s a reason to block it. And ‘insteading’ out at the check stage will result in the action being seen to have failed.

    Of course, the great thing about building new actions from scratch is that their rulebooks start empty. It’s easy to manage almost everything about them by just reordering your rules in the source if you want. But in any pre-existing action, I would not parry it at the carry out stage except in wild circumstances.

    Like

  2. Drew Cook Avatar

    Hi Wade! So, perhaps I am underselling things when I say “usually recommended” regarding a “check” rule. And I think maybe I’ll show it both ways. check and carry out. But I like to avoid “instead”/failure for custom actions because I often use “after” or “report” messages for them.

    I added the “check” with a little blurb. Thanks for commenting!

    Like

Leave a reply to Drew Cook Cancel reply