X-Git-Url: https://jxself.org/git/?p=ibg.git;a=blobdiff_plain;f=chapters%2F12.rst;h=832182344ffff2207b4b400dc87aeeb358d7a7f7;hp=0260f67233a9f16e37de7eb10843fdd3d762af46;hb=4381288eeb792adb3672ef747013c02815fa760a;hpb=4261ff48a6357e2af0957f5e1b88bdc022243d16 diff --git a/chapters/12.rst b/chapters/12.rst index 0260f67..8321823 100644 --- a/chapters/12.rst +++ b/chapters/12.rst @@ -14,7 +14,7 @@ Captain Fate: take 3 |W|\e've given ourselves an interesting challenge by overusing that convenient word "toilet", and here we show you how we resolve the -ambiguities that have been introduced. Also, it's time for the eponymous +ambiguities that have been introduced. Also, it's time for the eponymous owner of Benny's café to be developed in full. Too many toilets @@ -23,87 +23,95 @@ Too many toilets .. index:: single: ambiguous objects -If you check the :prop:`name` properties of the toilet door, the toilet key -and the toilet room, you’ll see that the dictionary word ``'toilet'`` -occurs in all of them. There won't be any problems if players mention -the words DOOR or KEY, but we reach a strange impasse should they try to -perform some action with just the word TOILET. The interpreter has to -think fast: is the player talking about the key? About the door? Or -about the toilet? Unable to decide, it asks: "Which do you mean, the -door to the toilet, the toilet key or the toilet?" - -And guess what? Players will never be able to refer to the toilet object -(unless they type BATH ROOM or REST ROOM, not an obvious choice since we -haven't used those phrases anywhere visible). If the player answers -TOILET the parser will still have three objects with that dictionary -word as a possible name, so it will ask again, and again -- until we -give it some dictionary word which is not ambiguous. A human reader -would be able to understand that the word TOILET alone refers to the -room, but the interpreter won't -- unless we help it a little. - -We could work around this problem in more than one way, but we'll take -this opportunity of demonstrating the use of a third-party library -package. - -When experienced designers find a problem which is not easily solvable, -they may come up with a smart solution and then consider that others -could benefit from the effort. The product of this generosity takes the -form of a library extension: the solution neatly packaged as a file that -other designers can incorporate into their source code. These files can -be found in the IF Archive: go to -http://mirror.ifarchive.org/indexes/if-archive.html and then select -"``.../infocom``", "``.../compilers``", "``.../inform6``", -"``.../library``", and "``.../contributions``". All of these files -contain Inform code. To use a library extension (also known as a library -contribution), you should download it and read the instructions (usually -embedded as comments in the file, but occasionally supplied separately) -to discover what to do next. Normally, you ``Include`` it (as we have -already done with ``Parser``, ``VerbLib`` and ``Grammar``), but often -there are rules about where exactly this Include should be placed in -your source code. It is not unusual to find other suggestions and -warnings. +If you check the :prop:`name` properties of the toilet door, the toilet key +and the toilet room, you’ll see that the dictionary word ``'toilet'`` +occurs in all of them. There won't be any problems if players mention the +words DOOR or KEY, but we reach a strange impasse should they try to +perform some action with just the word TOILET. The interpreter has to +think fast: is the player talking about the key? About the door? Or about +the toilet? Unable to decide, it asks: "Which do you mean, the door to the +toilet, the toilet key or the toilet?" + +And guess what? Players will never be able to refer to the toilet object +(unless they type BATH ROOM or REST ROOM, not an obvious choice since we +haven't used those phrases anywhere visible). If the player answers TOILET +the parser will still have three objects with that dictionary word as a +possible name, so it will ask again, and again -- until we give it some +dictionary word which is not ambiguous. A human reader would be able to +understand that the word TOILET alone refers to the room, but the +interpreter won't -- unless we help it a little. + +We could work around this problem in more than one way, but we'll take this +opportunity of demonstrating the use of a third-party library package. + +.. |IFARCHIVE| replace:: http://mirror.ifarchive.org/indexes/if-archive.html + +.. Generated by autoindex +.. index:: + single: IF Archive + +When experienced designers find a problem which is not easily solvable, +they may come up with a smart solution and then consider that others could +benefit from the effort. The product of this generosity takes the form of +a library extension: the solution neatly packaged as a file that other +designers can incorporate into their source code. These files can be found +in the IF Archive: go to |IFARCHIVE| and then select "``.../infocom``", +"``.../compilers``", "``.../inform6``", "``.../library``", and +"``.../contributions``". All of these files contain Inform code. To use a +library extension (also known as a library contribution), you should +download it and read the instructions (usually embedded as comments in the +file, but occasionally supplied separately) to discover what to do next. +Normally, you ``Include`` it (as we have already done with ``Parser``, +``VerbLib`` and ``Grammar``), but often there are rules about where exactly +this Include should be placed in your source code. It is not unusual to +find other suggestions and warnings. To help us out of the disambiguation problem with the word TOILET, we are going to use Neil Cerutti's extension ``pname.h``, which is designed for -situations precisely like this. First, we follow the link to the IF archive -and download the compressed file ``pname.zip``, which contains two more -files: ``pname.h`` and ``pname.txt``. We place these files in the folder -where we are currently developing our game or, if using the environment we -proposed in :doc:`02`, in the ``Inform\Lib\Contrib`` folder. The text file -offers instructions about installation and usage. Here we find a warning: - - This version of pname.h is recommended for use only with version 6/10 - of the Inform Library. - -We're actually using a later version, but this doesn't seem to cause a -problem. Most extensions aren't so fussy, but ``pname.h`` fiddles with -some routines at the heart of the standard library; these may not be +situations precisely like this. First, we follow the link to the IF +archive and download the compressed file ``pname.zip``, which contains two +more files: ``pname.h`` and ``pname.txt``. We place these files in the +folder where we are currently developing our game or, if using the +environment we proposed in :doc:`02`, in the ``Inform\Lib\Contrib`` folder. +The text file offers instructions about installation and usage. Here we +find a warning: + + This version of pname.h is recommended for use only with version 6/10 of + the Inform Library. + +We're actually using a later version, but this doesn't seem to cause a +problem. Most extensions aren't so fussy, but ``pname.h`` fiddles with +some routines at the heart of the standard library; these may not be identical in other Inform versions. -The introduction explains what ``pname.h`` does for you; namely, it lets -you avoid using complicated :prop:`parse_name` routines to disambiguate the -player's input when the same dictionary word refers to more than one -item. A :prop:`parse_name` routine would have been the solution to our -problem before the existence of this file, and it qualifies as an -advanced programming topic, difficult to master on a first approach. -Fortunately, we don't need to worry. Neil Cerutti explains: - - The ``pname.h`` package defines a new object property, ``pname`` - (short for phrase name), with a similar look and feel to the standard - :prop:`name` property: both contain a list of dictionary words. However, - in a ``pname`` property the order of the words is significant, and - special operators ``'.p'`` ``'.or'`` and ``'.x'`` enable you to embed - some intelligence into the list. In most cases where the standard - :prop:`name` property isn't enough, you can now just replace it with a - ``pname`` property, rather than write a :prop:`parse_name` property +.. Generated by autoindex +.. index:: + pair: parse_name; library property + +The introduction explains what ``pname.h`` does for you; namely, it lets +you avoid using complicated :prop:`parse_name` routines to disambiguate the +player's input when the same dictionary word refers to more than one item. +A :prop:`parse_name` routine would have been the solution to our problem +before the existence of this file, and it qualifies as an advanced +programming topic, difficult to master on a first approach. Fortunately, +we don't need to worry. Neil Cerutti explains: + + The ``pname.h`` package defines a new object property, ``pname`` (short + for phrase name), with a similar look and feel to the standard + :prop:`name` property: both contain a list of dictionary words. However, + in a ``pname`` property the order of the words is significant, and + special operators ``'.p'`` ``'.or'`` and ``'.x'`` enable you to embed + some intelligence into the list. In most cases where the standard + :prop:`name` property isn't enough, you can now just replace it with a + ``pname`` property, rather than write a :prop:`parse_name` property routine. -We'll soon see how it works. Let's take a look at the installation +We'll soon see how it works. Let's take a look at the installation instructions: To incorporate this package into your program, do three things: - #. Add four lines near the head of the program (before you include + #. Add four lines near the head of the program (before you include ``Parser.h``). .. code-block:: inform @@ -123,9 +131,9 @@ instructions: #. Add ``pname`` properties to those objects which require phrase recognition. -It seems simple enough. So, following steps one and two, we add those -``Replace...`` lines before the inclusion of ``Parser``, and we include -``pname.h`` right after it. ``Replace`` tells the compiler that we're +It seems simple enough. So, following steps one and two, we add those +``Replace...`` lines before the inclusion of ``Parser``, and we include +``pname.h`` right after it. ``Replace`` tells the compiler that we're providing replacements for some standard routines. .. code-block:: inform @@ -147,12 +155,12 @@ providing replacements for some standard routines. Include "pname"; ... -Now our source code is ready to benefit from the library package. How -does it work? We have acquired a new property -- ``pname`` -- which can -be added to some of our objects, and which works pretty much like a -:prop:`name` property. In fact, it should be used *instead* of a :prop:`name` -property where we have a disambiguation problem. Let’s change the -relevant lines for the toilet door and the toilet key: +Now our source code is ready to benefit from the library package. How does +it work? We have acquired a new property -- ``pname`` -- which can be +added to some of our objects, and which works pretty much like a +:prop:`name` property. In fact, it should be used *instead* of a +:prop:`name` property where we have a disambiguation problem. Let’s change +the relevant lines for the toilet door and the toilet key: .. code-block:: inform @@ -175,52 +183,50 @@ while leaving the ``outside_of_toilet`` unchanged: before [; ... -We are now using a new operator -- ``'.x'`` -- in our ``pname`` word -lists. explains +We are now using a new operator -- ``'.x'`` -- in our ``pname`` word lists. +The text file explains - The first dictionary word to the right of a ``'.x'`` operator is + The first dictionary word to the right of a ``'.x'`` operator is interpreted as optional. -and this makes the dictionary word ``'toilet'`` of lesser importance for -these objects, so that at run-time players could refer to the DOOR or -TOILET DOOR or the KEY or TOILET KEY -- but not simply to the TOILET -- -when referring to either the door or the key. And, by leaving unchanged -the name property of the ``outside_of_toilet`` object – where there is also -another ``'toilet'`` entry -- the ``pname`` properties will tell the -interpreter to discard the key and the door as possible objects to be -considered when players refer just to TOILET. Looking at it in terms of -the English language, we've effectively said that "TOILET" is an -adjective in the phrases "TOILET DOOR" and "TOILET KEY", but a noun when -used on its own to refer to the room. - -The ``pname.h`` package has additional functionality to deal with more -complex phrases, but we don't need it in our example game. Feel free, -however, to read ``pname.txt`` and discover what this fine library -extension can do for you: it's an easy answer to many a disambiguation +and this makes the dictionary word ``'toilet'`` of lesser importance for +these objects, so that at run-time players could refer to the DOOR or +TOILET DOOR or the KEY or TOILET KEY -- but not simply to the TOILET -- +when referring to either the door or the key. And, by leaving unchanged +the name property of the ``outside_of_toilet`` object – where there is also +another ``'toilet'`` entry -- the ``pname`` properties will tell the +interpreter to discard the key and the door as possible objects to be +considered when players refer just to TOILET. Looking at it in terms of +the English language, we've effectively said that "TOILET" is an adjective +in the phrases "TOILET DOOR" and "TOILET KEY", but a noun when used on its +own to refer to the room. + +The ``pname.h`` package has additional functionality to deal with more +complex phrases, but we don't need it in our example game. Feel free, +however, to read ``pname.txt`` and discover what this fine library +extension can do for you: it's an easy answer to many a disambiguation headache. - Don't shoot! I'm only the barman ================================ -A lot of the action of the game happens around Benny, and his definition -needs a little care. Let's explain what we want to happen. - - So the door is locked and the player, after discovering what the note - stuck on the toilet door said, will eventually ask Benny for the key. - Sadly, Benny allows use of the toilet only to customers, a remark - he'll make looking pointedly at the menu board behind him. The player - will have to ask for a coffee first, thereby qualifying as a customer - in Benny's eyes and thus entitled to make use of the toilet. At last! - Rush inside, change into Captain Fate’s costume and fly away to save - the day! - -Except that the player neither paid for the coffee, nor returned the -toilet key. Benny will have to stop the player from leaving the café in -these circumstances. To prevent unnecessary complication, there will be -a coin near the lavatory, enough cash to pay for the coffee. And that -about sums it all up; pretty simple to describe -- not so simple to -code. Remember Benny's basic definition from the previous chapter: +A lot of the action of the game happens around Benny, and his definition +needs a little care. Let's explain what we want to happen. + + So the door is locked and the player, after discovering what the note + stuck on the toilet door said, will eventually ask Benny for the key. + Sadly, Benny allows use of the toilet only to customers, a remark he'll + make looking pointedly at the menu board behind him. The player will + have to ask for a coffee first, thereby qualifying as a customer in + Benny's eyes and thus entitled to make use of the toilet. At last! Rush + inside, change into Captain Fate’s costume and fly away to save the day! + +Except that the player neither paid for the coffee, nor returned the toilet +key. Benny will have to stop the player from leaving the café in these +circumstances. To prevent unnecessary complication, there will be a coin +near the lavatory, enough cash to pay for the coffee. And that about sums +it all up; pretty simple to describe -- not so simple to code. Remember +Benny's basic definition from the previous chapter: .. code-block:: inform @@ -232,7 +238,7 @@ code. Remember Benny's basic definition from the previous chapter: strikes him.", has scenery animate male proper transparent; -We can now add some complexity, beginning with a :prop:`life` property. In +We can now add some complexity, beginning with a :prop:`life` property. In generic form: .. code-block:: inform @@ -244,7 +250,7 @@ generic form: Ask,Tell,Answer: !... code to handle conversation ], -We have seen some of these actions before. We'll take care of the easier +We have seen some of these actions before. We'll take care of the easier ones: .. code-block:: inform @@ -270,20 +276,20 @@ ones: Ask,Tell,Answer: "Benny is too busy for idle chit-chat."; -Attacking Benny is not wise. If the player is still dressed as John -Covarth, the game displays a message refusing to use violence by reason -of staying in character as a worthless wimp. However, if Captain Fate -attempts the action, we'll find that there is more to Benny than meets -the eye, and the game is lost. Kissing and conversation are disallowed -by a couple of tailored responses. - -The Give action is a bit more complicated, since Benny reacts to certain -objects in a special and significant way. Bear in mind that Benny's -definition needs to keep track of whether the player has asked for a -coffee (thereby becoming a customer and thus worthy of the key), whether -the coffee has been paid for, and whether the toilet key has been -returned. The solution, yet again (this really is a most useful -capability), is more local property variables: +Attacking Benny is not wise. If the player is still dressed as John +Covarth, the game displays a message refusing to use violence by reason of +staying in character as a worthless wimp. However, if Captain Fate +attempts the action, we'll find that there is more to Benny than meets the +eye, and the game is lost. Kissing and conversation are disallowed by a +couple of tailored responses. + +The Give action is a bit more complicated, since Benny reacts to certain +objects in a special and significant way. Bear in mind that Benny's +definition needs to keep track of whether the player has asked for a coffee +(thereby becoming a customer and thus worthy of the key), whether the +coffee has been paid for, and whether the toilet key has been returned. +The solution, yet again (this really is a most useful capability), is more +local property variables: .. code-block:: inform @@ -299,10 +305,10 @@ capability), is more local property variables: live [; ... -Now we are ready to tackle the ``Give`` action of the :prop:`life` property, -which deals with commands like GIVE THE KEY TO BENNY (in a moment, we'll -come to the ``Give`` action of the :prop:`orders` property, which deals with -commands like BENNY, GIVE ME THE KEY): +Now we are ready to tackle the :act:`Give` action of the :prop:`life` +property, which deals with commands like GIVE THE KEY TO BENNY (in a +moment, we'll come to the :act:`Give` action of the :prop:`orders` +property, which deals with commands like BENNY, GIVE ME THE KEY): .. code-block:: inform @@ -329,8 +335,8 @@ commands like BENNY, GIVE ME THE KEY): back anytime,~ he says."; } -The Give action in the :prop:`life` property holds the variable :var:`noun` as -the object offered to the NPC. Remember that we can use the ``switch`` +The Give action in the :prop:`life` property holds the variable :var:`noun` +as the object offered to the NPC. Remember that we can use the ``switch`` statement as shorthand for: .. code-block:: inform @@ -340,39 +346,43 @@ statement as shorthand for: ... We won't let players give away their clothes or their costume (yes, an -improbable action, but you never know). The toilet key and the coin are -successfully transferred. The property ``key_not_returned`` will be set to +improbable action, but you never know). The toilet key and the coin are +successfully transferred. The property ``key_not_returned`` will be set to true when we receive the toilet key from Benny (we have not coded that bit -yet), and now, when we give it back, it's reset to :const:`false`. The ``move`` -statement is in charge of the actual transfer of the object from the -player's inventory to Benny, and we finally display a confirmation -message. With the coin, we find a new statement: ``remove``. This extracts -the object from the object tree, so that it now has no parent. The effect -is to make it disappear from the game (though you are not destroying the -object permanently -- and indeed you could return it to the object tree -using the ``move`` statement); as far as the player is concerned, there -isn’t a COIN to be found anywhere. The ``coffee_not_paid`` property will be -set to true when Benny serves us the cup of coffee (again, we’ll see that -in a moment); now we reset it to :const:`false`, which liberates the player from -debt. This culminates with the ``"..."`` print-and-return statement, -telling the player that the action was successful. In passing, remember -that in :ref:`homely-atmos` we defined the counter such that PUT KEY ON -COUNTER is automatically translated into GIVE KEY TO BENNY . - -Why move the key to Benny but remove the coin instead? Once players -qualify as customers by ordering a coffee, they will be able to ask for -the key and return it as many times as they like, so it seems sensible -to keep the key around. The coin, however, will be a one-shot. We won't -let players ask for more than one coffee, to prevent their debt from -growing ad infinitum -- besides, they came in here to change, not to -indulge in caffeine. Once the coin is paid, it disappears for good, -supposedly into Benny's greedy pockets. No need to worry about it any -more. - -The benny object needs also an :prop:`orders` property, just to take care of -the player's requests for coffee and the key, and to fend off any other -demands. The ``Give`` action in an :prop:`orders` property deals with inputs -like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is +yet), and now, when we give it back, it's reset to :const:`false`. The +``move`` statement is in charge of the actual transfer of the object from +the player's inventory to Benny, and we finally display a confirmation +message. With the coin, we find a new statement: ``remove``. This +extracts the object from the object tree, so that it now has no parent. +The effect is to make it disappear from the game (though you are not +destroying the object permanently -- and indeed you could return it to the +object tree using the ``move`` statement); as far as the player is +concerned, there isn’t a COIN to be found anywhere. The +``coffee_not_paid`` property will be set to true when Benny serves us the +cup of coffee (again, we’ll see that in a moment); now we reset it to +:const:`false`, which liberates the player from debt. This culminates with +the ``"..."`` print-and-return statement, telling the player that the +action was successful. In passing, remember that in :ref:`homely-atmos` we +defined the counter such that PUT KEY ON COUNTER is automatically +translated into GIVE KEY TO BENNY . + +Why move the key to Benny but remove the coin instead? Once players +qualify as customers by ordering a coffee, they will be able to ask for the +key and return it as many times as they like, so it seems sensible to keep +the key around. The coin, however, will be a one-shot. We won't let +players ask for more than one coffee, to prevent their debt from growing ad +infinitum -- besides, they came in here to change, not to indulge in +caffeine. Once the coin is paid, it disappears for good, supposedly into +Benny's greedy pockets. No need to worry about it any more. + +.. Generated by autoindex +.. index:: + pair: life; library property + +The benny object needs also an :prop:`orders` property, just to take care +of the player's requests for coffee and the key, and to fend off any other +demands. The :act:`Give` action in an :prop:`orders` property deals with +inputs like ASK BENNY FOR THE KEY or BENNY, GIVE ME THE KEY. The syntax is similar to that of the :prop:`life` property: .. code-block:: inform @@ -415,54 +425,53 @@ similar to that of the :prop:`life` property: } ], -* We test the value of :var:`second` in order to trap over-generous - gestures such as BENNY, GIVE COFFEE TO CUSTOMERS . Then we consider +* We test the value of :var:`second` in order to trap over-generous + gestures such as BENNY, GIVE COFFEE TO CUSTOMERS. Then we consider potential requests. -* **Toilet key:** first, we check whether players already have the key - or not, and complain if they do, stopping execution thanks to the - implicit ``return true`` of the ``"..."`` statement. If players don’t - have the key, we proceed to check whether they've asked for a coffee - yet, by testing the ``coffee_asked_for`` property. If this is true , - we should also check if the key is actually one of Benny’s - possessions -- a perverse player could get the key, then drop it - somewhere and ask for it again; if this should happen, we indicate - that Benny is nobody's fool with the message ``"~Last place I saw - that key..."``. Once all these fitting conditions are :const:`true`, - players will get the key, which means that they have to return it -- - the ``key_not_returned`` property becomes :const:`true` -- and we display - a suitable message. However, if the player didn't ask for a coffee, - Benny refuses to oblige, mentioning for the first time the menu board - where players will be able to see a picture of a cup of coffee when - they EXAMINE it. Take care to see how all the ``else`` clauses pair - up with the appropriate if statements, triggering responses for each - of the conditions that wasn't met. - -* **Coffee:** we check whether players have already asked for a coffee, - by testing the ``coffee_asked_for`` property, and refuse to serve - another one if :const:`true`. If :const:`false`, we place the coffee on the - counter, and set the properties ``coffee_asked_for`` and - ``coffee_not_paid`` to :const:`true`. The message bit you know about. - -* **Food:** we'll provide an object to deal with all of the delicious - comestibles to be found in the café, specifically those (such as - "pastries and sandwiches") mentioned in our descriptions. Although - that object is not yet defined, we code ahead to thwart player's - gluttony in case they choose to ask Benny for food. - -* **Menu:** our default response -- "I don’t think that’s on the menu, - sir" -- isn’t very appropriate if the player asks for a menu, so we - provide a better one. - -* **Default:** this takes care of anything else that the player asks - Benny for, displaying his curt response. +* **Toilet key:** first, we check whether players already have the key or + not, and complain if they do, stopping execution thanks to the implicit + ``return true`` of the ``"..."`` statement. If players don’t have the + key, we proceed to check whether they've asked for a coffee yet, by + testing the ``coffee_asked_for`` property. If this is true , we should + also check if the key is actually one of Benny’s possessions -- a + perverse player could get the key, then drop it somewhere and ask for it + again; if this should happen, we indicate that Benny is nobody's fool + with the message ``"~Last place I saw that key..."``. Once all these + fitting conditions are :const:`true`, players will get the key, which + means that they have to return it -- the ``key_not_returned`` property + becomes :const:`true` -- and we display a suitable message. However, if + the player didn't ask for a coffee, Benny refuses to oblige, mentioning + for the first time the menu board where players will be able to see a + picture of a cup of coffee when they EXAMINE it. Take care to see how + all the ``else`` clauses pair up with the appropriate if statements, + triggering responses for each of the conditions that wasn't met. + +* **Coffee:** we check whether players have already asked for a coffee, by + testing the ``coffee_asked_for`` property, and refuse to serve another + one if :const:`true`. If :const:`false`, we place the coffee on the + counter, and set the properties ``coffee_asked_for`` and + ``coffee_not_paid`` to :const:`true`. The message bit you know about. + +* **Food:** we'll provide an object to deal with all of the delicious + comestibles to be found in the café, specifically those (such as + "pastries and sandwiches") mentioned in our descriptions. Although that + object is not yet defined, we code ahead to thwart player's gluttony in + case they choose to ask Benny for food. + +* **Menu:** our default response -- "I don’t think that’s on the menu, sir" + -- isn’t very appropriate if the player asks for a menu, so we provide a + better one. + +* **Default:** this takes care of anything else that the player asks Benny + for, displaying his curt response. And before you know it, Benny's object is out of the way; however, don't -celebrate too soon. There’s still some Benny-related behaviour that, -curiously enough, doesn’t happen in Benny's object; we're talking about -Benny's reaction if the player tries to leave without paying or -returning the key. We promised you that Benny would stop the player, and -indeed he will. But where? +celebrate too soon. There’s still some Benny-related behaviour that, +curiously enough, doesn’t happen in Benny's object; we're talking about +Benny's reaction if the player tries to leave without paying or returning +the key. We promised you that Benny would stop the player, and indeed he +will. But where? We must revisit the café room object: @@ -517,33 +526,46 @@ We must revisit the café room object: s_to street, n_to toilet_door; -Once again, we find that the solution to a design problem is not -necessarily unique. Remember what we saw when dealing with the player's -description: we could have assigned a new value to the -``player.description`` variable, but opted to use the -``LibraryMessages`` object instead. This is a similar case. The code -causing Benny to intercept the forgetful player could have been added, -perhaps, to a :prop:`daemon` property in Benny’s definition. However, since -the action to be intercepted is always the same one and happens to be a -movement action when the player tries to leave the café room, it is also -possible to code it by trapping the ``Go`` action of the room object. +.. index:: + pair: LibraryMessages; library object + +.. Generated by autoindex +.. index:: + pair: Go; library action + pair: LibraryMessages; library object + pair: daemon; library property + +Once again, we find that the solution to a design problem is not +necessarily unique. Remember what we saw when dealing with the player's +description: we could have assigned a new value to the +``player.description`` variable, but opted to use the +:obj:`LibraryMessages` object instead. This is a similar case. The code +causing Benny to intercept the forgetful player could have been added, +perhaps, to a :prop:`daemon` property in Benny’s definition. However, +since the action to be intercepted is always the same one and happens to be +a movement action when the player tries to leave the café room, it is also +possible to code it by trapping the :act:`Go` action of the room object. Both would have been right, but this is somewhat simpler. -We have added a :prop:`before` property to the room object (albeit a longish -one), just dealing with the ``Go`` action. As we mentioned in an earlier -chapter, this technique lets you trap the player who is about to exit a -room before the movement actually takes place, a good moment to -interfere if we want to prevent escape. The first line: +.. Generated by autoindex +.. index:: + pair: before; library property + +We have added a :prop:`before` property to the room object (albeit a +longish one), just dealing with the :act:`Go` action. As we mentioned in +an earlier chapter, this technique lets you trap the player who is about to +exit a room before the movement actually takes place, a good moment to +interfere if we want to prevent escape. The first line: .. code-block:: inform if (noun ~= s_obj) return false; -is telling the interpreter that we want to tamper only with southwards -movement, allowing the interpreter to apply normal rules for the other +is telling the interpreter that we want to tamper only with southwards +movement, allowing the interpreter to apply normal rules for the other available directions. -From here on, it's only conditions and more conditions. The player may +From here on, it's only conditions and more conditions. The player may attempt to leave: * without paying for the coffee and without returning the key, @@ -552,8 +574,8 @@ attempt to leave: * having returned the key, but not paid for the coffee, or -* free of sin and accountable for nothing in the eyes of all men (well, - in the eye of Benny, at least). +* free of sin and accountable for nothing in the eyes of all men (well, in + the eye of Benny, at least). The first three are covered by the test: @@ -561,13 +583,13 @@ The first three are covered by the test: if (benny.coffee_not_paid == true || benny.key_not_returned == true) ... -that is, if either the coffee is not paid for *or* if the key is not -returned. When this condition is :const:`false`, it means that both -misdemeanours have been avoided and that the player is free to go. -However, when this condition is :const:`true`, the hand of Benny falls on the -player's shoulder and then the game displays a different message +that is, if either the coffee is not paid for *or* if the key is not +returned. When this condition is :const:`false`, it means that both +misdemeanours have been avoided and that the player is free to go. +However, when this condition is :const:`true`, the hand of Benny falls on +the player's shoulder and then the game displays a different message according to which fault or faults the player has committed. If the player is free to go, and is wearing the crime-fighting costume, -the game is won. We tell you how that's reported in the next chapter, +the game is won. We tell you how that's reported in the next chapter, where we finish off the design.