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 .. code-block:: inform
65 !============================================================================
66 Constant Story "Captain Fate";
68 "^A simple Inform example
69 ^by Roger Firth and Sonja Kesserich.^";
70 Release 3; Serial "040804"; ! for keeping track of public releases
72 Constant MANUAL_PRONOUNS;
74 Constant OBJECT_SCORE 1;
75 Constant ROOM_SCORE 1;
80 !============================================================================
84 with description "UNDER CONSTRUCTION",
89 Take,Pull,Push,PushDir:
90 "Even though your SCULPTED adamantine muscles are up to the task,
91 you don't favour property damage.";
95 !============================================================================
98 Room street "On the street"
99 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
101 "On one side -- which your HEIGHTENED sense of direction
102 indicates is NORTH -- there's an open cafe now serving
103 lunch. To the south, you can see a phone booth.";
105 !============================================================================
106 ! The player's possessions
108 !============================================================================
109 ! Entry point routines
114 "^^Impersonating mild mannered John Covarth, assistant help boy at an
115 insignificant drugstore, you suddenly STOP when your acute hearing
116 deciphers a stray radio call from the POLICE. There's some MADMAN
117 attacking the population in Granary Park! You must change into your
118 Captain FATE costume fast...!^^";
121 !============================================================================
122 ! Standard and extended grammar
125 !============================================================================
127 Almost everything is familar, apart from a few details:
129 .. code-block:: inform
131 Constant MANUAL_PRONOUNS;
132 Constant MAX_SCORE 2;
133 Constant OBJECT_SCORE 1;
134 Constant ROOM_SCORE 1;
136 By default, Inform uses a system of automatic pronouns: as the player
137 character moves into a room, the library assigns pronouns like IT and HIM
138 to likely objects (if you play "Heidi" or "William Tell" and type PRONOUNS,
139 you can see how the settings change). There is another option. If we
140 declare the ``MANUAL_PRONOUNS`` constant, we force the library to assign
141 pronouns to objects only as the player mentions them (that is, IT will be
142 unassigned until the player types, say, EXAMINE TREE, at which point, IT
143 becomes the TREE ). The behaviour of pronoun assignment is a matter of
144 personal taste; no system is objectively perfect.
146 .. Generated by autoindex
148 pair: score; library variable
149 pair: scored; library attribute
151 Apart from the constant ``MAX_SCORE`` that we have seen in "William Tell",
152 which defines the maximum number of points to be scored, we now see two
153 more constants: ``OBJECT_SCORE`` and ``ROOM_SCORE``. There are several
154 scoring systems predefined in Inform. In "William Tell" we've seen how you
155 can manually add (or subtract) points by changing the value of the variable
156 :var:`score`. Another approach is to award points to players on the first
157 occasion that they (a) enter a particular room, or (b) pick up a particular
158 object. To define that a room or object is indeed “particular”, all you
159 have to do is give it the attribute :attr:`scored`; the library take cares
160 of the rest. The predefined scores are five points for finally reached
161 rooms and four points for wondrous acquisition of objects. With the
162 constants ``OBJECT_SCORE`` and ``ROOM_SCORE`` we can change those defaults;
163 for the sake of example, we've decided to modestly award one point for
164 each. By the way, the use of an equals sign ``=`` is optional with
165 ``Constant``; these two lines have identical effect:
167 .. code-block:: inform
169 Constant ROOM_SCORE 1;
171 Constant ROOM_SCORE = 1;
173 Another difference has to do with a special short-hand method that Inform
174 provides for displaying strings of text. Until now, we have shown you:
176 .. code-block:: inform
178 print "And now for something completely different...^"; return true;
180 print_ret "And now for something completely different...";
182 Both lines do the same thing: they display the quoted string, output a
183 newline character, and return true. As you have seen in the previous
184 example games, this happens quite a lot, so there is a yet shorter way of
185 achieving the same result:
187 .. code-block:: inform
189 "And now for something completely different...";
191 That is, *in a routine* (where the compiler is expecting to find a
192 collection of statements each terminated by a semicolon), a string in
193 double quotes by itself, without the need for any explicit keywords, works
194 exactly as if there were a ``print_ret`` in front of it. Remember that
195 this way of displaying text implies a ``return true`` at the end (which
196 therefore exits from the routine immediately). This detail becomes
197 important if we *don't* want to return true after the string has been
198 displayed on the screen -- we should use the explicit ``print`` statement
201 .. Generated by autoindex
203 pair: name; library property
205 You'll notice that -- unusually for a room -- our ``street`` object has
206 a :prop:`name` property:
208 .. code-block:: inform
210 Room street "On the street"
211 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
214 Rooms aren't normally referenced by name, so this may seem odd. In fact,
215 we're illustrating a feature of Inform: the ability to define dictionary
216 words as "known but irrelevant" in this location. If the player types
217 EXAMINE CITY here, the interpreter will reply "That's not something you
218 need to refer to in order to SAVE the day", rather than the misleading "You
219 can't see any such thing". We mostly prefer to deal with such scenic words
220 using classes like ``Prop`` and ``Furniture``, but sometimes a room's
221 :prop:`name` property is a quick and convenient solution.
223 .. Generated by autoindex
225 pair: container; library attribute
227 In this game, we provide a class named ``Appliance`` to take care of
228 furniture and unmovable objects. You’ll notice that the starting room we
229 have defined has no connections yet. The description mentions a phone
230 booth and a café, so we might want to code those. While the café will be a
231 normal room, it would seem logical that the phone booth is actually a big
232 box on the sidewalk; therefore we define a :attr:`container` set in the
233 street, which players may enter:
235 .. code-block:: inform
237 Appliance booth "phone booth" street
238 with name 'old' 'red' 'picturesque' 'phone' 'booth' 'cabin'
241 "It's one of the old picturesque models, a red cabin with room
245 "The booth is already open.";
247 "There's no way to close this booth.";
251 "With implausible celerity, you dive inside the phone booth.";
253 has enterable container open;
255 What's interesting are the attributes at the end of the definition. You'll
256 recall from Heidi's ``nest`` object that a :attr:`container` is an object
257 capable of having other objects placed in it. If we make something
258 :attr:`enterable`, players count as one of those objects, so that they may
259 squeeze inside. Finally, ``containers`` are, by default, supposed to be
260 closed. You can make them :attr:`openable` if you wish players to be able
261 to OPEN and CLOSE them at will, but this doesn't seem appropriate behaviour
262 for a public cabin -- it would become tedious to have to type OPEN BOOTH
263 and CLOSE BOOTH when these actions provide nothing special -- so we add
264 instead the attribute :attr:`open` (as we did with the nest), telling the
265 interpreter that the container is open from the word go. Players aren't
266 aware of our design, of course; they may indeed try to OPEN and CLOSE the
267 booth, so we trap those actions in a :prop:`before` property which just
268 tells them that these are not relevant options. The :prop:`after` property
269 gives a customised message to override the library’s default for commands
270 like ENTER BOOTH or GO INSIDE BOOTH.
272 Since in the street's description we have told players that the phone booth
273 is to the south, they might also try typing SOUTH. We must intercept this
274 attempt and redirect it (while we're at it, we add a connection to the
275 as-yet-undefined café room and a default message for the movement which is
278 .. code-block:: inform
280 Room street "On the street"
281 with name city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
283 "On one side -- which your HEIGHTENED sense of direction
284 indicates is NORTH -- there's an open cafe now serving
285 lunch. To the south, you can see a phone booth.",
287 s_to [; <<Enter booth>>; ],
289 "No time now for exploring! You'll move much faster in your
290 Captain FATE costume.";
292 That takes care of entering the booth. But what about leaving it? Players
293 may type EXIT or OUT while they are inside an enterable container and the
294 interpreter will oblige but, again, they might type NORTH. This is a
295 problem, since we are actually in the street (albeit inside the booth) and
296 to the north we have the café. We may provide for this condition in the
297 room's :prop:`before` property:
299 .. code-block:: inform
303 if (player in booth && noun == n_obj) <<Exit booth>>;
306 Since we are outdoors and the booth provides a shelter, it's not impossible
307 that a player may try just IN, which is a perfectly valid connection.
308 However, that would be an ambiguous command, for it could also refer to the
309 café, so we express our bafflement and force the player to try something
312 .. code-block:: inform
315 s_to [; <<Enter booth>>; ],
316 in_to "But which way?",
318 Now everything seems to be fine, except for a tiny detail. We've said
319 that, while in the booth, the player character’s location is still the
320 ``street`` room, regardless of being inside a :attr:`container`; if players
321 chanced to type LOOK, they'd get:
323 .. code-block:: transcript
325 On the street (in the phone booth)
326 On one side -- which your HEIGHTENED sense of direction indicates is NORTH --
327 there's an open cafe now serving lunch. To the south, you can see a
330 Hardly an adequate description while *inside* the booth. There are several
331 ways to fix the problem, depending on the result you wish to achieve. The
332 library provides a property called :prop:`inside_description` which you can
333 utilise with enterable containers. It works pretty much like the normal
334 :prop:`description` property, but it gets printed only when the player is
335 inside the container. The library makes use of this property in a very
336 clever way, because for every LOOK action it checks whether we can see
337 outside the container: if the container has the :attr:`transparent`
338 attribute set, or if it happens to be :attr:`open`, the library displays
339 the normal :prop:`description` of the room first and then the
340 :prop:`inside_description` of the container. If the library decides we
341 can’t see outside the container, only the :prop:`inside_description` is
342 displayed. Take for instance the following (simplified) example:
344 .. code-block:: inform
346 Room stage "On stage"
348 "The stage is filled with David Copperfield's
349 magical contraptions.",
352 Object magic_box "magic box" stage
354 "A big elongated box decorated with silver stars, where
355 scantily clad ladies make a disappearing act.",
357 "The inside panels of the magic box are covered with black
358 velvet. There is a tiny switch by your right foot.",
360 has container openable enterable light;
362 Now, the player would be able to OPEN BOX and ENTER BOX. A player who
363 tried a LOOK would get:
365 .. code-block:: transcript
367 On stage (in the magic box)
368 The stage is filled with David Copperfield's magical contraptions.
370 The inside panels of the magic box are covered with black velvet. There is a
371 tiny switch by your right foot.
373 If now the player closes the box and LOOKs:
375 .. code-block:: transcript
377 On stage (in the magic box)
378 The inside panels of the magic box are covered with black velvet. There is a
379 tiny switch by your right foot.
381 In our case, however, we don't wish the description of the street to be
382 displayed at all (even if a caller is supposedly able to see the street
383 while inside a booth). The problem is that we have made the booth an
384 :attr:`open` container, so the street's description would be displayed
385 every time. There is another solution. We can make the
386 :prop:`description` property of the ``street`` room a bit more complex, and
387 change its value: instead of a string, we write an embedded routine.
388 Here's the (almost) finished room:
390 .. code-block:: inform
392 Room street "On the street"
393 with name 'city' 'buildings' 'skyscrapers' 'shops' 'apartments' 'cars',
396 "From this VANTAGE point, you are rewarded with a broad view
397 of the sidewalk and the entrance to Benny's cafe.";
399 "On one side -- which your HEIGHTENED sense of direction
400 indicates is NORTH -- there's an open cafe now serving
401 lunch. To the south, you can see a phone booth.";
405 if (player in booth && noun == n_obj) <<Exit booth>>;
408 s_to [; <<Enter booth>>; ],
409 in_to "But which way?",
411 "No time now for exploring! You'll move much faster in your
412 Captain FATE costume.";
414 The description while inside the booth mentions the sidewalk, which
415 might invite the player to EXAMINE it. No problem:
417 .. code-block:: inform
419 Appliance "sidewalk" street
420 with name sidewalk' 'pavement' 'street',
423 "You make a quick surveillance of the sidewalk and discover much
424 to your surprise that it looks JUST like any other sidewalk in
427 Unfortunately, both descriptions also mention the café, which will be a
428 room and therefore not, from the outside, an examinable object. The
429 player may enter it and will get whatever description we code as the
430 result of a LOOK action (which will have to do with the way the café
431 looks from the *inside*); but while we are on the street we need
432 something else to describe it:
434 .. code-block:: inform
436 Appliance outside_of_cafe "Benny's cafe" street
437 with name 'benny^s' 'cafe' 'entrance',
439 "The town's favourite for a quick snack, Benny's cafe has a 50's
443 print "With an impressive mixture of hurry and nonchalance
444 you step into the open cafe.^";
448 has enterable proper;
450 .. index:: accented characters
454 Although the text of our guide calls Benny's establishment a "café" --
455 note the acute "e" -- the game itself simplifies this to "cafe". We do
456 this for clarity, not because Inform doesn't support accented
457 characters. The |DM4| explains in detail how to display these
458 characters in :dm4:`§1.11 <s1.html#s1_11>` "*How text is printed*" and
459 provides the whole Z-machine character set in Table 2. In our case, we
460 could have displayed this::
462 The town's favourite for a quick snack, Benny's café has a 50's ROCKETSHIP look.
464 by defining the :prop:`description` property as any of these:
466 .. code-block:: inform
469 "The town's favourite for a quick snack, Benny's caf@'e has a 50's
473 "The town's favourite for a quick snack, Benny's caf@@170 has a 50's
477 "The town's favourite for a quick snack, Benny's caf@{E9} has a 50's
480 However, all three forms are harder to read than the vanilla "cafe", so
481 we've opted for the simple life.
483 Unlike the sidewalk object, we offer more than a mere description. Since
484 the player may try ENTER CAFE as a reasonable way of access -- which would
485 have confused the interpreter immensely -- we take the opportunity of
486 making this object also :attr:`enterable`, and we cheat a little. The
487 attribute :attr:`enterable` has permitted the verb ENTER to be applied to
488 this object, but this is not a :attr:`container`; we want the player to be
489 sent into the *real* café room instead. The :prop:`before` property handles
490 this, intercepting the action, displaying a message and teleporting the
491 player into the café. We ``return true`` to inform the interpreter that we
492 have taken care of the :act:`Enter` action ourselves, so it can stop right
495 .. Generated by autoindex
497 pair: n_to; library property
499 As a final detail, note that we now have two ways of going into the café:
500 the :prop:`n_to` property of the ``street`` room and the :act:`Enter`
501 action of the ``outside_of_cafe`` object. A perfectionist might point out
502 that it would be neater to handle the actual movement of the player in just
503 one place of our code, because this helps clarity. To achieve this, we
504 redirect the street's :prop:`n_to` property thus:
506 .. code-block:: inform
508 n_to [; <<Enter outside_of_cafe>>; ],
510 You may think that this is unnecessary madness, but a word to the wise: in
511 a large game, you want action handling going on just in one place when
512 possible, because it will help you to keep track of where things are
513 a-happening if something goes *ploof* (as, believe us, it will; see
514 :doc:`16`). You don't need to be a perfectionist, just cautious.
516 A booth in this kind of situation is an open invitation for the player to
517 step inside and try to change into Captain Fate's costume. We won't let
518 this happen -- the player isn't Clark Kent, after all; later we'll explain
519 how we forbid this action -- and that will force the player to go inside
520 the café, looking for a discreet place to disrobe; but first, let's freeze
521 John Covarth outside Benny's and reflect about a fundamental truth.
523 A hero is not an ordinary person
524 ================================
526 Which is to say, normal actions won't be the same for him.
528 .. Generated by autoindex
530 pair: Sing; library action
532 As you have probably inferred from the previous chapters, some of the
533 library’s standard defined actions are less important than others in making
534 the game advance towards one of its conclusions. The library defines PRAY
535 and SING, for instance, which are of little consequence in a normal gaming
536 situation; each displays an all-purpose message, sufficiently
537 non-committal, and that's it. Of course, if your game includes a magic
538 portal that will reveal itself only if the player lets rip with a snatch of
539 Wagner, you may intercept the :act:`Sing` action in a :prop:`before`
540 property and alter its default, pretty useless behaviour. If not, it's
541 "Your singing is abominable" for you.
543 All actions, useful or not, have a stock of messages associated with them
544 (the messages are held in the ``english.h`` library file and listed in
545 :dm4:`Appendix 4 <sa4.html>` of the |DM4|). We have already seen one way
546 of altering the player character's description -- "As good looking as ever"
547 -- in "William Tell", but the other defaults may also be redefined to suit
548 your tastes and circumstantial needs.
551 pair: LibraryMessages; library object
553 John Covarth, aka Captain Fate, could happily settle for most of these
554 default messages, but we deem it worthwhile to give him some customised
555 responses. If nothing else, this adds to the general atmosphere, a nicety
556 that many players regard as important. For this mission, we make use of
557 the :obj:`LibraryMessages` object.
559 .. code-block:: inform
563 Object LibraryMessages ! must be defined between Parser and VerbLib
565 Buy: "Petty commerce interests you only on COUNTED occasions.";
566 Dig: "Your keen senses detect NOTHING underground worth your
567 immediate attention.";
568 Pray: "You won't need to bother almighty DIVINITIES to save
570 Sing: "Alas! That is not one of your many superpowers.";
571 Sleep: "A hero is ALWAYS on the watch.";
572 Strong: "An unlikely vocabulary for a HERO like you.";
573 Swim: "You quickly turn all your ATTENTION towards locating a
574 suitable place to EXERCISE your superior strokes,
575 but alas! you find none.";
578 if (clothes has worn)
579 "In your secret identity's outfit, you manage most
580 efficaciously to look like a two-cent loser, a
581 good-for-nothing wimp.";
583 "Now that you are wearing your costume, you project
584 the image of power UNBOUND, of ballooned,
585 multicoloured MUSCLE, of DASHING yet MODEST chic.";
587 "That's not a verb you need to SUCCESSFULLY save the day.";
589 "That's not something you need to refer to in order to
595 If you provide it, the :obj:`LibraryMessages` object must be defined
596 *between* the inclusion of ``Parser`` and ``VerbLib`` (it won't work
597 otherwise and you’ll get a compiler error). The object contains a single
598 property -- :prop:`before` -- which intercepts display of the default
599 messages that you want to change. An attempt to SING, for example, will
600 now result in "Alas! That is not one of your many superpowers" being
603 In addition to such verb-specific responses, the library defines other
604 messages not directly associated with an action, like the default response
605 when a verb is unrecognised, or if you refer to an object which is not in
606 scope, or indeed many other things. Most of these messages can be accessed
607 through the ``Miscellany entry``, which has a numbered list of responses.
608 The variable ``lm_n`` holds the current value of the number of the message
609 to be displayed, so you can change the default with a test like this:
611 .. code-block:: inform
614 "That's not something you need to refer to in order to SAVE the day.";
616 where 39 is the number for the standard message "That's not something you
617 need to refer to in the course of this game" -- displayed when the player
618 mentions a noun which is listed in a room's name property, as we did for
623 Remember that when we are testing for different values of the same
624 variable, we can also use the switch statement. For the Miscellany
625 entry, the following code would work just as nicely:
627 .. code-block:: inform
633 if (clothes has worn)
634 "In your secret identity's outfit, you manage most
635 efficaciously to look like a two-cent loser, a
636 good-for-nothing wimp.";
638 "Now that you are wearing your costume, you project
639 the image of power UNBOUND, of ballooned,
640 multicoloured MUSCLE, of DASHING yet MODEST chic.";
642 "That's not a verb you need to SUCCESSFULLY save the day.";
644 "That's not something you need to refer to in order to SAVE the day.";
648 pair: LibraryMessages; library object
650 .. Generated by autoindex
652 pair: Miscellany; library action
654 Not surprisingly, the default message for self-examination: "As good
655 looking as ever" is a :act:`Miscellany` entry -- it's number 19 -- so we
656 can change it through the :obj:`LibraryMessages` object instead of, as
657 before, assigning a new string to the ``player.description`` property. In
658 our game, the description of the player character has two states: with
659 street clothes as John Covarth and with the super-hero outfit as Captain
660 Fate; hence the ``if (clothes has worn)`` clause.
662 This discussion of changing our hero's appearance shows that there are
663 different ways of achieving the same result, which is a common situation
664 while designing a game. Problems may be approached from different angles;
665 why use one technique and not another? Usually, the context tips the
666 balance in favour of one solution, though it might happen that you opt for
667 the not-so-hot approach for some overriding reason. Don't feel
668 discouraged; choices like this become more common (and easier) as your
671 .. Ugh. Ghastly, but it does the job.
673 .. |WNL_LATEX| replace:: :latex:`\emph{\textbf{whatever new look}}`
675 .. |WNL_HTML| replace:: :html:`<strong><em>whatever new look</em></strong>`
679 Going back to our example, an alternative approach would be to set the
680 variable ``player.description`` in the ``Initialise`` routine (as we did
681 with "William Tell") to the "ordinary clothes" string, and then later
682 change it as the need arises. It is a variable, after all, and you can
683 alter its value with another statement like ``player.description =``
684 |WNL_LATEX| |WNL_HTML| anywhere in your code. This alternative solution
685 might be better if we intended changing the description of the player
686 many times through the game. Since we plan to have only two states, the
687 :obj:`LibraryMessages` approach will do just fine.
689 A final warning: as we explained when extending the standard verb grammars,
690 you *could* edit the appropriate library file and change all the default
691 messages, but that wouldn't be a sound practice, because your library file
692 will probably not be right for the next game. Use of the
693 :obj:`LibraryMessages` object is strongly advised.
695 If you're typing in the game, you'll probably want to read the brief
696 section on :ref:`compile-as-you-go` prior to performing a test compile.
697 Once everything's correct, it’s time that our hero entered that enticing