7 | *I was an innkeeper, who loved to carouse;*
8 | *J was a joiner, and built up a house.*
12 .. image:: /images/picI.png
19 n even the simplest story, there's bound to be scope for the player to
20 attempt activities that you hadn't anticipated. Sometimes there may be
21 alternative ways of approaching a problem: if you can't be sure which
22 approach the player will take, you really ought to allow for all
23 possibilities. Sometimes the objects you create and the descriptions you
24 provide may suggest to the player that doing such-and-such should be
25 possible, and, within reason, you ought to allow for that also. The basic
26 game design is easy: what takes the time, and makes a game large and
27 complex, is taking care of all the *other* things that the player may think
30 Here, we try to illustrate what this means by addressing a few of the more
31 glaring deficiencies in our first game.
36 Here's a fragment of the game being played:
38 .. code-block:: transcript
41 Through the dense foliage, you glimpse a building to the west. A track heads
44 You can see a baby bird here.
47 Too young to fly, the nestling tweets helplessly.
50 You hear nothing unexpected.
54 That's not too smart, is it? Our description specifically calls the
55 player's attention to the sound of the bird -- and then she finds out that
56 we've got nothing special to say about its helpless tweeting.
58 The library has a stock of actions and responses for each of the game's
59 defined verbs, so it can handle most of the player's input with a default,
60 standard behaviour instead of remaining impertinently silent or saying that
61 it doesn't understand what the player intends. "You hear nothing
62 unexpected" is the library's standard LISTEN response, good enough after
63 LISTEN TO NEST or LISTEN TO TREE, but fairly inappropriate here; we really
64 need to substitute a more relevant response after LISTEN TO BIRD. Here's
67 .. code-block:: inform6
69 Object bird "baby bird" forest
70 with description "Too young to fly, the nestling tweets helplessly.",
71 name 'baby' 'bird' 'nestling',
74 print "It sounds scared and in need of assistance.^";
79 We'll go through this a step at a time:
81 #. We've added a new ``before`` property to our bird object. The
82 interpreter looks at the property *before* attempting to perform any
83 action which is directed specifically at this object::
87 #. The value of the property is an embedded routine, containing a label and
91 print "It sounds scared and in need of assistance.^";
94 #. The label is the name of an action, in this case ``Listen``. What we're
95 telling the interpreter is: if the action that you're about to perform
96 on the bird is a ``Listen``, execute these statements first; if it's any
97 other action, carry on as normal. So, if the player types EXAMINE BIRD,
98 PICK UP BIRD, PUT BIRD IN NEST, HIT BIRD or FONDLE BIRD, then she'll get
99 the standard response. If she types LISTEN TO BIRD, then our two
100 statements get executed before anything else happens. We call this
101 "trapping" or "intercepting" the action of Listening to the bird.
103 #. The two statements that we execute are, first::
105 print "It sounds scared and in need of assistance.^";
107 which causes the interpreter to display the string given in double
108 quotes; remember that a ``^`` character in a string appears as a
109 newline. Second, we execute::
113 which tells the interpreter that it doesn't need to do anything else,
114 because we've handled the ``Listen`` action ourselves. And the game now
115 behaves like this -- perfect:
117 .. code-block:: transcript
120 It sounds scared and in need of assistance.
124 The use of the ``return true`` statement probably needs a bit more
125 explanation. An object's ``before`` property traps an action aimed at that
126 object right at the start, before the interpreter has started to do
127 anything. That's the point at which the statements in the embedded routine
128 are executed. If the last of those statements is ``return true`` then the
129 interpreter assumes that the action has been dealt with by those
130 statements, and so there's nothing left to do: no action, no message;
131 nothing. On the other hand, if the last of the statements is ``return
132 false`` then the interpreter carries on to perform the default action as
133 though it hadn't been intercepted. Sometimes that's what you want it to
134 do, but not here: if instead we'd written this:
136 .. code-block:: inform6
138 Object bird "baby bird" forest
139 with description "Too young to fly, the nestling tweets helplessly.",
140 name 'baby' 'bird' 'nestling',
143 print "It sounds scared and in need of assistance.^";
148 then the interpreter would first have displayed our string, and then
149 carried on with its normal response, which is to display the standard
152 .. code-block:: transcript
155 It sounds scared and in need of assistance.
156 You hear nothing unexpected.
160 This technique -- intercepting an action aimed at a particular object in
161 order to do something appropriate for that object -- is one that we'll use
167 At the start of the game the player character stands "outside a cottage", which
168 might lead her to believe that she can go inside:
170 .. code-block:: transcript
172 In front of a cottage
173 You stand outside a cottage. The forest stretches east.
176 You can't go that way.
180 Again, that isn't perhaps the most appropriate response, but it's easy to
183 .. code-block:: inform6
185 Object before_cottage "In front of a cottage"
187 "You stand outside a cottage. The forest stretches east.",
189 in_to "It's such a lovely day -- much too nice to go inside.",
190 cant_go "The only path lies to the east.",
193 The ``in_to`` property would normally link to another room, in the same way
194 as the ``e_to`` property contain the internal ID of the ``forest`` object.
195 However, if instead you set its value to be a string, the interpreter
196 displays that string when the player tries the IN direction. Other --
197 unspecified -- directions like NORTH and UP still elicit the standard "You
198 can't go that way" response, but we can change that too, by supplying a
199 ``cant_go`` property whose value is a suitable string. We then get this
200 friendlier behaviour:
202 .. code-block:: transcript
204 In front of a cottage
205 You stand outside a cottage. The forest stretches east.
208 It's such a lovely day -- much too nice to go inside.
211 The only path lies to the east.
218 There's another issue here; since we haven't actually implemented an object
219 to represent the cottage, a perfectly reasonable EXAMINE COTTAGE command
220 receives the obviously nonsensical reply "You can't see any such thing".
221 That's easy to fix; we can add a new ``cottage`` object, making it a piece
222 of ``scenery`` just like the ``tree``:
224 .. code-block:: inform6
226 Object cottage "tiny cottage" before_cottage
227 with description "It's small and simple, but you're very happy here.",
228 name 'tiny' 'cottage' 'home' 'house' 'hut' 'shed' 'hovel',
231 This solves the problem, but promptly gives us another unreasonable
234 .. code-block:: transcript
236 In front of a cottage
237 You stand outside a cottage. The forest stretches east.
240 That's not something you can enter.
244 The situation here is similar to our LISTEN TO BIRD problem, and the
245 solution we adopt is similar as well:
247 .. code-block:: inform6
249 Object cottage "tiny cottage" before_cottage
250 with description "It's small and simple, but you're very happy here.",
251 name 'tiny' 'cottage' 'home' 'house' 'hut' 'shed' 'hovel',
254 print_ret "It's such a lovely day -- much too nice to go inside.";
258 We use a ``before`` property to intercept the ``Enter`` action applied to
259 the cottage object, so that we can display a more appropriate message.
260 This time, however, we've done it using one statement rather than two. It
261 turns out that the sequence "``print`` a string which ends with a newline
262 character, and then ``return true``" is so frequently needed that there's a
263 special statement which does it all. That is, this single statement (where
264 you'll note that the string *doesn't* need to end in ``^``)::
266 print_ret "It's such a lovely day -- much too nice to go inside.";
268 works exactly the same as this pair of statements::
270 print "It's such a lovely day -- much too nice to go inside.^";
273 We could have used the shorter form when handling LISTEN TO BIRD, and we
274 *will* use it from now on.
279 In the clearing, holding the nest and looking at the tree, the player is
280 meant to type UP. Just as likely, though, she'll try CLIMB TREE (which
281 currently gives the completely misleading response "I don't think much is
282 to be achieved by that"). Yet another opportunity to use a ``before``
283 property, but now with a difference.
285 .. code-block:: inform6
287 Object tree "tall sycamore tree" clearing
289 "Standing proud in the middle of the clearing,
290 the stout tree looks easy to climb.",
291 name 'tall' 'sycamore' 'tree' 'stout' 'proud',
294 PlayerTo(top_of_tree);
299 This time, when we intercept the ``Climb`` action applied to the ``tree``
300 object, it's not in order to display a better message; it's because we want
301 to move the player character to another room, just as if she'd typed UP.
302 Relocating the player character is actually quite a complex business, but
303 fortunately all of that complexity is hidden: there's a standard **library
304 routine** to do the job, not one that we've written, but one that's
305 provided as part of the Inform system.
307 You'll remember that, when we first mentioned routines (see "Standalone
308 routines" on page 57), we used the example of ``Initialise()`` and said
309 that "the routine's name followed by opening and closing parentheses is all
310 that it takes to call a routine". That was true for ``Initialise()``, but
311 not quite the whole story. To move the player character, we've got to
312 specify where we want her to go, and we do that by supplying the internal
313 ID of the destination room within the opening and closing parentheses.
314 That is, instead of just ``PlayerTo()`` we call ``PlayerTo(top_of_tree)``,
315 and we describe ``top_of_tree`` as the routine's **argument**.
317 Although we've moved the player character to another room, we're still in
318 the middle of the intercepted ``Climb`` action. As previously, we need to
319 tell the interpreter that we've dealt with the action, and so we don't want
320 the standard rejection message to be displayed. The ``return true``
321 statement does that, as usual.
323 Dropping objects from the tree
324 ==============================
326 In a normal room like the ``forest`` or the ``clearing``, the player can
327 DROP something she's carrying and it'll effectively fall to the ground at
328 her feet. Simple, convenient, predictable -- except when the player is at
329 the top of the tree. Should she DROP something from up there, having it
330 land nearby might seem a bit improbable; much more likely that it would
331 fall to the clearing below.
333 It looks like we might want to intercept the ``Drop`` action, but not quite
334 in the way we've been doing up until now. For one thing, we don't want to
335 complicate the definitions of the ``bird`` and the ``nest`` and any other
336 objects we may introduce: much better to find a general solution that will
337 work for all objects. And second, we need to recognise that not all
338 objects are droppable; the player can't, for example, DROP THE BRANCH.
340 The best approach to the second problem is to intercept the ``Drop`` action
341 *after* it has occurred, rather than beforehand. That way, we let the
342 library take care of objects which aren't being held or which can't be
343 dropped, and only become involved once a ``Drop`` has been successful. And
344 the best approach to the first problem is to do this particular
345 interception not on an object-by-object basis, as we have been doing so
346 far, but instead for every ``Drop`` which takes place in our troublesome
347 ``top_of_tree`` room. This is what we have to write:
349 .. code-block:: inform6
351 Object top_of_tree "At the top of the tree"
352 with description "You cling precariously to the trunk.",
356 move noun to clearing;
361 Let's again take it a step at a time:
363 #. We've added a new ``after`` property to our ``top_of_tree`` object. The
364 interpreter looks at the property *subsequent to* performing any action in
369 #. The value of the property is an embedded routine, containing a label and
373 move noun to clearing;
376 #. The label is the name of an action, in this case ``Drop``. What we're
377 telling the interpreter is: if the action that you've just performed
378 here is a ``Drop``, execute these statements before telling the player
379 what you've done; if it's any other action, carry on as normal.
381 #. The two statements that we execute are first::
383 move noun to clearing;
385 which takes the object which has just been moved from the ``player``
386 object to the ``top_of_tree`` object (by the successful ``Drop`` action)
387 and moves it again so that its parent becomes the ``clearing`` object.
388 That ``noun`` is a library variable that always contains the internal ID
389 of the object which is the target of the current action. If the player
390 types DROP NEST, ``noun`` contains the internal ID of the ``nest``
391 object; if she types DROP NESTLING then ``noun`` contains the internal
392 ID of the ``bird`` object. Second, we execute::
396 which tells the interpreter that it should now let the player know
397 what's happened. Here's the result of all this:
399 .. code-block:: transcript
401 At the top of the tree
402 You cling precariously to the trunk.
404 You can see a wide firm bough here.
411 At the top of the tree
412 You cling precariously to the trunk.
414 You can see a wide firm bough here.
419 A tall sycamore stands in the middle of this clearing. The path winds
420 southwest through the trees.
422 You can see a bird's nest (in which is a baby bird) here.
426 Of course, you might think that the standard message "Dropped" is slightly
427 unhelpful in these non-standard circumstances. If you prefer to hint at
428 what's just happened, you could use this alternative solution:
430 .. code-block:: inform6
432 Object top_of_tree "At the top of the tree"
433 with description "You cling precariously to the trunk.",
437 move noun to clearing;
438 print_ret "Dropped... to the ground far below.";
442 The ``print_ret`` statement does two things for us: displays a more
443 informative message, and returns ``true`` to tell the interpreter that
444 there's no need to let the player know what's happened -- we've handled
447 Is the bird in the nest?
448 ========================
450 The game ends when the player character puts the nest onto the branch. Our
451 assumption here is that the bird is inside the nest, but this might not be
452 so; the player may have first taken up the bird and then gone back for the
453 nest, or vice versa. It would be better not to end the game until we'd
454 checked for the bird actually being in the nest; fortunately, that's easy
457 .. code-block:: inform6
459 Object branch "wide firm bough" top_of_tree
460 with description "It's flat enough to support a small object.",
461 name 'wide' 'firm' 'flat' 'bough' 'branch',
462 each_turn [; if (bird in nest && nest in branch) deadflag = 2; ],
463 has static supporter;
465 The extended ``if`` statement::
467 if (bird in nest && nest in branch) deadflag = 2;
469 should now be read as: "Test whether the ``bird`` is currently in (or on)
470 the ``nest``, *and* whether the ``nest`` is currently on (or in) the
471 ``branch``; if both parts are ``true``, set the value of ``deadflag`` to 2;
472 otherwise, do nothing".
477 You should by now have some appreciation of the need not only to handle the
478 obvious actions which were at the forefront of your mind when designing the
479 game, but also as many as you can of the other possible ways that a player
480 may choose to interact with the objects presented to her. Some of those
481 ways will be highly intelligent, some downright dumb; in either case you
482 should try to ensure that the game's response is at least sensible, even
483 when you're telling the player "sorry, you can't do that".
485 The new topics that we've encountered here include these:
487 .. rubric:: Object properties
489 Objects can have a ``before`` property -- if there is one, the interpreter
490 looks at it *before* performing an action which in some way involves that
491 object. Similarly, you can provide an ``after`` property, which the
492 interpreter looks at *after* performing an action but before telling the
493 player what's happened. Both ``before`` and ``after`` properties can be
494 used not only with tangible objects like the ``bird``, ``cottage`` and
495 ``tree`` (when they intercept actions aimed at that particular object) but
496 also with rooms (when they intercept actions aimed at any object in that
499 The value of each ``before`` and ``after`` property is an embedded routine.
500 If such a routine ends with ``return false``, the interpreter then carries
501 on with the next stage of the action which has been intercepted; if it ends
502 with ``return true``, the interpreter does nothing further for that action.
503 By combining these possibilities, you can supplement the work done by a
504 standard action with statements of your own, or you can replace a standard
507 Previously, we've seen connection properties used with the internal ID of
508 the room to which they lead. In this chapter, we showed that the value
509 could also be a string (explaining why movement in that direction isn't
510 possible). Here are examples of both, and also of the ``cant_go`` property
511 which provides just such an explanation for *all* connections that aren't
515 in_to "It's such a lovely day -- much too nice to go inside.",
516 cant_go "The only path lies to the east.",
518 .. rubric:: Routines and arguments
520 The library includes a number of useful routines, available to perform
521 certain common tasks if you require them; there's a list in "Library
522 routines" on page 264. We used the ``PlayerTo`` routine, which moves the
523 player character from her current room to another one -- not necessarily
524 adjacent to the first room.
526 When calling ``PlayerTo``, we had to tell the library which room is the
527 destination. We did this by supplying that room's internal ID within
532 A value given in parentheses like that is called an **argument** of the
533 routine. In fact, a routine can have more than one argument; if so,
534 they're separated by commas. For example, to move the player character to
535 a room *without* displaying that room's description, we could have supplied
538 PlayerTo(clearing,1);
540 In this example, the effect of the ``1`` is to prevent the description
543 .. rubric:: Statements
545 We encountered several new statements:
550 We used these at the end of embedded routines to control what the
551 interpreter did next.
555 ``print_ret "string";``
556 The ``print`` statement simply displays the string of characters
557 represented here by *string*. The ``print_ret`` statement also does
558 that, then outputs a newline character, and finally executes a ``return
561 ``if (condition && condition ) ...``
562 We extended the simple ``if`` statement that we met before. The ``&&``
563 (to be read as "and") is an operator commonly used when testing for
564 more than one condition at the same time. It means "if this condition
565 is true *and* this condition is also true *and* ..." There's also a
566 ``||`` operator, to be read as "or", and a "not" operator ``~~``, which
567 turns true into false and vice versa.
571 In addition, there are ``&``, ``|`` and ``~`` operators, but they do
572 a rather different job and are much less common. Take care not to
575 ``move obj_id to parent_obj_id;``
576 The ``move`` statement rearranges the object tree, by making the first
577 ``obj_id`` a child of the ``parent_obj_id``.
581 We've talked a lot about intercepting actions like ``Listen``, ``Enter``,
582 ``Climb`` and ``Drop``. An action is a generalised representation of
583 something to be done, determined by the verb which the player types. For
584 example, the verbs HEAR and LISTEN are ways of saying much the same thing,
585 and so both result in the same action: ``Listen``. Similarly, verbs like
586 ENTER, GET INTO, SIT ON and WALK INSIDE all lead to an action of ``Enter``,
587 CLIMB and SCALE lead to Climb, and DISCARD, DROP, PUT DOWN and THROW all
588 lead to ``Drop``. This makes life much easier for the designer; although
589 Inform defines quite a lot of actions, there are many fewer than there are
590 ways of expressing those same actions using English verbs.
592 Each action is represented internally by a number, and the value of the
593 current action is stored in a library variable called, erm, ``action``.
594 Two more variables are also useful here: ``noun`` holds the internal ID of
595 the object which is the focus of the action, and ``second`` holds the
596 internal ID of the secondary object (if there is one). Here are some
599 =============================== ====== ======= =======
600 Player types action noun second
601 ------------------------------- ------ ------- -------
602 LISTEN Listen nothing nothing
603 LISTEN TO THE BIRD Listen bird nothing
604 PICK UP THE BIRD Take bird nothing
605 PUT BIRD IN NEST Insert bird nest
606 DROP THE NEST Drop nest nothing
607 PUT NEST ON BRANCH PutOn nest branch
608 =============================== ====== ======= =======
610 The value ``nothing`` is a built-in constant (like ``true`` and ``false``)
611 which means, well, there isn't any object to refer to. There's a list of
612 standard library actions in "Group 1 actions" on page 270, "Group 2
613 actions" on page 271 and "Group 3 actions" on page 271.
615 We've now reached the end of our first game. In these three chapters we've
616 shown you the basic principles on which almost all games are based, and
617 introduced you to many of the components that you'll need when creating
618 more interesting IF. We suggest that you take one last look at the source
619 code (see "Heidi" story on page 213), and then move on to the next stage.