Do a bunch of proofreading fixes.
[ibg.git] / chapters / 12.rst
1 ====================
2 Captain Fate: take 3
3 ====================
4
5 .. epigraph::
6
7    | *W was a watchman, and guarded the door;*
8    | *X was expensive, and so became poor.*
9
10 .. only:: html
11
12    .. image:: /images/picW.png
13       :align: left
14
15 .. raw:: latex
16
17    \dropcap{w}
18
19 e've given ourselves an interesting challenge by overusing that 
20 convenient word "toilet", and here we show you how we resolve the 
21 ambiguities that have been introduced. Also, it's time for the eponymous 
22 owner of Benny's café to be developed in full.
23
24 Too many toilets
25 ================
26
27 If you check the ``name`` properties of the toilet door, the toilet key 
28 and the toilet room, you’ll see that the dictionary word ``'toilet'`` 
29 occurs in all of them. There won't be any problems if players mention 
30 the words DOOR or KEY, but we reach a strange impasse should they try to 
31 perform some action with just the word TOILET. The interpreter has to 
32 think fast: is the player talking about the key? About the door? Or 
33 about the toilet? Unable to decide, it asks: "Which do you mean, the 
34 door to the toilet, the toilet key or the toilet?"
35
36 And guess what? Players will never be able to refer to the toilet object 
37 (unless they type BATH ROOM or REST ROOM, not an obvious choice since we 
38 haven't used those phrases anywhere visible). If the player answers 
39 TOILET the parser will still have three objects with that dictionary 
40 word as a possible name, so it will ask again, and again -- until we 
41 give it some dictionary word which is not ambiguous. A human reader 
42 would be able to understand that the word TOILET alone refers to the 
43 room, but the interpreter won't -- unless we help it a little.
44
45 We could work around this problem in more than one way, but we'll take 
46 this opportunity of demonstrating the use of a third-party library 
47 package.
48
49 When experienced designers find a problem which is not easily solvable, 
50 they may come up with a smart solution and then consider that others 
51 could benefit from the effort. The product of this generosity takes the 
52 form of a library extension: the solution neatly packaged as a file that 
53 other designers can incorporate into their source code. These files can 
54 be found in the IF Archive: go to 
55 http://mirror.ifarchive.org/indexes/if-archive.html and then select 
56 "``.../infocom``", "``.../compilers``", "``.../inform6``", 
57 "``.../library``", and "``.../contributions``". All of these files 
58 contain Inform code. To use a library extension (also known as a library 
59 contribution), you should download it and read the instructions (usually 
60 embedded as comments in the file, but occasionally supplied separately) 
61 to discover what to do next. Normally, you ``Include`` it (as we have 
62 already done with ``Parser``, ``VerbLib`` and ``Grammar``), but often 
63 there are rules about where exactly this Include should be placed in 
64 your source code. It is not unusual to find other suggestions and 
65 warnings.
66
67 To help us out of the disambiguation problem with the word TOILET, we are
68 going to use Neil Cerutti's extension ``pname.h``, which is designed for
69 situations precisely like this. First, we follow the link to the IF archive
70 and download the compressed file ``pname.zip``, which contains two more
71 files: ``pname.h`` and ``pname.txt``. We place these files in the folder
72 where we are currently developing our game or, if using the environment we
73 proposed in :doc:`02`, in the ``Inform\Lib\Contrib`` folder. The text file
74 offers instructions about installation and usage. Here we find a warning:
75
76   This version of pname.h is recommended for use only with version 6/10 
77   of the Inform Library.
78
79 We're actually using a later version, but this doesn't seem to cause a 
80 problem. Most extensions aren't so fussy, but ``pname.h`` fiddles with 
81 some routines at the heart of the standard library; these may not be 
82 identical in other Inform versions.
83
84 The introduction explains what ``pname.h`` does for you; namely, it lets 
85 you avoid using complicated ``parse_name`` routines to disambiguate the 
86 player's input when the same dictionary word refers to more than one 
87 item. A ``parse_name`` routine would have been the solution to our 
88 problem before the existence of this file, and it qualifies as an 
89 advanced programming topic, difficult to master on a first approach. 
90 Fortunately, we don't need to worry. Neil Cerutti explains:
91
92   The ``pname.h`` package defines a new object property, ``pname`` 
93   (short for phrase name), with a similar look and feel to the standard 
94   ``name`` property: both contain a list of dictionary words. However, 
95   in a ``pname`` property the order of the words is significant, and 
96   special operators ``'.p'`` ``'.or'`` and ``'.x'`` enable you to embed 
97   some intelligence into the list. In most cases where the standard 
98   ``name`` property isn't enough, you can now just replace it with a 
99   ``pname`` property, rather than write a ``parse_name`` property 
100   routine.
101
102 We'll soon see how it works. Let's take a look at the installation 
103 instructions:
104
105   To incorporate this package into your program, do three things:
106
107   #.  Add four lines near the head of the program (before you include 
108       ``Parser.h``).
109
110       .. code-block:: inform
111
112          Replace MakeMatch;
113          Replace Identical;
114          Replace NounDomain;
115          Replace TryGivenObject;
116
117   #.  Include the ``pname.h`` header just after you include ``Parser.h``.
118
119       .. code-block:: inform
120
121          Include "Parser";
122          Include "pname";
123
124   #.  Add ``pname`` properties to those objects which require phrase 
125       recognition.
126
127 It seems simple enough. So, following steps one and two, we add those 
128 ``Replace...`` lines before the inclusion of ``Parser``, and we include 
129 ``pname.h`` right after it. ``Replace`` tells the compiler that we're 
130 providing replacements for some standard routines.
131
132 .. code-block:: inform
133
134   Constant Story "Captain Fate";
135   Constant Headline
136               "^A simple Inform example
137                ^by Roger Firth and Sonja Kesserich.^";
138   Release 3; Serial "040804";     ! for keeping track of public releases
139
140   Constant MANUAL_PRONOUNS;
141
142   Replace MakeMatch;              ! requited by pname.h
143   Replace Identical;
144   Replace NounDomain;
145   Replace TryGivenObject;
146
147   Include "Parser";
148   Include "pname";
149   ...
150
151 Now our source code is ready to benefit from the library package. How 
152 does it work? We have acquired a new property -- ``pname`` -- which can 
153 be added to some of our objects, and which works pretty much like a 
154 ``name`` property. In fact, it should be used *instead* of a ``name`` 
155 property where we have a disambiguation problem. Let’s change the 
156 relevant lines for the toilet door and the toilet key:
157
158 .. code-block:: inform
159
160   Object  toilet_door
161     with  pname '.x' 'red' '.x' 'toilet' 'door',
162           short_name [;
163           ...
164
165   Object  toilet_key "toilet key" benny
166     with  pname '.x' 'toilet' 'key',
167           article "the",
168           ...
169
170 while leaving the ``outside_of_toilet`` unchanged:
171
172 .. code-block:: inform
173
174   Object  outside_of_toilet "toilet" cafe
175     with  name 'toilet' 'bath' 'rest' 'room' 'bathroom' 'restroom',
176           before [;
177           ...
178
179 We are now using a new operator -- ``'.x'`` -- in our ``pname`` word 
180 lists. explains
181
182   The first dictionary word to the right of a ``'.x'`` operator is 
183   interpreted as optional.
184
185 and this makes the dictionary word ``'toilet'`` of lesser importance for 
186 these objects, so that at run-time players could refer to the DOOR or 
187 TOILET DOOR or the KEY or TOILET KEY -- but not simply to the TOILET -- 
188 when referring to either the door or the key. And, by leaving unchanged 
189 the name property of the ``outside_of_toilet`` object – where there is also 
190 another ``'toilet'`` entry -- the ``pname`` properties will tell the 
191 interpreter to discard the key and the door as possible objects to be 
192 considered when players refer just to TOILET. Looking at it in terms of 
193 the English language, we've effectively said that "TOILET" is an 
194 adjective in the phrases "TOILET DOOR" and "TOILET KEY", but a noun when 
195 used on its own to refer to the room.
196
197 The ``pname.h`` package has additional functionality to deal with more 
198 complex phrases, but we don't need it in our example game. Feel free, 
199 however, to read ``pname.txt`` and discover what this fine library 
200 extension can do for you: it's an easy answer to many a disambiguation 
201 headache.
202
203
204 Don't shoot! I'm only the barman
205 ================================
206
207 A lot of the action of the game happens around Benny, and his definition 
208 needs a little care. Let's explain what we want to happen.
209
210   So the door is locked and the player, after discovering what the note 
211   stuck on the toilet door said, will eventually ask Benny for the key. 
212   Sadly, Benny allows use of the toilet only to customers, a remark 
213   he'll make looking pointedly at the menu board behind him. The player 
214   will have to ask for a coffee first, thereby qualifying as a customer 
215   in Benny's eyes and thus entitled to make use of the toilet. At last! 
216   Rush inside, change into Captain Fate’s costume and fly away to save 
217   the day!
218
219 Except that the player neither paid for the coffee, nor returned the 
220 toilet key. Benny will have to stop the player from leaving the café in 
221 these circumstances. To prevent unnecessary complication, there will be 
222 a coin near the lavatory, enough cash to pay for the coffee. And that 
223 about sums it all up; pretty simple to describe -- not so simple to 
224 code. Remember Benny's basic definition from the previous chapter:
225
226 .. code-block:: inform
227
228   Object  benny "Benny" cafe
229     with  name 'benny',
230           description
231               "A deceptively FAT man of uncanny agility, Benny entertains his
232                customers crushing coconuts against his forehead when the mood
233                strikes him.",
234     has   scenery animate male proper transparent;
235
236 We can now add some complexity, beginning with a ``life`` property. In 
237 generic form:
238
239 .. code-block:: inform
240
241   life [;
242     Give:             !... code for giving objects to Benny
243     Attack:           !... code to deal with player's aggressive moves
244     Kiss:             !... code about the player getting tender on Benny
245     Ask,Tell,Answer:  !... code to handle conversation
246   ],
247
248 We have seen some of these actions before. We'll take care of the easier 
249 ones:
250
251 .. code-block:: inform
252
253   Attack:
254     if (costume has worn) {
255         deadflag = 4;
256         print "Before the horror-stricken eyes of the surrounding
257                people, you MAGNIFICENTLY jump OVER the counter and
258                attack Benny with REMARKABLE, albeit NOT sufficient,
259                speed. Benny receives you with a TREACHEROUS upper-cut
260                that sends your GRANITE JAW flying through the cafe.^^
261                ~These guys in pyjamas think they can bully innocent
262                folk,~ snorts Benny, as the EERIE hands of DARKNESS
263                engulf your vision and you lose consciousness.";
264     }
265     else
266         "That would be an unlikely act for MEEK John Covarth.";
267
268     Kiss:
269       "This is no time for MINDLESS infatuation.";
270
271     Ask,Tell,Answer:
272       "Benny is too busy for idle chit-chat.";
273
274 Attacking Benny is not wise. If the player is still dressed as John 
275 Covarth, the game displays a message refusing to use violence by reason 
276 of staying in character as a worthless wimp. However, if Captain Fate 
277 attempts the action, we'll find that there is more to Benny than meets 
278 the eye, and the game is lost. Kissing and conversation are disallowed 
279 by a couple of tailored responses.
280
281 The Give action is a bit more complicated, since Benny reacts to certain 
282 objects in a special and significant way. Bear in mind that Benny's 
283 definition needs to keep track of whether the player has asked for a 
284 coffee (thereby becoming a customer and thus worthy of the key), whether 
285 the coffee has been paid for, and whether the toilet key has been 
286 returned. The solution, yet again (this really is a most useful 
287 capability), is more local property variables:
288
289 .. code-block:: inform
290
291   Object  benny "Benny" cafe
292     with  name 'benny',
293           description
294               "A deceptively FAT man of uncanny agility, Benny entertains his
295                customers crushing coconuts against his forehead when the mood
296                strikes him.",
297           coffee_asked_for false,          ! has player asked for a coffee?
298           coffee_not_paid  false,          ! is Benny waiting to be paid?
299           key_not_returned false,          ! is Benny waiting for the key?
300           live [;
301           ...
302
303 Now we are ready to tackle the ``Give`` action of the ``life`` property, 
304 which deals with commands like GIVE THE KEY TO BENNY (in a moment, we'll 
305 come to the ``Give`` action of the ``orders`` property, which deals with 
306 commands like BENNY, GIVE ME THE KEY):
307
308 .. code-block:: inform
309
310   Give:
311     switch (noun) {
312       clothes:
313         "You NEED your unpretentious John Covarth clothes.";
314       costume:
315         "You NEED your stupendous ACID-PROTECTIVE suit.";
316       toilet_key:
317         self.key_not_returned = false;
318         move toilet_key to benny;
319         "Benny nods as you ADMIRABLY return his key.";
320       coin:
321         remove coin;
322         self.coffee_not_paid = false;
323         print "With marvellous ILLUSIONIST gestures, you produce the
324                coin from the depths of your ";
325         if (costume has worn) print "BULLET-PROOF costume";
326         else                  print "ordinary street clothes";
327         " as if it had dropped on the counter from Benny's ear!
328          People around you clap politely. Benny takes the coin
329          and gives it a SUSPICIOUS bite. ~Thank you, sir. Come
330          back anytime,~ he says.";
331     }
332
333 The Give action in the ``life`` property holds the variable ``noun`` as 
334 the object offered to the NPC. Remember that we can use the ``switch`` 
335 statement as shorthand for:
336
337 .. code-block:: inform
338
339   if (noun == costume) { whatever };
340   if (noun == clothes) { whatever };
341   ...
342
343 We won't let players give away their clothes or their costume (yes, an
344 improbable action, but you never know). The toilet key and the coin are
345 successfully transferred. The property ``key_not_returned`` will be set to
346 true when we receive the toilet key from Benny (we have not coded that bit
347 yet), and now, when we give it back, it's reset to ``false``.  The ``move``
348 statement is in charge of the actual transfer of the object from the
349 player's inventory to Benny, and we finally display a confirmation
350 message. With the coin, we find a new statement: ``remove``. This extracts
351 the object from the object tree, so that it now has no parent. The effect
352 is to make it disappear from the game (though you are not destroying the
353 object permanently -- and indeed you could return it to the object tree
354 using the ``move`` statement); as far as the player is concerned, there
355 isn’t a COIN to be found anywhere. The ``coffee_not_paid`` property will be
356 set to true when Benny serves us the cup of coffee (again, we’ll see that
357 in a moment); now we reset it to ``false``, which liberates the player from
358 debt. This culminates with the ``"..."`` print-and-return statement,
359 telling the player that the action was successful. In passing, remember
360 that in :ref:`homely-atmos` we defined the counter such that PUT KEY ON
361 COUNTER is automatically translated into GIVE KEY TO BENNY .
362
363 Why move the key to Benny but remove the coin instead? Once players 
364 qualify as customers by ordering a coffee, they will be able to ask for 
365 the key and return it as many times as they like, so it seems sensible 
366 to keep the key around. The coin, however, will be a one-shot. We won't 
367 let players ask for more than one coffee, to prevent their debt from 
368 growing ad infinitum -- besides, they came in here to change, not to 
369 indulge in caffeine. Once the coin is paid, it disappears for good, 
370 supposedly into Benny's greedy pockets. No need to worry about it any 
371 more.
372
373 The benny object needs also an ``orders`` property, just to take care of 
374 the player's requests for coffee and the key, and to fend off any other 
375 demands. The ``Give`` action in an ``orders`` property deals with inputs 
376 like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is 
377 similar to that of the ``life`` property:
378
379 .. code-block:: inform
380
381   orders [;   ! handles ASK BENNY FOR X and BENNY, GIVE ME XXX
382     Give:
383       if (second ~= player or nothing) "Benny looks at you strangely.";
384       switch (noun) {
385         toilet_key:
386           if (toilet_key in player) "But you DO have the key already.";
387           if (self.coffee_asked_for == true)
388               if (toilet_key in self) {
389                   move toilet_key to player;
390                   self.key_not_returned = true;
391                   "Benny tosses the key to the rest rooms on the
392                    counter, where you grab it with a dextrous and
393                    precise movement of your HYPER-AGILE hand.";
394               }
395               else
396                   "~Last place I saw that key, it was in YOUR
397                    possession,~ grumbles Benny. ~Be sure to return it
398                    before you leave.~";
399           else
400               "~Toilet is only fer customers,~ he grumbles, looking
401                pointedly at a menu board behind him.";
402         coffee:
403           if (self.coffee_asked_for == true)
404               "One coffee should be enough.";
405           move coffee to counter;
406           self.coffee_asked_for = self.coffee_not_paid = true;
407           "With two gracious steps, Benny places his world-famous
408            Cappuccino in front of you.";
409         food:         
410           "Food will take too much time, and you must change NOW.";
411         menu:
412           "With only the smallest sigh, Benny nods towards the menu
413            on the wall behind him.";
414         default:
415           "~I don't think that's on the menu, sir.~";
416       }
417   ],
418
419 * We test the value of ``second`` in order to trap over-generous 
420   gestures such as BENNY, GIVE COFFEE TO CUSTOMERS . Then we consider 
421   potential requests.
422
423 * **Toilet key:** first, we check whether players already have the key 
424   or not, and complain if they do, stopping execution thanks to the 
425   implicit ``return true`` of the ``"..."`` statement. If players don’t 
426   have the  key, we proceed to check whether they've asked for a coffee 
427   yet, by testing the ``coffee_asked_for`` property. If this is true , 
428   we should also check if the key is actually one of Benny’s 
429   possessions -- a perverse player could get the key, then drop it 
430   somewhere and ask for it again; if this should happen, we indicate 
431   that Benny is nobody's fool with the message ``"~Last place I saw 
432   that key..."``. Once all these fitting conditions are ``true``, 
433   players will get the key, which means that they have to return it -- 
434   the ``key_not_returned`` property becomes ``true`` -- and we display 
435   a suitable message. However, if the player didn't ask for a coffee, 
436   Benny refuses to oblige, mentioning for the first time the menu board 
437   where players will be able to see a picture of a cup of coffee when 
438   they EXAMINE it. Take care to see how all the ``else`` clauses pair 
439   up with the appropriate if statements, triggering responses for each 
440   of the conditions that wasn't met.
441
442 * **Coffee:** we check whether players have already asked for a coffee, 
443   by testing the ``coffee_asked_for`` property, and refuse to serve 
444   another one if ``true``. If ``false``, we place the coffee on the 
445   counter, and set the properties ``coffee_asked_for`` and 
446   ``coffee_not_paid`` to ``true``. The message bit you know about.
447
448 * **Food:** we'll provide an object to deal with all of the delicious 
449   comestibles to be found in the café, specifically those (such as 
450   "pastries and sandwiches") mentioned in our descriptions. Although 
451   that object is not yet defined, we code ahead to thwart player's 
452   gluttony in case they choose to ask Benny for food.
453
454 * **Menu:** our default response -- "I don’t think that’s on the menu, 
455   sir" -- isn’t very appropriate if the player asks for a menu, so we 
456   provide a better one.
457
458 * **Default:** this takes care of anything else that the player asks 
459   Benny for, displaying his curt response.
460
461 And before you know it, Benny's object is out of the way; however, don't
462 celebrate too soon. There’s still some Benny-related behaviour that, 
463 curiously enough, doesn’t happen in Benny's object; we're talking about 
464 Benny's reaction if the player tries to leave without paying or 
465 returning the key. We promised you that Benny would stop the player, and 
466 indeed he will. But where?
467
468 We must revisit the café room object:
469
470 .. code-block:: inform
471
472   Room     cafe "Inside Benny's cafe"
473     with   description
474                "Benny's offers the FINEST selection of pastries and sandwiches.
475                 Customers clog the counter, where Benny himself manages to
476                 serve, cook and charge without missing a step. At the north side
477                 of the cafe you can see a red door connecting with the toilet.",
478            before [;
479              Go:   ! The player is about to depart. Is he making for the street?
480                if (noun ~= s_obj) return false;
481                if (benny.coffee_not_paid == true ||
482                    benny.key_not_returned == true) {
483                    print "Just as you are stepping into the street, the big hand
484                           of Benny falls on your shoulder.";
485                    if (benny.coffee_not_paid == true &&
486                        benny.key_not_returned == true)
487                        "^^~Hey! You've got my key and haven't paid for the
488                         coffee. Do I look like a chump?~ You apologise as only a
489                         HERO knows how to do and return inside.";
490                    if (benny.coffee_not_paid == true)
491                        "^^~Just waidda minute here, Mister,~ he says.
492                         ~Sneaking out without paying, are you?~ You quickly 
493                         mumble an excuse and go back into the cafe. Benny
494                         returns to his chores with a mistrusting eye.";
495                    if (benny.key_not_returned == true)
496                        "^^~Just where you think you're going with the toilet
497                         key?~ he says. ~You a thief?~ As Benny forces you back
498                         into the cafe, you quickly assure him that it was only
499                         a STUPEFYING mistake.";
500                }     
501                if (costume has worn) {
502                    deadflag = 5;           ! you win!
503                    "You step onto the sidewalk, where the passing pedestrians
504                     recognise the rainbow EXTRAVAGANZA of Captain FATE's costume
505                     and cry your name in awe as you JUMP with sensational
506                     momentum into the BLUE morning skies!";
507                }
508            ],
509            first_time_out false,           ! Captain Fate's first appearance?
510            after [;
511              Go:   ! The player has just arrived. Did he come from the toilet?
512                if (noun ~= s_obj) return false;
513                if (costume has worn && self.first_time_out == false) {
514                    self.first_time_out = true;
515                    StartDaemon(customers);
516                }
517            ],
518            s_to  street,
519            n_to  toilet_door;
520
521 Once again, we find that the solution to a design problem is not 
522 necessarily unique. Remember what we saw when dealing with the player's 
523 description: we could have assigned a new value to the 
524 ``player.description`` variable, but opted to use the 
525 ``LibraryMessages`` object instead. This is a similar case. The code 
526 causing Benny to intercept the forgetful player could have been added, 
527 perhaps, to a ``daemon`` property in Benny’s definition. However, since 
528 the action to be intercepted is always the same one and happens to be a 
529 movement action when the player tries to leave the café room, it is also 
530 possible to code it by trapping the ``Go`` action of the room object. 
531 Both would have been right, but this is somewhat simpler.
532
533 We have added a ``before`` property to the room object (albeit a longish 
534 one), just dealing with the ``Go`` action. As we mentioned in an earlier 
535 chapter, this technique lets you trap the player who is about to exit a 
536 room before the movement actually takes place, a good moment to 
537 interfere if we want to prevent escape. The first line:
538
539 .. code-block:: inform
540
541   if (noun ~= s_obj) return false;
542
543 is telling the interpreter that we want to tamper only with southwards 
544 movement, allowing the interpreter to apply normal rules for the other 
545 available directions.
546
547 From here on, it's only conditions and more conditions. The player may 
548 attempt to leave:
549
550 * without paying for the coffee and without returning the key,
551
552 * having paid for the coffee, but without returning the key,
553
554 * having returned the key, but not paid for the coffee, or
555
556 * free of sin and accountable for nothing in the eyes of all men (well, 
557   in the eye of Benny, at least).
558
559 The first three are covered by the test:
560
561 .. code-block:: inform
562
563   if (benny.coffee_not_paid == true || benny.key_not_returned == true) ...
564
565 that is, if either the coffee is not paid for *or* if the key is not 
566 returned. When this condition is ``false``, it means that both 
567 misdemeanours have been avoided and that the player is free to go. 
568 However, when this condition is ``true``, the hand of Benny falls on the 
569 player's shoulder and then the game displays a different message 
570 according to which fault or faults the player has committed.
571
572 If the player is free to go, and is wearing the crime-fighting costume, 
573 the game is won. We tell you how that's reported in the next chapter, 
574 where we finish off the design.