7 | |CENTER| *I was an innkeeper, who loved to carouse;*
8 | |CENTER| *J was a joiner, and built up a house.*
12 .. image:: /images/picI.png
15 |I|\n even the simplest story, there's bound to be scope for the player to
16 attempt activities that you hadn't anticipated. Sometimes there may be
17 alternative ways of approaching a problem: if you can't be sure which
18 approach the player will take, you really ought to allow for all
19 possibilities. Sometimes the objects you create and the descriptions you
20 provide may suggest to the player that doing such-and-such should be
21 possible, and, within reason, you ought to allow for that also. The basic
22 game design is easy: what takes the time, and makes a game large and
23 complex, is taking care of all the *other* things that the player may think
26 Here, we try to illustrate what this means by addressing a few of the more
27 glaring deficiencies in our first game.
32 Here's a fragment of the game being played:
34 .. code-block:: transcript
37 Through the dense foliage, you glimpse a building to the west. A track heads
40 You can see a baby bird here.
43 Too young to fly, the nestling tweets helplessly.
46 You hear nothing unexpected.
50 That's not too smart, is it? Our description specifically calls the
51 player's attention to the sound of the bird -- and then she finds out that
52 we've got nothing special to say about its helpless tweeting.
54 The library has a stock of actions and responses for each of the game's
55 defined verbs, so it can handle most of the player's input with a default,
56 standard behaviour instead of remaining impertinently silent or saying that
57 it doesn't understand what the player intends. "You hear nothing
58 unexpected" is the library's standard LISTEN response, good enough after
59 LISTEN TO NEST or LISTEN TO TREE, but fairly inappropriate here; we really
60 need to substitute a more relevant response after LISTEN TO BIRD. Here's
63 .. code-block:: inform
65 Object bird "baby bird" forest
66 with description "Too young to fly, the nestling tweets helplessly.",
67 name 'baby' 'bird' 'nestling',
70 print "It sounds scared and in need of assistance.^";
75 We'll go through this a step at a time:
77 #. We've added a new ``before`` property to our bird object. The
78 interpreter looks at the property *before* attempting to perform any
79 action which is directed specifically at this object::
83 #. The value of the property is an embedded routine, containing a label and
87 print "It sounds scared and in need of assistance.^";
90 #. The label is the name of an action, in this case ``Listen``. What we're
91 telling the interpreter is: if the action that you're about to perform
92 on the bird is a ``Listen``, execute these statements first; if it's any
93 other action, carry on as normal. So, if the player types EXAMINE BIRD,
94 PICK UP BIRD, PUT BIRD IN NEST, HIT BIRD or FONDLE BIRD, then she'll get
95 the standard response. If she types LISTEN TO BIRD, then our two
96 statements get executed before anything else happens. We call this
97 "trapping" or "intercepting" the action of Listening to the bird.
99 #. The two statements that we execute are, first::
101 print "It sounds scared and in need of assistance.^";
103 which causes the interpreter to display the string given in double
104 quotes; remember that a ``^`` character in a string appears as a
105 newline. Second, we execute::
109 which tells the interpreter that it doesn't need to do anything else,
110 because we've handled the ``Listen`` action ourselves. And the game now
111 behaves like this -- perfect:
113 .. code-block:: transcript
116 It sounds scared and in need of assistance.
120 The use of the ``return true`` statement probably needs a bit more
121 explanation. An object's ``before`` property traps an action aimed at that
122 object right at the start, before the interpreter has started to do
123 anything. That's the point at which the statements in the embedded routine
124 are executed. If the last of those statements is ``return true`` then the
125 interpreter assumes that the action has been dealt with by those
126 statements, and so there's nothing left to do: no action, no message;
127 nothing. On the other hand, if the last of the statements is ``return
128 false`` then the interpreter carries on to perform the default action as
129 though it hadn't been intercepted. Sometimes that's what you want it to
130 do, but not here: if instead we'd written this:
132 .. code-block:: inform
134 Object bird "baby bird" forest
135 with description "Too young to fly, the nestling tweets helplessly.",
136 name 'baby' 'bird' 'nestling',
139 print "It sounds scared and in need of assistance.^";
144 then the interpreter would first have displayed our string, and then
145 carried on with its normal response, which is to display the standard
148 .. code-block:: transcript
151 It sounds scared and in need of assistance.
152 You hear nothing unexpected.
156 This technique -- intercepting an action aimed at a particular object in
157 order to do something appropriate for that object -- is one that we'll use
163 At the start of the game the player character stands "outside a cottage", which
164 might lead her to believe that she can go inside:
166 .. code-block:: transcript
168 In front of a cottage
169 You stand outside a cottage. The forest stretches east.
172 You can't go that way.
176 Again, that isn't perhaps the most appropriate response, but it's easy to
179 .. code-block:: inform
181 Object before_cottage "In front of a cottage"
183 "You stand outside a cottage. The forest stretches east.",
185 in_to "It's such a lovely day -- much too nice to go inside.",
186 cant_go "The only path lies to the east.",
189 The ``in_to`` property would normally link to another room, in the same way
190 as the ``e_to`` property contain the internal ID of the ``forest`` object.
191 However, if instead you set its value to be a string, the interpreter
192 displays that string when the player tries the IN direction. Other --
193 unspecified -- directions like NORTH and UP still elicit the standard "You
194 can't go that way" response, but we can change that too, by supplying a
195 ``cant_go`` property whose value is a suitable string. We then get this
196 friendlier behaviour:
198 .. code-block:: transcript
200 In front of a cottage
201 You stand outside a cottage. The forest stretches east.
204 It's such a lovely day -- much too nice to go inside.
207 The only path lies to the east.
214 There's another issue here; since we haven't actually implemented an object
215 to represent the cottage, a perfectly reasonable EXAMINE COTTAGE command
216 receives the obviously nonsensical reply "You can't see any such thing".
217 That's easy to fix; we can add a new ``cottage`` object, making it a piece
218 of ``scenery`` just like the ``tree``:
220 .. code-block:: inform
222 Object cottage "tiny cottage" before_cottage
223 with description "It's small and simple, but you're very happy here.",
224 name 'tiny' 'cottage' 'home' 'house' 'hut' 'shed' 'hovel',
227 This solves the problem, but promptly gives us another unreasonable
230 .. code-block:: transcript
232 In front of a cottage
233 You stand outside a cottage. The forest stretches east.
236 That's not something you can enter.
240 The situation here is similar to our LISTEN TO BIRD problem, and the
241 solution we adopt is similar as well:
243 .. code-block:: inform
245 Object cottage "tiny cottage" before_cottage
246 with description "It's small and simple, but you're very happy here.",
247 name 'tiny' 'cottage' 'home' 'house' 'hut' 'shed' 'hovel',
250 print_ret "It's such a lovely day -- much too nice to go inside.";
254 We use a ``before`` property to intercept the ``Enter`` action applied to
255 the cottage object, so that we can display a more appropriate message.
256 This time, however, we've done it using one statement rather than two. It
257 turns out that the sequence "``print`` a string which ends with a newline
258 character, and then ``return true``" is so frequently needed that there's a
259 special statement which does it all. That is, this single statement (where
260 you'll note that the string *doesn't* need to end in ``^``)::
262 print_ret "It's such a lovely day -- much too nice to go inside.";
264 works exactly the same as this pair of statements::
266 print "It's such a lovely day -- much too nice to go inside.^";
269 We could have used the shorter form when handling LISTEN TO BIRD, and we
270 *will* use it from now on.
275 In the clearing, holding the nest and looking at the tree, the player is
276 meant to type UP. Just as likely, though, she'll try CLIMB TREE (which
277 currently gives the completely misleading response "I don't think much is
278 to be achieved by that"). Yet another opportunity to use a ``before``
279 property, but now with a difference.
281 .. code-block:: inform
283 Object tree "tall sycamore tree" clearing
285 "Standing proud in the middle of the clearing,
286 the stout tree looks easy to climb.",
287 name 'tall' 'sycamore' 'tree' 'stout' 'proud',
290 PlayerTo(top_of_tree);
295 This time, when we intercept the ``Climb`` action applied to the ``tree``
296 object, it's not in order to display a better message; it's because we want
297 to move the player character to another room, just as if she'd typed UP.
298 Relocating the player character is actually quite a complex business, but
299 fortunately all of that complexity is hidden: there's a standard
300 :term:`library routine` to do the job, not one that we've written, but one
301 that's provided as part of the Inform system.
303 You'll remember that, when we first mentioned routines (see
304 :ref:`standalone-routines`), we used the example of ``Initialise()`` and
305 said that "the routine's name followed by opening and closing parentheses
306 is all that it takes to call a routine". That was true for
307 ``Initialise()``, but not quite the whole story. To move the player
308 character, we've got to specify where we want her to go, and we do that by
309 supplying the internal ID of the destination room within the opening and
310 closing parentheses. That is, instead of just ``PlayerTo()`` we call
311 ``PlayerTo(top_of_tree)``, and we describe ``top_of_tree`` as the routine's
314 Although we've moved the player character to another room, we're still in
315 the middle of the intercepted ``Climb`` action. As previously, we need to
316 tell the interpreter that we've dealt with the action, and so we don't want
317 the standard rejection message to be displayed. The ``return true``
318 statement does that, as usual.
320 Dropping objects from the tree
321 ==============================
323 In a normal room like the ``forest`` or the ``clearing``, the player can
324 DROP something she's carrying and it'll effectively fall to the ground at
325 her feet. Simple, convenient, predictable -- except when the player is at
326 the top of the tree. Should she DROP something from up there, having it
327 land nearby might seem a bit improbable; much more likely that it would
328 fall to the clearing below.
330 It looks like we might want to intercept the ``Drop`` action, but not quite
331 in the way we've been doing up until now. For one thing, we don't want to
332 complicate the definitions of the ``bird`` and the ``nest`` and any other
333 objects we may introduce: much better to find a general solution that will
334 work for all objects. And second, we need to recognise that not all
335 objects are droppable; the player can't, for example, DROP THE BRANCH.
337 The best approach to the second problem is to intercept the ``Drop`` action
338 *after* it has occurred, rather than beforehand. That way, we let the
339 library take care of objects which aren't being held or which can't be
340 dropped, and only become involved once a ``Drop`` has been successful. And
341 the best approach to the first problem is to do this particular
342 interception not on an object-by-object basis, as we have been doing so
343 far, but instead for every ``Drop`` which takes place in our troublesome
344 ``top_of_tree`` room. This is what we have to write:
346 .. code-block:: inform
348 Object top_of_tree "At the top of the tree"
349 with description "You cling precariously to the trunk.",
353 move noun to clearing;
358 Let's again take it a step at a time:
360 #. We've added a new ``after`` property to our ``top_of_tree`` object. The
361 interpreter looks at the property *subsequent to* performing any action in
366 #. The value of the property is an embedded routine, containing a label and
370 move noun to clearing;
373 #. The label is the name of an action, in this case ``Drop``. What we're
374 telling the interpreter is: if the action that you've just performed
375 here is a ``Drop``, execute these statements before telling the player
376 what you've done; if it's any other action, carry on as normal.
378 #. The two statements that we execute are first::
380 move noun to clearing;
382 which takes the object which has just been moved from the ``player``
383 object to the ``top_of_tree`` object (by the successful ``Drop`` action)
384 and moves it again so that its parent becomes the ``clearing`` object.
385 That ``noun`` is a library variable that always contains the internal ID
386 of the object which is the target of the current action. If the player
387 types DROP NEST, ``noun`` contains the internal ID of the ``nest``
388 object; if she types DROP NESTLING then ``noun`` contains the internal
389 ID of the ``bird`` object. Second, we execute::
393 which tells the interpreter that it should now let the player know
394 what's happened. Here's the result of all this:
396 .. code-block:: transcript
398 At the top of the tree
399 You cling precariously to the trunk.
401 You can see a wide firm bough here.
408 At the top of the tree
409 You cling precariously to the trunk.
411 You can see a wide firm bough here.
416 A tall sycamore stands in the middle of this clearing. The path winds
417 southwest through the trees.
419 You can see a bird's nest (in which is a baby bird) here.
423 Of course, you might think that the standard message "Dropped" is slightly
424 unhelpful in these non-standard circumstances. If you prefer to hint at
425 what's just happened, you could use this alternative solution:
427 .. code-block:: inform
429 Object top_of_tree "At the top of the tree"
430 with description "You cling precariously to the trunk.",
434 move noun to clearing;
435 print_ret "Dropped... to the ground far below.";
439 The ``print_ret`` statement does two things for us: displays a more
440 informative message, and returns ``true`` to tell the interpreter that
441 there's no need to let the player know what's happened -- we've handled
444 Is the bird in the nest?
445 ========================
447 The game ends when the player character puts the nest onto the branch. Our
448 assumption here is that the bird is inside the nest, but this might not be
449 so; the player may have first taken up the bird and then gone back for the
450 nest, or vice versa. It would be better not to end the game until we'd
451 checked for the bird actually being in the nest; fortunately, that's easy
454 .. code-block:: inform
456 Object branch "wide firm bough" top_of_tree
457 with description "It's flat enough to support a small object.",
458 name 'wide' 'firm' 'flat' 'bough' 'branch',
459 each_turn [; if (bird in nest && nest in branch) deadflag = 2; ],
460 has static supporter;
462 The extended ``if`` statement::
464 if (bird in nest && nest in branch) deadflag = 2;
466 should now be read as: "Test whether the ``bird`` is currently in (or on)
467 the ``nest``, *and* whether the ``nest`` is currently on (or in) the
468 ``branch``; if both parts are ``true``, set the value of ``deadflag`` to 2;
469 otherwise, do nothing".
474 You should by now have some appreciation of the need not only to handle the
475 obvious actions which were at the forefront of your mind when designing the
476 game, but also as many as you can of the other possible ways that a player
477 may choose to interact with the objects presented to her. Some of those
478 ways will be highly intelligent, some downright dumb; in either case you
479 should try to ensure that the game's response is at least sensible, even
480 when you're telling the player "sorry, you can't do that".
482 The new topics that we've encountered here include these:
487 Objects can have a ``before`` property -- if there is one, the interpreter
488 looks at it *before* performing an action which in some way involves that
489 object. Similarly, you can provide an ``after`` property, which the
490 interpreter looks at *after* performing an action but before telling the
491 player what's happened. Both ``before`` and ``after`` properties can be
492 used not only with tangible objects like the ``bird``, ``cottage`` and
493 ``tree`` (when they intercept actions aimed at that particular object) but
494 also with rooms (when they intercept actions aimed at any object in that
497 The value of each ``before`` and ``after`` property is an embedded routine.
498 If such a routine ends with ``return false``, the interpreter then carries
499 on with the next stage of the action which has been intercepted; if it ends
500 with ``return true``, the interpreter does nothing further for that action.
501 By combining these possibilities, you can supplement the work done by a
502 standard action with statements of your own, or you can replace a standard
505 Previously, we've seen connection properties used with the internal ID of
506 the room to which they lead. In this chapter, we showed that the value
507 could also be a string (explaining why movement in that direction isn't
508 possible). Here are examples of both, and also of the ``cant_go`` property
509 which provides just such an explanation for *all* connections that aren't
513 in_to "It's such a lovely day -- much too nice to go inside.",
514 cant_go "The only path lies to the east.",
518 Routines and arguments
519 ----------------------
521 The library includes a number of useful routines, available to perform
522 certain common tasks if you require them; there's a list in
523 :ref:`library-routines`. We used the ``PlayerTo`` routine, which moves the
524 player character from her current room to another one -- not necessarily
525 adjacent to the first room.
527 When calling ``PlayerTo``, we had to tell the library which room is the
528 destination. We did this by supplying that room's internal ID within
533 A value given in parentheses like that is called an :term:`argument` of the
534 routine. In fact, a routine can have more than one argument; if so,
535 they're separated by commas. For example, to move the player character to
536 a room *without* displaying that room's description, we could have supplied
539 PlayerTo(clearing,1);
541 In this example, the effect of the ``1`` is to prevent the description
547 We encountered several new statements:
552 We used these at the end of embedded routines to control what the
553 interpreter did next.
557 ``print_ret "string";``
558 The ``print`` statement simply displays the string of characters
559 represented here by *string*. The ``print_ret`` statement also does
560 that, then outputs a newline character, and finally executes a ``return
563 ``if (condition && condition ) ...``
564 We extended the simple ``if`` statement that we met before. The ``&&``
565 (to be read as "and") is an operator commonly used when testing for
566 more than one condition at the same time. It means "if this condition
567 is true *and* this condition is also true *and* ..." There's also a
568 ``||`` operator, to be read as "or", and a "not" operator ``~~``, which
569 turns true into false and vice versa.
573 In addition, there are ``&``, ``|`` and ``~`` operators, but they do
574 a rather different job and are much less common. Take care not to
577 ``move obj_id to parent_obj_id;``
578 The ``move`` statement rearranges the object tree, by making the first
579 ``obj_id`` a child of the ``parent_obj_id``.
583 We've talked a lot about intercepting actions like ``Listen``, ``Enter``,
584 ``Climb`` and ``Drop``. An action is a generalised representation of
585 something to be done, determined by the verb which the player types. For
586 example, the verbs HEAR and LISTEN are ways of saying much the same thing,
587 and so both result in the same action: ``Listen``. Similarly, verbs like
588 ENTER, GET INTO, SIT ON and WALK INSIDE all lead to an action of ``Enter``,
589 CLIMB and SCALE lead to Climb, and DISCARD, DROP, PUT DOWN and THROW all
590 lead to ``Drop``. This makes life much easier for the designer; although
591 Inform defines quite a lot of actions, there are many fewer than there are
592 ways of expressing those same actions using English verbs.
594 Each action is represented internally by a number, and the value of the
595 current action is stored in a library variable called, erm, ``action``.
596 Two more variables are also useful here: ``noun`` holds the internal ID of
597 the object which is the focus of the action, and ``second`` holds the
598 internal ID of the secondary object (if there is one). Here are some
601 =============================== ====== ======= =======
602 Player types action noun second
603 ------------------------------- ------ ------- -------
604 LISTEN Listen nothing nothing
605 LISTEN TO THE BIRD Listen bird nothing
606 PICK UP THE BIRD Take bird nothing
607 PUT BIRD IN NEST Insert bird nest
608 DROP THE NEST Drop nest nothing
609 PUT NEST ON BRANCH PutOn nest branch
610 =============================== ====== ======= =======
612 The value ``nothing`` is a built-in constant (like ``true`` and ``false``)
613 which means, well, there isn't any object to refer to. There's a list of
614 standard library actions in :ref:`group-1-actions`, :ref:`group-2-actions`
615 and :ref:`group-3-actions`.
617 We've now reached the end of our first game. In these three chapters we've
618 shown you the basic principles on which almost all games are based, and
619 introduced you to many of the components that you'll need when creating
620 more interesting IF. We suggest that you take one last look at the source
621 code (see :doc:`/appendices/b`), and then move on to the next stage.