PunyInform Coding 3: Daemons and Describing Objects


Look at the bottom of this article for links to the other articles and tutorials on PunyInform. These tutorials make the most sense if you go through them in order.

In this tutorial, we’re building a game where you’re working for Mrs. Morris. It’s the end of the day and you want to go home. All you have to do is microwave a plate of spaghetti to a proper temperature for eating and put it in the dumbwaiter. Then you can leave.

You can download the source code seen in this tutorial, as well as the compiled game (demogame_3.z3) from this folder.

Declaring the constants

PunyInform code part 1

On line 8, we declare that we want to show the time on the statusline rather than the score.

Line 12: We want the player to be able to “set (object) to (number)”. This is included in the extended verbset, so we’ll just add that option. We get a bunch of other nice-to-have verbs as well. If file size was a major concern for us, we could just define the verb ‘set’ by hand, but it’s not.

Line 13: In addition to letting the player type numbers with digits, we can allow them to use words for small numbers, so the player can type “set timer to five”.

Line 15: We decided we don’t need a scoring system for this game. Defining NO_SCORE drops the messages telling the player the score has gone up or down etc, but keeps a ‘score’ verb which just prints a message that there is no score in this game.

Entry point routines, extensions and grammar

PunyInform code part 2

After defining all library constants, it’s time to include globals.h. After this, we create a global variable of our own. A PunyInform program can define up to about 150 global variables of its own. This can be useful to keep track of what has happened in the game etc. We give this particular variable a name starting with “f_” to mark that it’s a flag – something that can only have values true (1) or false (0). When the game starts, the player has not served Mrs. Morris a meal, so the flag starts out with the value false.

PunyInform supports a set of “Entry point routines” (See which ones in the PunyInform manual and read up on what they do in the Designer’s Manual). If you want to define any entry point routines, you need to do so before including puny.h. One of these routines is DeathMessage.

If at any time we want to end the game, we set deadflag to a value greater than 0. The value 1 (also referred to as GS_DEAD) means the player died. The value 2 ( = GS_WIN) means the player won. Values greater than 2 are used when we want to add our own ways of ending the game. If we use a value greater than 2, we must also add a DeathMessage routine which checks the value of deadflag and prints a message if it’s greater than 2.

On line 28, we include an extension called “ext_waittime.h”. This allows the player to type things like “wait for 10 minutes” or “wait until 9 pm”.

The verb ‘set’ can be used in two ways: “set (object)” or “set (object) to (number)”. For our game, it’s better if we drop the form “set (object)” and add another form: “set (object) to (number) minutes”. When we want to remove some part of the grammar for a verb, we need to replace the entire grammar for that verb. This is what we do in line 30-32. Note the keyword replace.

In line 34-38 we add new ways to express “switch on (object)” and “switch off (object)”, namely “start (object)” and “stop (object)” respectively.

The kitchen

PunyInform code part 3

The kitchen is the location where everything happens in this game.

If the player tries to go north, we supply a routine to decide on the outcome of this action. If they have served Mrs. Morris her meal, we return Street, which is of course a location. Otherwise, we print a message saying why the player can’t go north and return true.

The dumbwaiter – the ticket to winning and losing

PunyInform code part 4

The dumbwaiter is a container which is always open. To give it a paragraph of its own in the room description, we give it the when_open property. In this routine, we print that there’s a dumbwaiter here, and then we perform the action ##Search with the noun self. We do this with the angle bracket notation on line 59. This means the game will print whatever it would normally print if the player had typed “search the dumbwaiter”, meaning it will say what’s in the dumbwaiter.

Then we have a before routine, to handle the player putting things in the dumbwaiter. As you already know from previous tutorials, a before routine can react to the actions the player types. It can also react to actions performed in code, like <Search self>; . Additionally, some actions issue “fake actions”. A fake action is an action which doesn’t have an action routine, and there is no grammar pointing to it. These are the fake actions that PunyInform can issue:

  • The ##Insert action issues a ##Receive fake action to the object the player tries to put something in. While this fake action is happening, the global variable receive_action has the value ##Insert.
  • The ##PutOn action issues a ##Receive fake action to the object the player tries to put something on. While this fake action is happening, receive_action has the value ##PutOn.
  • The ##Take action issues a ##LetGo fake action to the object the player tries to remove something from.
  • The ##ThrowAt action issues a ##ThrownAt fake action to the object the player tries to throw something at.
  • The ##Go actions issues a ##Going fake action to the location where the player is about to go.

So e.g. when the player types “put banana in box”, the banana can react to the ##Insert action, and the box can react to the ##Receive action. In the game we’re writing, this is what we do whenever the player tries to place something in the dumbwaiter:

  • If the noun isn’t the spaghetti, it’s simply denied – we print a message and return true.
  • We print that the player puts the spaghetti in the dumbwaiter.
  • We check the temperature of the spaghetti, divided by six. (Any remainder is thrown away)
  • If it’s less than 2, it’s too cold. The player will need to heat the food more.
  • If it’s more than 2, it’s too hot. The player is fired and the game ends.
  • Since at this point it has to be two, we note that the player has indeed served Mrs. Morris a satisfactory meal (by setting f_served_meal to true), and can now go home. We also remove the spaghetti from the game, and print a message.
  • Note that regardless what happens, we always return true, thus blocking the action. This means nothing actually ends up in the dumbwaiter. While we may print that the player puts the spaghetti in the dumbwaiter, we don’t actually have to do it.

The microwave oven, part 1

PunyInform code part 5

The microwave oven is a pretty complicated object. Here we see the first part, and the second and third parts are in the next images. There’s also a timer for the oven, which comes later.

First, we want to tell the player about the oven in the room description. While there are specific properties like when_open and when_closed, there’s always the more generic describe, and this seems more suitable here, since not only do we want to say if the oven is open or closed, but also if it’s on or off and what’s inside it. We end this routine with an action in double angle brackets on line 95. This means “perform this action, and then return true”. Since the describe routine returns true, the library knows we’ve described the micro, and it won’t bother with listing it in the room.

Then comes the before routine, which reacts to the ##SwitchOn action. If the oven is already on, we don’t need to react. The action routine will tell the player the oven is already on, and that’s just the way we want it. Therefore we return false. Now, if the oven is off and open, it can’t be turned on. Same thing if it’s off and closed but the timer hasn’t been set. In these cases, we print a message and return true.

The microwave oven, part 2

PunyInform code part 6

Now it’s time for an after routine. If ##SwitchOn wasn’t stopped in the before routine, and the ##SwitchOn action routine didn’t see any reason why the player shouldn’t be allowed to switch the oven on, we will start the oven’s daemon using the StartDaemon() routine.

A daemon is a routine attached to an object using the daemon property. It can be started with StartDaemon(object)and stopped with StopDaemon(object). By starting a daemon, you indicate that you want it to run at the end of each turn until you stop it again. It will run regardless if the player is near the object or not. In this case, we use a daemon to heat food. Even if we had other rooms the player could explore, and the player left the kitchen, the oven should keep heating any food that’s in it for as long as the oven’s timer is set for.

Back to the after routine. In line 108-109, we react to ##SwitchOff by stopping the oven’s daemon.

Then we react to ##Open. If the player opens the oven when it’s on, we turn the oven off, stop the daemon and print a suitable message. Since we also return true, the default message won’t be printed.

Then we have the description routine. If the player examines the oven, we say it’s clean and tidy, and then we have them examine the timer using <<Examine Timer>>;

The microwave oven, part 3

PunyInform code part 7

Now we need a daemon routine. It’s responsible for heating food, as well as turning the oven off when the timer reaches zero.

If the spaghetti is in the oven, increase the temperature of the spaghetti by four steps. We do this by calling a custom routine in an individual property of the Spaghetti object, named change_temperature. We could have named this property pretty much anything we like, but what is does is change the temperature of the spaghetti, so change_temperature seemed appropriate.

The properties provided by the library are all common properties . You can add a few common properties yourself using the syntax Property my_property; but the number of common properties is limited, especially when using the z3 format. You can however use any number of individual properties. You do so by just writing the name you want to use in an object declaration, and the value it should have for that object. Individual properties take up a little more space and are a little slower to access than common properties, but for many uses that’s not so important.

Then we decrease the timer setting by 1, using Timer.setting--; . This is equivalent to writing Timer.setting = Timer.setting - 1; . There is also ++ to increase a variable by one.

Now we check if the timer has reached zero. If it has, we also double-check that the oven is still on, and if it is we do this:

  • Turn the oven off
  • Set waittime_waiting to false. This is a signal to the ext_waittime extension that if the player is currently waiting because they typed something like “wait until 8:30” or “wait for 20 minutes”, that waiting should now be aborted – the player wouldn’t want to keep waiting while the food is getting cold again.
  • Print a message saying the oven goes PING and shuts down.

Lastly, we check if the oven is now off and if it is, stop the daemon too.

In line 134, we define a property called add_to_scope . The add_to_scope property is used to say “whenever this object is in scope ( = can be referred to by the player ), also place some other object(s) in scope.” It can hold either a list of objects to place in scope, or a routine which places objects in scope using PlaceInScope(object);. In this case, we just need to place a single object in scope, and there are no ifs or buts about it, so a list is fine. The list can hold up to four objects in a z3 game, or up to 32 objects in a z5 or z8 game.

So, why do we need add_to_scope here? Normally, we could attach the timer to the oven by making the timer a child object of the oven (put it “in” the oven), but this will get confusing because the oven is also a container, so children are consider to be inside the oven. This is a case when add_to_scope comes in handy. Another example could be a telephone. While you’re talking to someone on the phone, that person should be in scope, even if they’re not in the room with you. To achieve this effect, you can have the phone add the person to scope for as long as the call lasts.

The spaghetti, part one

PunyInform code part 8

The plate of spaghetti is another complicated object. The code is split in two images here.

We have given it an individual property called temperature. This starts out as 0, meaning room temperature. We have decided that 29 is the maximum temperature, and this is the temperature it gets if we heat it in the microwave oven for a long time. 29 probably corresponds to about 200° C.

Then there’s another individual property called change_temperature and it holds a routine which does just what the name suggests. The routine is meant to be called with one argument (deg), and it tries to change the temperature that much, while making sure the temperature stays in the range 0 to 29 inclusive.

And we have another individual property called print_temperature, holding a routine which does just this. It uses a switch statement which is a convenient way of doing different things depending on the value of an expression. You could achieve exactly the same effect with a series of if + else statements, but this may be more readable.

Keep in mind that Inform only has integer arithmetics, so self.temperature / 6 will be rounded down to the neareast integer. If you wanted to know the remainder of the division, you would use %, as in self.temperature % 6 .

The spaghetti’s daemon only has one job: Make the spaghetti cool off by one step every turn, unless the spaghetti’s temperature is already at 0. Note that this daemon is always running, so when the spaghetti is being heated in the oven, its temperature is increased by four by the oven’s daemon and decreased by one by its own daemon, every turn. Adding it up, the temperature increases by 3 each turn in the oven.

The spaghetti, continued

PunyInform code part 9

The spaghetti has an invent property. This is used to affect how the object is printed when PunyInform lists objects, like when taking inventory, when looking inside something else (“search oven”), or when printing the objects in a room. The invent routine is called twice:

  • First invent is called with inventory_stage set to 1. This happens just as the object name is about to be printed. If the invent routine returns true, nothing further is printed (and invent isn’t called again).
  • Then invent is called with inventory_stage set to 2 when the object name has been printed but additional information like ” (providing light)” hasn’t. If the invent routine returns true, nothing further is printed.

For the spaghetti, we use this to say how warm the spaghetti is, unless we can’t touch the spaghetti, which only happens while it’s in the oven. ObjectIsUntouchable(object, dont_print) is a routine provided by PunyInform to decide if an object can’t be touched by the player because there’s a barrier in the way. If we don’t give a value for the dont_print parameter, or we give it the value false, a message will be printed if the player can’t touch the object. We don’t want that here, so we give it the value true.

Then there’s the description property. Since we want to print some words descibing the temperature of the spaghetti both in the invent and the description routines, it makes sense to put the code to print those words in a routine of its own. Hence the print_temperature property.

The timer

PunyInform code part 10

This is the timer for the oven. It’s not located in a room, but is dragged into scope by the oven. The timer has an individual property setting which holds the number of minutes it has left to go.

The description property tells the player the current setting of the timer.

We use the before routine for multiple purposes:

  • We give the player a sensible message if they try to pick up the timer.
  • If the player tries to turn, push or pull the timer (which can all be considered pretty reasonable attempts to set it), we help them with the syntax they need to set the timer.
  • If the player tries to switch on the timer rather than the oven, we redirect the action to the oven. We have a bunch of code in the oven object to handle SwitchOn, and all of that will be applied, just as if the player had typed “switch on the oven”. Note that we use the double angle bracket syntax to perform the action, meaning we also return true afterwards, thus blocking the default response of the SwitchOn action for the timer.
  • We allow the player to set the timer to a number (of minutes). When a grammar line allows the player to type a number as part of the input, that number is kept in parsed_number.

The street and the Initialise routine

PunyInform code part 11

The final object in the game is the Street location. As soon as we get out here, a ##Look action will automatically be performed. We use the after routine to react to this by ending the game and printing a message.

In the Initialise routine, we need to set the time of day, since this is a game that shows the time on the statusline. We set it by calling SetTime(time, step); . time is the number of minutes past midnight, so 20 * 60 means 8:00 PM. step is the relation between minutes and moves. A value of 1 means that one move takes one minute. A value of 5 would mean that one move takes five minutes. A value of -5 would mean that five moves take one minute.

We then start the Spaghetti’s daemon, which will then run for the entire game. And we print an introduction to the game.


Text adventure fan, player and author since the eighties. Current projects include Ozmoo (a Z-code interpreter for the C64) and PunyInform (a lightweight Inform 6 library for writing text adventures for 8-bit platforms and newer computers)

1 thought on “PunyInform Coding 3: Daemons and Describing Objects

  1. Being Italian I can say that a story revolving around microwaved carbonara is definitely a horror setup. LOL! Jokes aside, this is a beautiful article: very well-written and helpful. We need more, please. Congrats!

Leave a Reply

Your email address will not be published. Required fields are marked *