7 | |CENTER| *S was a sailor, and spent all he got;*
8 | |CENTER| *T was a tinker, and mended a pot.*
12 .. image:: /images/picS.png
15 |S|\imple though they are, our two games have covered most of the basic
16 functionality of Inform, providing enough solid ground underfoot for you to
17 start creating simple stories. Even if some of what you've encountered
18 doesn't make sense yet, you should be able to browse a game's source code
19 and form a general understanding of what is going on.
21 We'll now design a third game, to show you a few additional features and
22 give you some more sample code to analyse. In "Heidi" we tried to make
23 progress step by step, explaining every bit of code that went into the game
24 as we laid the objects sequentially; in "William Tell" you'll have noticed
25 that we took a few necessary explanatory detours, as the concepts grew more
26 interesting and complicated. Here we'll organise the information in
27 logical didactic chunks, defining some of the objects minimally at first
28 and then adding complexity as need arises. Again, this means that you
29 won't be able to compile for testing purposes after the addition of every
30 code snippet, so, if you're typing in the game as you read, you’ll need to
31 check the advice in :ref:`compile-as-you-go`.
33 A lot of what goes into this game we have already seen; you may deduce from
34 this that the game design business is fairly repetitious and that most
35 games are, when you reach the programming bottom line, another remake of
36 the same old theme. Well, yes and no: you've got a camera and have seen
37 some short home videos in the making, but it’s a long way from here to
38 Casablanca. To stick with the analogy, we'll now construct the opening
39 sequence of an indie B-movie, a tribute to the style of super-hero made
40 famous by a childhood of comic books:
44 "Impersonating mild mannered John Covarth, assistant help boy at an
45 insignificant drugstore, you suddenly STOP when your acute hearing
46 deciphers a stray radio call from the POLICE. There’s some MADMAN
47 attacking the population in Granary Park! You must change into your
48 Captain FATE costume fast...!"
50 which won't be so easy to do. In this short example, players will win when
51 they manage to change into their super-hero costume and fly away to meet
52 the foe. The confrontation will -- perhaps -- take place in some other
53 game, where we can but hope that Captain Fate will vanquish the forces of
54 evil, thanks to his mysterious (and here unspecified) superpowers.
56 Fade up on: a nondescript city street
57 =====================================
59 The game starts with meek John Covarth walking down the street. We set up
62 .. include:: /config/typethis.rst
64 .. code-block:: inform
67 !============================================================================
68 Constant Story "Captain Fate";
70 "^A simple Inform example
71 ^by Roger Firth and Sonja Kesserich.^";
72 Release 3; Serial "040804"; ! for keeping track of public releases
74 Constant MANUAL_PRONOUNS;
76 Constant OBJECT_SCORE 1;
77 Constant ROOM_SCORE 1;
82 !============================================================================
86 with description "UNDER CONSTRUCTION",
91 Take,Pull,Push,PushDir:
92 "Even though your SCULPTED adamantine muscles are up to the task,
93 you don't favour property damage.";
97 !============================================================================
100 Room street "On the street"
101 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
103 "On one side -- which your HEIGHTENED sense of direction
104 indicates is NORTH -- there's an open cafe now serving
105 lunch. To the south, you can see a phone booth.";
107 !============================================================================
108 ! The player's possessions
110 !============================================================================
111 ! Entry point routines
116 "^^Impersonating mild mannered John Covarth, assistant help boy at an
117 insignificant drugstore, you suddenly STOP when your acute hearing
118 deciphers a stray radio call from the POLICE. There's some MADMAN
119 attacking the population in Granary Park! You must change into your
120 Captain FATE costume fast...!^^";
123 !============================================================================
124 ! Standard and extended grammar
127 !============================================================================
129 Almost everything is familar, apart from a few details:
131 .. code-block:: inform
133 Constant MANUAL_PRONOUNS;
134 Constant MAX_SCORE 2;
135 Constant OBJECT_SCORE 1;
136 Constant ROOM_SCORE 1;
138 By default, Inform uses a system of automatic pronouns: as the player
139 character moves into a room, the library assigns pronouns like IT and HIM
140 to likely objects (if you play "Heidi" or "William Tell" and type PRONOUNS,
141 you can see how the settings change). There is another option. If we
142 declare the ``MANUAL_PRONOUNS`` constant, we force the library to assign
143 pronouns to objects only as the player mentions them (that is, IT will be
144 unassigned until the player types, say, EXAMINE TREE, at which point, IT
145 becomes the TREE ). The behaviour of pronoun assignment is a matter of
146 personal taste; no system is objectively perfect.
148 .. Generated by autoindex
150 pair: score; library variable
151 pair: scored; library attribute
153 Apart from the constant ``MAX_SCORE`` that we have seen in "William Tell",
154 which defines the maximum number of points to be scored, we now see two
155 more constants: ``OBJECT_SCORE`` and ``ROOM_SCORE``. There are several
156 scoring systems predefined in Inform. In "William Tell" we've seen how you
157 can manually add (or subtract) points by changing the value of the variable
158 :var:`score`. Another approach is to award points to players on the first
159 occasion that they (a) enter a particular room, or (b) pick up a particular
160 object. To define that a room or object is indeed “particular”, all you
161 have to do is give it the attribute :attr:`scored`; the library take cares
162 of the rest. The predefined scores are five points for finally reached
163 rooms and four points for wondrous acquisition of objects. With the
164 constants ``OBJECT_SCORE`` and ``ROOM_SCORE`` we can change those defaults;
165 for the sake of example, we've decided to modestly award one point for
166 each. By the way, the use of an equals sign ``=`` is optional with
167 ``Constant``; these two lines have identical effect:
169 .. code-block:: inform
171 Constant ROOM_SCORE 1;
173 Constant ROOM_SCORE = 1;
175 Another difference has to do with a special short-hand method that Inform
176 provides for displaying strings of text. Until now, we have shown you:
178 .. code-block:: inform
180 print "And now for something completely different...^"; return true;
182 print_ret "And now for something completely different...";
184 Both lines do the same thing: they display the quoted string, output a
185 newline character, and return true. As you have seen in the previous
186 example games, this happens quite a lot, so there is a yet shorter way of
187 achieving the same result:
189 .. code-block:: inform
191 "And now for something completely different...";
193 That is, *in a routine* (where the compiler is expecting to find a
194 collection of statements each terminated by a semicolon), a string in
195 double quotes by itself, without the need for any explicit keywords, works
196 exactly as if there were a ``print_ret`` in front of it. Remember that
197 this way of displaying text implies a ``return true`` at the end (which
198 therefore exits from the routine immediately). This detail becomes
199 important if we *don't* want to return true after the string has been
200 displayed on the screen -- we should use the explicit ``print`` statement
203 .. Generated by autoindex
205 pair: name; library property
207 You'll notice that -- unusually for a room -- our ``street`` object has
208 a :prop:`name` property:
210 .. code-block:: inform
212 Room street "On the street"
213 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
216 Rooms aren't normally referenced by name, so this may seem odd. In fact,
217 we're illustrating a feature of Inform: the ability to define dictionary
218 words as "known but irrelevant" in this location. If the player types
219 EXAMINE CITY here, the interpreter will reply "That's not something you
220 need to refer to in order to SAVE the day", rather than the misleading "You
221 can't see any such thing". We mostly prefer to deal with such scenic words
222 using classes like ``Prop`` and ``Furniture``, but sometimes a room's
223 :prop:`name` property is a quick and convenient solution.
225 .. Generated by autoindex
227 pair: container; library attribute
229 In this game, we provide a class named ``Appliance`` to take care of
230 furniture and unmovable objects. You’ll notice that the starting room we
231 have defined has no connections yet. The description mentions a phone
232 booth and a café, so we might want to code those. While the café will be a
233 normal room, it would seem logical that the phone booth is actually a big
234 box on the sidewalk; therefore we define a :attr:`container` set in the
235 street, which players may enter:
237 .. include:: /config/typethis.rst
239 .. code-block:: inform
241 Appliance booth "phone booth" street
242 with name 'old' 'red' 'picturesque' 'phone' 'booth' 'cabin'
245 "It's one of the old picturesque models, a red cabin with room
249 "The booth is already open.";
251 "There's no way to close this booth.";
255 "With implausible celerity, you dive inside the phone booth.";
257 has enterable container open;
259 What's interesting are the attributes at the end of the definition. You'll
260 recall from Heidi's ``nest`` object that a :attr:`container` is an object
261 capable of having other objects placed in it. If we make something
262 :attr:`enterable`, players count as one of those objects, so that they may
263 squeeze inside. Finally, ``containers`` are, by default, supposed to be
264 closed. You can make them :attr:`openable` if you wish players to be able
265 to OPEN and CLOSE them at will, but this doesn't seem appropriate behaviour
266 for a public cabin -- it would become tedious to have to type OPEN BOOTH
267 and CLOSE BOOTH when these actions provide nothing special -- so we add
268 instead the attribute :attr:`open` (as we did with the nest), telling the
269 interpreter that the container is open from the word go. Players aren't
270 aware of our design, of course; they may indeed try to OPEN and CLOSE the
271 booth, so we trap those actions in a :prop:`before` property which just
272 tells them that these are not relevant options. The :prop:`after` property
273 gives a customised message to override the library’s default for commands
274 like ENTER BOOTH or GO INSIDE BOOTH.
276 Since in the street's description we have told players that the phone booth
277 is to the south, they might also try typing SOUTH. We must intercept this
278 attempt and redirect it (while we're at it, we add a connection to the
279 as-yet-undefined café room and a default message for the movement which is
282 .. code-block:: inform
284 Room street "On the street"
285 with name city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
287 "On one side -- which your HEIGHTENED sense of direction
288 indicates is NORTH -- there's an open cafe now serving
289 lunch. To the south, you can see a phone booth.",
291 s_to [; <<Enter booth>>; ],
293 "No time now for exploring! You'll move much faster in your
294 Captain FATE costume.";
296 That takes care of entering the booth. But what about leaving it? Players
297 may type EXIT or OUT while they are inside an enterable container and the
298 interpreter will oblige but, again, they might type NORTH. This is a
299 problem, since we are actually in the street (albeit inside the booth) and
300 to the north we have the café. We may provide for this condition in the
301 room's :prop:`before` property:
303 .. code-block:: inform
307 if (player in booth && noun == n_obj) <<Exit booth>>;
310 Since we are outdoors and the booth provides a shelter, it's not impossible
311 that a player may try just IN, which is a perfectly valid connection.
312 However, that would be an ambiguous command, for it could also refer to the
313 café, so we express our bafflement and force the player to try something
316 .. code-block:: inform
319 s_to [; <<Enter booth>>; ],
320 in_to "But which way?",
322 Now everything seems to be fine, except for a tiny detail. We've said
323 that, while in the booth, the player character’s location is still the
324 ``street`` room, regardless of being inside a :attr:`container`; if players
325 chanced to type LOOK, they'd get:
327 .. code-block:: transcript
329 On the street (in the phone booth)
330 On one side -- which your HEIGHTENED sense of direction indicates is NORTH --
331 there's an open cafe now serving lunch. To the south, you can see a
334 Hardly an adequate description while *inside* the booth. There are several
335 ways to fix the problem, depending on the result you wish to achieve. The
336 library provides a property called :prop:`inside_description` which you can
337 utilise with enterable containers. It works pretty much like the normal
338 :prop:`description` property, but it gets printed only when the player is
339 inside the container. The library makes use of this property in a very
340 clever way, because for every LOOK action it checks whether we can see
341 outside the container: if the container has the :attr:`transparent`
342 attribute set, or if it happens to be :attr:`open`, the library displays
343 the normal :prop:`description` of the room first and then the
344 :prop:`inside_description` of the container. If the library decides we
345 can’t see outside the container, only the :prop:`inside_description` is
346 displayed. Take for instance the following (simplified) example:
348 .. code-block:: inform
350 Room stage "On stage"
352 "The stage is filled with David Copperfield's
353 magical contraptions.",
356 Object magic_box "magic box" stage
358 "A big elongated box decorated with silver stars, where
359 scantily clad ladies make a disappearing act.",
361 "The inside panels of the magic box are covered with black
362 velvet. There is a tiny switch by your right foot.",
364 has container openable enterable light;
366 Now, the player would be able to OPEN BOX and ENTER BOX. A player who
367 tried a LOOK would get:
369 .. code-block:: transcript
371 On stage (in the magic box)
372 The stage is filled with David Copperfield's magical contraptions.
374 The inside panels of the magic box are covered with black velvet. There is a
375 tiny switch by your right foot.
377 If now the player closes the box and LOOKs:
379 .. code-block:: transcript
381 On stage (in the magic box)
382 The inside panels of the magic box are covered with black velvet. There is a
383 tiny switch by your right foot.
385 In our case, however, we don't wish the description of the street to be
386 displayed at all (even if a caller is supposedly able to see the street
387 while inside a booth). The problem is that we have made the booth an
388 :attr:`open` container, so the street's description would be displayed
389 every time. There is another solution. We can make the
390 :prop:`description` property of the ``street`` room a bit more complex, and
391 change its value: instead of a string, we write an embedded routine.
392 Here's the (almost) finished room:
394 .. include:: /config/typethis.rst
396 .. code-block:: inform
398 Room street "On the street"
399 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
402 "From this VANTAGE point, you are rewarded with a broad view
403 of the sidewalk and the entrance to Benny's cafe.";
405 "On one side -- which your HEIGHTENED sense of direction
406 indicates is NORTH -- there's an open cafe now serving
407 lunch. To the south, you can see a phone booth.";
411 if (player in booth && noun == n_obj) <<Exit booth>>;
414 s_to [; <<Enter booth>>; ],
415 in_to "But which way?",
417 "No time now for exploring! You'll move much faster in your
418 Captain FATE costume.";
420 The description while inside the booth mentions the sidewalk, which
421 might invite the player to EXAMINE it. No problem:
423 .. include:: /config/typethis.rst
425 .. code-block:: inform
427 Appliance "sidewalk" street
428 with name sidewalk' 'pavement' 'street',
431 "You make a quick surveillance of the sidewalk and discover much
432 to your surprise that it looks JUST like any other sidewalk in
435 Unfortunately, both descriptions also mention the café, which will be a
436 room and therefore not, from the outside, an examinable object. The
437 player may enter it and will get whatever description we code as the
438 result of a LOOK action (which will have to do with the way the café
439 looks from the *inside*); but while we are on the street we need
440 something else to describe it:
442 .. include:: /config/typethis.rst
444 .. code-block:: inform
446 Appliance outside_of_cafe "Benny's cafe" street
447 with name 'benny^s' 'cafe' 'entrance',
449 "The town's favourite for a quick snack, Benny's cafe has a 50's
453 print "With an impressive mixture of hurry and nonchalance
454 you step into the open cafe.^";
458 has enterable proper;
460 .. index:: accented characters
464 Although the text of our guide calls Benny's establishment a "café" --
465 note the acute "e" -- the game itself simplifies this to "cafe". We do
466 this for clarity, not because Inform doesn't support accented
467 characters. The |DM4| explains in detail how to display these
468 characters in :dm4:`§1.11 <s1.html#s1_11>` "*How text is printed*" and
469 provides the whole Z-machine character set in Table 2. In our case, we
470 could have displayed this::
472 The town's favourite for a quick snack, Benny's café has a 50's ROCKETSHIP look.
474 by defining the :prop:`description` property as any of these:
476 .. code-block:: inform
479 "The town's favourite for a quick snack, Benny's caf@'e has a 50's
483 "The town's favourite for a quick snack, Benny's caf@@170 has a 50's
487 "The town's favourite for a quick snack, Benny's caf@{E9} has a 50's
490 However, all three forms are harder to read than the vanilla "cafe", so
491 we've opted for the simple life.
493 Unlike the sidewalk object, we offer more than a mere description. Since
494 the player may try ENTER CAFE as a reasonable way of access -- which would
495 have confused the interpreter immensely -- we take the opportunity of
496 making this object also :attr:`enterable`, and we cheat a little. The
497 attribute :attr:`enterable` has permitted the verb ENTER to be applied to
498 this object, but this is not a :attr:`container`; we want the player to be
499 sent into the *real* café room instead. The :prop:`before` property handles
500 this, intercepting the action, displaying a message and teleporting the
501 player into the café. We ``return true`` to inform the interpreter that we
502 have taken care of the :act:`Enter` action ourselves, so it can stop right
505 .. Generated by autoindex
507 pair: n_to; library property
509 As a final detail, note that we now have two ways of going into the café:
510 the :prop:`n_to` property of the ``street`` room and the :act:`Enter`
511 action of the ``outside_of_cafe`` object. A perfectionist might point out
512 that it would be neater to handle the actual movement of the player in just
513 one place of our code, because this helps clarity. To achieve this, we
514 redirect the street's :prop:`n_to` property thus:
516 .. include:: /config/typethis.rst
518 .. code-block:: inform
520 n_to [; <<Enter outside_of_cafe>>; ],
522 You may think that this is unnecessary madness, but a word to the wise: in
523 a large game, you want action handling going on just in one place when
524 possible, because it will help you to keep track of where things are
525 a-happening if something goes *ploof* (as, believe us, it will; see
526 :doc:`16`). You don't need to be a perfectionist, just cautious.
528 A booth in this kind of situation is an open invitation for the player to
529 step inside and try to change into Captain Fate's costume. We won't let
530 this happen -- the player isn't Clark Kent, after all; later we'll explain
531 how we forbid this action -- and that will force the player to go inside
532 the café, looking for a discreet place to disrobe; but first, let's freeze
533 John Covarth outside Benny's and reflect about a fundamental truth.
535 A hero is not an ordinary person
536 ================================
538 Which is to say, normal actions won't be the same for him.
540 .. Generated by autoindex
542 pair: Sing; library action
544 As you have probably inferred from the previous chapters, some of the
545 library’s standard defined actions are less important than others in making
546 the game advance towards one of its conclusions. The library defines PRAY
547 and SING, for instance, which are of little consequence in a normal gaming
548 situation; each displays an all-purpose message, sufficiently
549 non-committal, and that's it. Of course, if your game includes a magic
550 portal that will reveal itself only if the player lets rip with a snatch of
551 Wagner, you may intercept the :act:`Sing` action in a :prop:`before`
552 property and alter its default, pretty useless behaviour. If not, it's
553 "Your singing is abominable" for you.
555 All actions, useful or not, have a stock of messages associated with them
556 (the messages are held in the ``english.h`` library file and listed in
557 :dm4:`Appendix 4 <sa4.html>` of the |DM4|). We have already seen one way
558 of altering the player character's description -- "As good looking as ever"
559 -- in "William Tell", but the other defaults may also be redefined to suit
560 your tastes and circumstantial needs.
563 pair: LibraryMessages; library object
565 John Covarth, aka Captain Fate, could happily settle for most of these
566 default messages, but we deem it worthwhile to give him some customised
567 responses. If nothing else, this adds to the general atmosphere, a nicety
568 that many players regard as important. For this mission, we make use of
569 the :obj:`LibraryMessages` object.
571 .. include:: /config/typethis.rst
573 .. code-block:: inform
577 Object LibraryMessages ! must be defined between Parser and VerbLib
579 Buy: "Petty commerce interests you only on COUNTED occasions.";
580 Dig: "Your keen senses detect NOTHING underground worth your
581 immediate attention.";
582 Pray: "You won't need to bother almighty DIVINITIES to save
584 Sing: "Alas! That is not one of your many superpowers.";
585 Sleep: "A hero is ALWAYS on the watch.";
586 Strong: "An unlikely vocabulary for a HERO like you.";
587 Swim: "You quickly turn all your ATTENTION towards locating a
588 suitable place to EXERCISE your superior strokes,
589 but alas! you find none.";
592 if (clothes has worn)
593 "In your secret identity's outfit, you manage most
594 efficaciously to look like a two-cent loser, a
595 good-for-nothing wimp.";
597 "Now that you are wearing your costume, you project
598 the image of power UNBOUND, of ballooned,
599 multicoloured MUSCLE, of DASHING yet MODEST chic.";
601 "That's not a verb you need to SUCCESSFULLY save the day.";
603 "That's not something you need to refer to in order to
609 If you provide it, the :obj:`LibraryMessages` object must be defined
610 *between* the inclusion of ``Parser`` and ``VerbLib`` (it won't work
611 otherwise and you’ll get a compiler error). The object contains a single
612 property -- :prop:`before` -- which intercepts display of the default
613 messages that you want to change. An attempt to SING, for example, will
614 now result in "Alas! That is not one of your many superpowers" being
617 In addition to such verb-specific responses, the library defines other
618 messages not directly associated with an action, like the default response
619 when a verb is unrecognised, or if you refer to an object which is not in
620 scope, or indeed many other things. Most of these messages can be accessed
621 through the ``Miscellany entry``, which has a numbered list of responses.
622 The variable ``lm_n`` holds the current value of the number of the message
623 to be displayed, so you can change the default with a test like this:
625 .. code-block:: inform
628 "That's not something you need to refer to in order to SAVE the day.";
630 where 39 is the number for the standard message "That's not something you
631 need to refer to in the course of this game" -- displayed when the player
632 mentions a noun which is listed in a room's name property, as we did for
637 Remember that when we are testing for different values of the same
638 variable, we can also use the switch statement. For the Miscellany
639 entry, the following code would work just as nicely:
641 .. code-block:: inform
647 if (clothes has worn)
648 "In your secret identity's outfit, you manage most
649 efficaciously to look like a two-cent loser, a
650 good-for-nothing wimp.";
652 "Now that you are wearing your costume, you project
653 the image of power UNBOUND, of ballooned,
654 multicoloured MUSCLE, of DASHING yet MODEST chic.";
656 "That's not a verb you need to SUCCESSFULLY save the day.";
658 "That's not something you need to refer to in order to SAVE the day.";
662 pair: LibraryMessages; library object
664 .. Generated by autoindex
666 pair: Miscellany; library action
668 Not surprisingly, the default message for self-examination: "As good
669 looking as ever" is a :act:`Miscellany` entry -- it's number 19 -- so we
670 can change it through the :obj:`LibraryMessages` object instead of, as
671 before, assigning a new string to the ``player.description`` property. In
672 our game, the description of the player character has two states: with
673 street clothes as John Covarth and with the super-hero outfit as Captain
674 Fate; hence the ``if (clothes has worn)`` clause.
676 This discussion of changing our hero's appearance shows that there are
677 different ways of achieving the same result, which is a common situation
678 while designing a game. Problems may be approached from different angles;
679 why use one technique and not another? Usually, the context tips the
680 balance in favour of one solution, though it might happen that you opt for
681 the not-so-hot approach for some overriding reason. Don't feel
682 discouraged; choices like this become more common (and easier) as your
685 .. Ugh. Ghastly, but it does the job.
687 .. |WNL_LATEX| replace:: :latex:`\emph{\textbf{whatever new look}}`
689 .. |WNL_HTML| replace:: :html:`<strong><em>whatever new look</em></strong>`
693 Going back to our example, an alternative approach would be to set the
694 variable ``player.description`` in the ``Initialise`` routine (as we did
695 with "William Tell") to the "ordinary clothes" string, and then later
696 change it as the need arises. It is a variable, after all, and you can
697 alter its value with another statement like ``player.description =``
698 |WNL_LATEX| |WNL_HTML| anywhere in your code. This alternative solution
699 might be better if we intended changing the description of the player
700 many times through the game. Since we plan to have only two states, the
701 :obj:`LibraryMessages` approach will do just fine.
703 A final warning: as we explained when extending the standard verb grammars,
704 you *could* edit the appropriate library file and change all the default
705 messages, but that wouldn't be a sound practice, because your library file
706 will probably not be right for the next game. Use of the
707 :obj:`LibraryMessages` object is strongly advised.
709 If you're typing in the game, you'll probably want to read the brief
710 section on :ref:`compile-as-you-go` prior to performing a test compile.
711 Once everything's correct, it’s time that our hero entered that enticing