X-Git-Url: https://jxself.org/git/?p=ibg.git;a=blobdiff_plain;f=chapters%2F11.rst;h=ff082ec038d2eac4c421874217cb41953510ca7d;hp=ef710042f394ad635dba527b6ba76756de47d448;hb=4381288eeb792adb3672ef747013c02815fa760a;hpb=d102cdffefa7d68901d9f6e7d564656270bd0280 diff --git a/chapters/11.rst b/chapters/11.rst index ef71004..ff082ec 100644 --- a/chapters/11.rst +++ b/chapters/11.rst @@ -4,42 +4,37 @@ Captain Fate: take 2 .. epigraph:: - | *U was a usurer, a miserable elf;* - | *V was a vintner, who drank all himself.* + | |CENTER| *U was a usurer, a miserable elf;* + | |CENTER| *V was a vintner, who drank all himself.* .. only:: html .. image:: /images/picV.png :align: left -.. raw:: latex - - \dropcap{v} - -iewed from the inside, Benny's café is warm and welcoming, and packed -with lunchtime customers. We'll try to conjure up some appropriate -images, but the main focus of the room isn't the decor: it's the door -leading to the toilet -- and, perhaps, privacy? +|V|\iewed from the inside, Benny's café is warm and welcoming, and packed +with lunchtime customers. We'll try to conjure up some appropriate images, +but the main focus of the room isn't the decor: it's the door leading to +the toilet -- and, perhaps, privacy? .. _homely-atmos: A homely atmosphere =================== -Benny's café is populated with customers enjoying their lunch, so it -won't be a good place to change identities. However, the toilet to the -north looks promising, though Benny has strict rules about its use and -the door seems to be locked. +Benny's café is populated with customers enjoying their lunch, so it won't +be a good place to change identities. However, the toilet to the north +looks promising, though Benny has strict rules about its use and the door +seems to be locked. .. admonition:: Cultural Note :class: admonition note - not for the first time, this guide betrays its origins. In - European countries the word "toilet" often refers not only to the - white porcelain artefact, but also to the room in which it can be - found (also, a "bathroom" is for taking a bath, a "restroom" for - taking a rest). Bear with us on this; the dual usage becomes - important a little later on. + Not for the first time, this guide betrays its origins. In European + countries the word "toilet" often refers not only to the white porcelain + artefact, but also to the room in which it can be found (also, a + "bathroom" is for taking a bath, a "restroom" for taking a rest). Bear + with us on this; the dual usage becomes important a little later on. We define the café room in simple form: @@ -55,7 +50,7 @@ We define the café room in simple form: s_to street, n_to toilet_door; -We'll elaborate on the last line (``n_to toilet_door``) later, when we +We'll elaborate on the last line (``n_to toilet_door``) later, when we define the door object which lies between the café and the toilet. We've mentioned a counter: @@ -76,40 +71,39 @@ We've mentioned a counter: ], has supporter; -That ``before property``, superficially normal, actually conceals a -little surprise. By now you should be entirely comfortable with using an -object's ``before`` property to intercept an action directed at that -object; for example, if the player types HIT COUNTER then the counter's -``before`` property is potentially able to intercept the resulting -Attack action. However, the command PUT KEY ON COUNTER generates *two* -actions. First, a PutOn action is offered to the key (effectively -saying, do you want to be placed on top of the counter?); that’s the -normal bit. And then the surprise: a Receive action is offered to the -counter (effectively saying, are you happy to have the key placed on -you?) Both actions have the same opportunity of returning ``false`` to -let the action continue, ``true`` to prevent it. - -.. todo:: - - There are a lot of actions here that are rendered in a typewriter font - and others that are not. Should these ones that are not be promoted - to having a typewriter font? - -The Receive action is generated by the library in the PutOnSub action -handler, and also in InsertSub (so a command like PUT BIRD IN NEST sends a -Receive to the nest object). There’s a matching LetGo, generated by the -library from commands like TAKE KEY OFF COUNTER and REMOVE BIRD FROM -NEST. Receive and LetGo are examples of what’s called a :term:`fake -action`. +That :prop:`before` property, superficially normal, actually conceals a +little surprise. By now you should be entirely comfortable with using an +object's :prop:`before` property to intercept an action directed at that +object; for example, if the player types HIT COUNTER then the counter's +:prop:`before` property is potentially able to intercept the resulting +:act:`Attack` action. However, the command PUT KEY ON COUNTER generates +*two* actions. First, a :act:`PutOn` action is offered to the key +(effectively saying, do you want to be placed on top of the counter?); +that’s the normal bit. And then the surprise: a :act:`Receive` action is +offered to the counter (effectively saying, are you happy to have the key +placed on you?) Both actions have the same opportunity of returning +:const:`false` to let the action continue, :const:`true` to prevent it. + +.. Generated by autoindex +.. index:: + pair: LetGo; library action + pair: Receive; library action + +The :act:`Receive` action is generated by the library in the ``PutOnSub`` +action handler, and also in ``InsertSub`` (so a command like PUT BIRD IN +NEST sends a Receive to the nest object). There’s a matching :act:`LetGo`, +generated by the library from commands like TAKE KEY OFF COUNTER and REMOVE +BIRD FROM NEST. :act:`Receive` and :act:`LetGo` are examples of what’s +called a :term:`fake action`. .. note:: - in "William Tell" we defined the ``quiver``, way back in - :ref:`possessions`, as an ``open container``. As things stand, the player - can put *any* held object, however inappropriate, into it. We could have - trapped the Receive action to ensure that arrows are the only acceptable - contents (recollect that ``~~``, to be read as "not", turns true into - false and vice versa): + In "William Tell" we defined the ``quiver``, way back in + :ref:`possessions`, as an ``open container``. As things stand, the + player can put *any* held object, however inappropriate, into it. We + could have trapped the :act:`Receive` action to ensure that arrows are + the only acceptable contents (recollect that ``~~``, to be read as "not", + turns true into false and vice versa): .. code-block:: inform @@ -121,14 +115,14 @@ action`. print_ret "Only arrows -- clean arrows -- go in your quiver."; ], -Here, we intercept any attempt to place an item on the counter, and -translate it into an attempt to give that item to Benny. Part of the -game's plot depends on the player returning the toilet key to Benny, and -also paying him for his delicious cup of world-famous Cappuccino. -Putting the key and the money on the counter is a reasonable alternative -way for the player to accomplish this. +Here, we intercept any attempt to place an item on the counter, and +translate it into an attempt to give that item to Benny. Part of the +game's plot depends on the player returning the toilet key to Benny, and +also paying him for his delicious cup of world-famous Cappuccino. Putting +the key and the money on the counter is a reasonable alternative way for +the player to accomplish this. -We've also mentioned some customers. These are treated as NPCs, reacting +We've also mentioned some customers. These are treated as NPCs, reacting to our hero’s performance. .. code-block:: inform @@ -194,75 +188,90 @@ to our hero’s performance. ], has scenery animate pluralname; -Let's go step by step. Our hero enters the café dressed as John Covarth, -but will eventually manage to change clothes in the toilet, and he'll -have to cross back through the café to reach the street and win the -game. The customers' ``description`` takes into consideration which -outfit the player character is wearing. - -In "William Tell" we’ve seen a brief manifestation of the ``life`` -property, but here we'll extend it a little. As we explained, ``life`` -lets you intercept those actions particular to animate objects. Here we -trap ``Attack`` and ``Kiss`` to offer some customised messages for these -actions when applied to the customers. Also, we avoid conversation by -intercepting ``Ask``, ``Tell`` and ``Answer`` in order just to produce a -message which depends on the player character's attire. - -One other feature of ``animate`` objects is the possibility of giving -them orders: BILL, SHAKE THE SPEAR or ANNIE, GET YOUR GUN . These -actions are dealt with in the ``orders`` property and, as with the -``life`` property, the embedded routine can become quite complex if you -want your NPCs to behave in an interesting way. In this case, we don't -need the customers to perform tasks for us, so instead we provide a -simple rejection message, just in case the player tries to order people -around. - -Which leaves us with the ``daemon`` bit. A daemon is a property normally -used to perform some timed or repetitive action without the need of the -player’s direct interaction; for example, machines which work by -themselves, animals that move on their own, or people going about their -business. More powerfully, a daemon may take notice of the player’s -decisions at a particular moment, allowing for some interactive -behaviour; this is, however, an advanced feature that we won't use in -this example. A daemon gets a chance of doing something at the end of -every turn, typically to (or with) the object to which it’s associated. -In our example, the daemon triggers some sneers and nasty comments from -the customers once our hero comes out of the toilet dressed in Captain -Fate’s costume. +Let's go step by step. Our hero enters the café dressed as John Covarth, +but will eventually manage to change clothes in the toilet, and he'll have +to cross back through the café to reach the street and win the game. The +customers' :prop:`description` takes into consideration which outfit the +player character is wearing. + +.. Generated by autoindex +.. index:: + pair: Answer; library action + pair: Ask; library action + pair: Attack; library action + pair: Kiss; library action + pair: Tell; library action + pair: life; library property + +In "William Tell" we’ve seen a brief manifestation of the :prop:`life` +property, but here we'll extend it a little. As we explained, :prop:`life` +lets you intercept those actions particular to animate objects. Here we +trap :act:`Attack` and :act:`Kiss` to offer some customised messages for +these actions when applied to the customers. Also, we avoid conversation +by intercepting :act:`Ask`, :act:`Tell` and :act:`Answer` in order just to +produce a message which depends on the player character's attire. + +.. Generated by autoindex +.. index:: + pair: animate; library attribute + pair: orders; library property + +One other feature of :attr:`animate` objects is the possibility of giving +them orders: BILL, SHAKE THE SPEAR or ANNIE, GET YOUR GUN . These actions +are dealt with in the :prop:`orders` property and, as with the :prop:`life` +property, the embedded routine can become quite complex if you want your +NPCs to behave in an interesting way. In this case, we don't need the +customers to perform tasks for us, so instead we provide a simple rejection +message, just in case the player tries to order people around. + +.. Generated by autoindex +.. index:: + pair: daemon; library property + +Which leaves us with the :prop:`daemon` bit. A daemon is a property +normally used to perform some timed or repetitive action without the need +of the player’s direct interaction; for example, machines which work by +themselves, animals that move on their own, or people going about their +business. More powerfully, a daemon may take notice of the player’s +decisions at a particular moment, allowing for some interactive behaviour; +this is, however, an advanced feature that we won't use in this example. A +daemon gets a chance of doing something at the end of every turn, typically +to (or with) the object to which it’s associated. In our example, the +daemon triggers some sneers and nasty comments from the customers once our +hero comes out of the toilet dressed in Captain Fate’s costume. To code a daemon, you need to do three things: -#. First, define a daemon property in the object’s body; the value of - the property is always an embedded routine. +#. First, define a daemon property in the object’s body; the value of the + property is always an embedded routine. -#. However, daemons do nothing until you activate them. This is easily - achieved with the call ``StartDaemon(obj_id)``, which may happen - anywhere (if you want some object's daemon to be active from the - beginning of the game,you can make the call in your Initialise - routine). +#. However, daemons do nothing until you activate them. This is easily + achieved with the call :samp:`StartDaemon({obj_id})`, which may happen + anywhere (if you want some object's daemon to be active from the + beginning of the game,you can make the call in your Initialise routine). -#. Once the daemon has finished its mission (if ever) you may stop it - with the call ``StopDaemon(obj_id)``. +#. Once the daemon has finished its mission (if ever) you may stop it with + the call :samp:`StopDaemon({obj_id})`. -How does our particular daemon work? The appearance of our hero in full -crime-fighting wear will make the customers stare at him and make snarky -remarks. This must happen in the café room – the place where the -customers are -- so we need to make certain that the daemon does -something interesting only while the player stays in the right place -(and hasn’t wandered, say, back into the toilet): +How does our particular daemon work? The appearance of our hero in full +crime-fighting wear will make the customers stare at him and make snarky +remarks. This must happen in the café room – the place where the customers +are -- so we need to make certain that the daemon does something +interesting only while the player stays in the right place (and hasn’t +wandered, say, back into the toilet): .. code-block:: inform if (location ~= cafe) return; -So if the location is not the café room (remember ~= means "not equal -to"), return without doing anything else; on this turn, there’s nothing -for the daemon to do. We use a plain ``return`` statement because the -value returned from a daemon doesn’t matter. +So if the location is not the café room (remember ~= means "not equal to"), +return without doing anything else; on this turn, there’s nothing for the +daemon to do. We use a plain ``return`` statement because the value +returned from a daemon doesn’t matter. -We have defined a customised local property, ``number_of_comments``, to -control the sequence of customers' remarks. When the Captain enters the -café room from the toilet for the first time, the value of the property +We have defined a customised local property, ``number_of_comments``, to +control the sequence of customers' remarks. When the Captain enters the +café room from the toilet for the first time, the value of the property should be zero, so the statement block under the test: .. code-block:: inform @@ -273,46 +282,50 @@ should be zero, so the statement block under the test: curiosity.^"; } -will happen only this once. What we intend is to output the text "Nearby -customers..." right after the startling entrance of our hero, setting up -the scene for the comments which are about to happen. Since we assign a -value of 1 to the property, the message will not be printed again. -Notice how we use an explicit ``print`` statement; the execution of the -daemon will continue normally to the next line. +will happen only this once. What we intend is to output the text "Nearby +customers..." right after the startling entrance of our hero, setting up +the scene for the comments which are about to happen. Since we assign a +value of 1 to the property, the message will not be printed again. Notice +how we use an explicit ``print`` statement; the execution of the daemon +will continue normally to the next line. -We want the customers to indulge in witticisms once they see the -costumed Captain, but not on a completely predictable basis. +We want the customers to indulge in witticisms once they see the costumed +Captain, but not on a completely predictable basis. .. code-block:: inform if (random(2) == 1) ... -``random`` is an Inform routine used to generate random numbers or to -choose randomly between given choices; in the form -:samp:`random({expression})` it returns a random number between 1 and -``expression`` inclusive. So our condition is actually stating: if a -random choice between 1 and 2 happens to be 1 then perform some action. -Remember that a daemon is run once at the end of every turn, so the -condition is trying to squeeze a comment from a customer roughly once -every other turn. - -Next, we proceed as we have already seen in "William Tell", with a -switch statement to order the comments in a controlled sequence by -cunning use of our tailored local property, ``number_of_comments``. We -have written just five messages (could have been one or a hundred) and -then we reach the default case, which is a good place to stop the -daemon, since we have no more customers’ remarks to display. - -Ah, but when does the daemon *start* functioning? Well, as soon as our -protagonist comes out of the toilet dressed in his multicoloured -super-hero pyjamas. Since we want to minimise the possible game states, -we’ll make some general rules to avoid trouble: (a) players will be able -to change only in the toilet; (b) we won’t let players change back into -street clothes; and (c) once players manage to step into the street thus -dressed, the game is won. So, we can safely assume that if players enter -the café in their Captain’s outfit, they’ll be coming from the toilet. -As a consequence of all this, we add an ``after`` property to the café -room object: +``random`` is an Inform routine used to generate random numbers or to +choose randomly between given choices; in the form +:samp:`random({expression})` it returns a random number between 1 and +``expression`` inclusive. So our condition is actually stating: if a +random choice between 1 and 2 happens to be 1 then perform some action. +Remember that a daemon is run once at the end of every turn, so the +condition is trying to squeeze a comment from a customer roughly once every +other turn. + +Next, we proceed as we have already seen in "William Tell", with a switch +statement to order the comments in a controlled sequence by cunning use of +our tailored local property, ``number_of_comments``. We have written just +five messages (could have been one or a hundred) and then we reach the +default case, which is a good place to stop the daemon, since we have no +more customers’ remarks to display. + +.. Generated by autoindex +.. index:: + pair: after; library property + +Ah, but when does the daemon *start* functioning? Well, as soon as our +protagonist comes out of the toilet dressed in his multicoloured super-hero +pyjamas. Since we want to minimise the possible game states, we’ll make +some general rules to avoid trouble: (a) players will be able to change +only in the toilet; (b) we won’t let players change back into street +clothes; and (c) once players manage to step into the street thus dressed, +the game is won. So, we can safely assume that if players enter the café +in their Captain’s outfit, they’ll be coming from the toilet. As a +consequence of all this, we add an :prop:`after` property to the café room +object: .. code-block:: inform @@ -330,14 +343,14 @@ room object: s_to street, n_to toilet_door -There are two useful techniques to detect when the player is entering or -leaving a room. We'll later see in detail how to deal with a player -trying to go away and how to avoid it if need be. For now, let’s just -mention that, in both cases, you have to intercept the ``Go`` action in -a room object; if you trap it in a ``before`` property, you’re checking -for departure from the room; if you trap it in an ``after`` property, -you’re checking for arrivals into the room. Right now we wish to know if -the player just came from the toilet, so we use an ``after`` property. +There are two useful techniques to detect when the player is entering or +leaving a room. We'll later see in detail how to deal with a player trying +to go away and how to avoid it if need be. For now, let’s just mention +that, in both cases, you have to intercept the :act:`Go` action in a room +object; if you trap it in a :prop:`before` property, you’re checking for +departure from the room; if you trap it in an :prop:`after` property, +you’re checking for arrivals into the room. Right now we wish to know if +the player just came from the toilet, so we use an :prop:`after` property. The first line: @@ -345,27 +358,32 @@ The first line: if (noun ~= s_obj) return false; -is telling the interpreter that we want to do something if the player -entered the room by typing a GO SOUTH command (this would normally mean -"coming from the north", but remember that nothing stops you from -connecting rooms without cardinal logic); the interpreter will apply -normal rules for the other available directions. - -Then we check whether the player character is wearing the costume, in -which case it starts the ``daemon`` of the ``customers`` object. The use -of the local first_time_out property ensures that the condition is -``true`` only once, so the statement block attached to it runs also +is telling the interpreter that we want to do something if the player +entered the room by typing a GO SOUTH command (this would normally mean +"coming from the north", but remember that nothing stops you from +connecting rooms without cardinal logic); the interpreter will apply normal +rules for the other available directions. + +.. Generated by autoindex +.. index:: + pair: daemon; library property + pair: true; library constant + +Then we check whether the player character is wearing the costume, in which +case it starts the :prop:`daemon` of the ``customers`` object. The use of +the local ``first_time_out`` property ensures that the condition is +:const:`true` only once, so the statement block attached to it runs also once. -We've finished with the customers in the café. Now, we have the toilet -to the north which, for reasons of gameplay *and* decency, is protected -by a door. +We've finished with the customers in the café. Now, we have the toilet to +the north which, for reasons of gameplay *and* decency, is protected by a +door. A door to adore =============== -Door objects require some specific properties and attributes. Let's -first code a simple door: +Door objects require some specific properties and attributes. Let's first +code a simple door: .. code-block:: inform @@ -380,49 +398,58 @@ first code a simple door: with_key toilet_key, has scenery door openable lockable locked; -We find this door in the café. We must specify the direction in which -the door leads and, as we have mentioned in the café's description, that -would be to the north. That’s what the ``door_dir`` property is for, and -in this case it takes the value of the north direction property -``n_to``. Then we must tell Inform the identity of the room to be found -behind the door, hence the ``door_to`` property, which takes the value -of the toilet room -- to be defined later. Remember the café's -connection to the north, ``n_to toilet_door``? Thanks to it, Inform will -know that the door is in the way, and thanks to the ``door_to`` -property, what lies beyond. - -Doors *must* have the attribute ``door``, but beyond that we have a -stock of options to help us define exactly what kind of door we are -dealing with. As for containers, doors can be ``openable`` (which -activates the verbs OPEN and CLOSE so that they can be applied to this -object) and, since by default they are closed, you can give them the -attribute ``open`` if you wish otherwise. Additionally, doors can be -``lockable`` (which sets up the LOCK/UNLOCK verbs) and you can make them -``locked`` to override their default unlocked status. The verbs LOCK -and UNLOCK are expecting some kind of key object to operate the door. -This must be defined using the ``with_key`` property, whose value should -be the internal ID of the key; in our example, the soon-to-be-defined -``toilet_key`` . If you don't supply this property, players won't be -able to lock or unlock the door. - -This simple door definition has one problem, namely, that it exists only -in the café room. If you wish the door to be present also from the -toilet side, you can either (a) define another door to be found in the -``toilet room``, or (b) make this one a two-sided door. - -Solution (a) seems superficially straightforward, but then you have the -problem of keeping the states of the two doors – open/closed, -locked/unlocked -- in synch. In this scenario, where you can access the -toilet only through this door, that wouldn't be too complicated, since -you could leave the door object in the café room opened all the time, -regardless of what players do with the door object in the toilet room -and vice versa -- they are never going to see them at the same time. In -general terms, though, such inconsistencies lead to problems; solution +We find this door in the café. We must specify the direction in which the +door leads and, as we have mentioned in the café's description, that would +be to the north. That’s what the :prop:`door_dir` property is for, and in +this case it takes the value of the north direction property :prop:`n_to`. +Then we must tell Inform the identity of the room to be found behind the +door, hence the :prop:`door_to` property, which takes the value of the +toilet room -- to be defined later. Remember the café's connection to the +north, ``n_to toilet_door``? Thanks to it, Inform will know that the door +is in the way, and thanks to the :prop:`door_to` property, what lies +beyond. + +.. Generated by autoindex +.. index:: + pair: door; library attribute + pair: lockable; library attribute + pair: locked; library attribute + pair: open; library attribute + pair: openable; library attribute + pair: with_key; library property + +Doors *must* have the attribute :attr:`door`, but beyond that we have a +stock of options to help us define exactly what kind of door we are dealing +with. As for containers, doors can be :attr:`openable` (which activates +the verbs OPEN and CLOSE so that they can be applied to this object) and, +since by default they are closed, you can give them the attribute +:attr:`open` if you wish otherwise. Additionally, doors can be +:attr:`lockable` (which sets up the LOCK/UNLOCK verbs) and you can make +them :attr:`locked` to override their default unlocked status. The verbs +LOCK and UNLOCK are expecting some kind of key object to operate the door. +This must be defined using the :prop:`with_key` property, whose value +should be the internal ID of the key; in our example, the +soon-to-be-defined ``toilet_key`` . If you don't supply this property, +players won't be able to lock or unlock the door. + +This simple door definition has one problem, namely, that it exists only in +the café room. If you wish the door to be present also from the toilet +side, you can either (a) define another door to be found in the ``toilet +room``, or (b) make this one a two-sided door. + +Solution (a) seems superficially straightforward, but then you have the +problem of keeping the states of the two doors – open/closed, +locked/unlocked -- in synch. In this scenario, where you can access the +toilet only through this door, that wouldn't be too complicated, since you +could leave the door object in the café room opened all the time, +regardless of what players do with the door object in the toilet room and +vice versa -- they are never going to see them at the same time. In +general terms, though, such inconsistencies lead to problems; solution (a) is best ignored for most purposes. -Solution (b) is better, since you have only one door object to deal with -and its possible states affect both sides. However, the coding gets a -little bit complicated and you''ll have to define routines for most +Solution (b) is better, since you have only one door object to deal with +and its possible states affect both sides. However, the coding gets a +little bit complicated and you''ll have to define routines for most properties: .. code-block:: inform @@ -449,40 +476,40 @@ properties: with_key toilet_key, has scenery door openable lockable locked; -First of all, the door now needs a ``found_in`` property, since it's -going to be located both in the café and the toilet. The ``description`` -checks which side of the door we are looking at – testing the current -value of the variable ``location``, which holds the room the player is -in -- because we have a scribbled note stuck on one side, but not on the -other. And the ``door_dir`` and ``door_to`` properties must use the same -trick, because we travel north from the café into the toilet, but south -from the toilet into the café. - -Right now, the game will display "the toilet door" every time it needs -to refer to this object. It would be nice if we could somehow get the -game to distinguish between "the door to the toilet" and "the door to -the cafe", depending on the side we are facing. For this, a ``short_name -property`` is the thing. We have already talked about the external name -defined as part of an object's header information: +First of all, the door now needs a :prop:`found_in` property, since it's +going to be located both in the café and the toilet. The +:prop:`description` checks which side of the door we are looking at – +testing the current value of the variable :var:`location`, which holds the +room the player is in -- because we have a scribbled note stuck on one +side, but not on the other. And the :prop:`door_dir` and :prop:`door_to` +properties must use the same trick, because we travel north from the café +into the toilet, but south from the toilet into the café. + +Right now, the game will display "the toilet door" every time it needs to +refer to this object. It would be nice if we could somehow get the game to +distinguish between "the door to the toilet" and "the door to the cafe", +depending on the side we are facing. For this, a ``short_name property`` +is the thing. We have already talked about the external name defined as +part of an object's header information: .. code-block:: inform Object toilet_door "toilet door" -That ``toilet door`` will be the name displayed by the game at run-time -to refer to the door. With identical effect, this could also have been -coded thus: +That ``toilet door`` will be the name displayed by the game at run-time to +refer to the door. With identical effect, this could also have been coded +thus: .. code-block:: inform Object toilet_door with short_name "toilet door", -``short_name`` is a property that supplies the external name of an -object, either as a string or an embedded routine. Normally, objects -retain the same external name throughout the game -- and the header -information method is perfect in that case -- but if it needs to change, -it's easy to write a routine as the value of ``short_name``: +:prop:`short_name` is a property that supplies the external name of an +object, either as a string or an embedded routine. Normally, objects +retain the same external name throughout the game -- and the header +information method is perfect in that case -- but if it needs to change, +it's easy to write a routine as the value of :prop:`short_name`: .. code-block:: inform @@ -491,61 +518,64 @@ it's easy to write a routine as the value of ``short_name``: short_name [; if (location == cafe) print "door to the toilet"; else print "door to the cafe"; + return true; ], description ... -Notice the ``return true`` at the end of the routine. You''ll recall -that the standard rule says "return false to carry on, true to take over -and stop normal execution”. In the case of ``short_name``, "carry on" -means "and now display the external name from the header information", -which is sometimes handy; for instance, you could write a ``short_name`` -routine to prefix an object's external name with one of a range of -adjectives -- perhaps a shining/flickering/fading/useless lantern. +Notice the ``return true`` at the end of the routine. You''ll recall that +the standard rule says "return false to carry on, true to take over and +stop normal execution". In the case of :prop:`short_name`, "carry on" +means "and now display the external name from the header information", +which is sometimes handy; for instance, you could write a +:prop:`short_name` routine to prefix an object's external name with one of +a range of adjectives -- perhaps a shining/flickering/fading/useless +lantern. .. note:: - what's displayed if there isn't an external name in an object's header? + What's displayed if there isn't an external name in an object's header? If you've read the section :ref:`compile-as-you-go`, you'll recall that the interpreter simply uses the internal identifier within parentheses; - that is, with no external name and no ``short_name`` property, we might - see: - - .. code-block:: inform + that is, with no external name and no :prop:`short_name` property, we + might see:: You open the (toilet_door). - And the same principle applies if we were mistakenly to ``return - false`` from this short_name routine: we would get, first, the result - of our ``print`` statement, and then the standard rules would display - the internal ID: - - .. code-block:: inform + And the same principle applies if we were mistakenly to ``return false`` + from this short_name routine: we would get, first, the result of our + ``print`` statement, and then the standard rules would display the + internal ID:: You open the door to the toilet(toilet_door). -Doors can get more complicated than this (no, please, don't throw our -guide out of the window). Here comes some optional deluxe coding to make -the door object a bit friendlier in game play, so you can skip it if you +Doors can get more complicated than this (no, please, don't throw our guide +out of the window). Here comes some optional deluxe coding to make the +door object a bit friendlier in game play, so you can skip it if you foresee headaches. -Our door now behaves nicely at run-time. It can be locked and unlocked -if the player character has the right key; it can be opened and closed. -A sequence of commands to go into the toilet and lock the door behind -you would be: UNLOCK DOOR WITH KEY, OPEN DOOR, GO NORTH, CLOSE DOOR, -LOCK DOOR WITH KEY. After we are finished, let's go back to the café: -UNLOCK DOOR WITH KEY, OPEN DOOR, SOUTH. If the player is of the -fastidious kind: CLOSE DOOR, LOCK DOOR WITH KEY. This game features only -one door, but if it had three or four of them, players would grow -restless (at the very least) if they needed to type so many commands -just to go through a door. This is the kind of thing reportedly -considered as poor design, because the game is suddenly slowed down to -get over a simple action which involves no secrets or surprises. How -exciting can the crossing of an ordinary door be, after all? - -If a few lines of code can make the life of the player easier, it's -worth a shot. Let's provide a few improvements to our toilet door in -``before`` and ``after`` properties: +Our door now behaves nicely at run-time. It can be locked and unlocked if +the player character has the right key; it can be opened and closed. A +sequence of commands to go into the toilet and lock the door behind you +would be: UNLOCK DOOR WITH KEY, OPEN DOOR, GO NORTH, CLOSE DOOR, LOCK DOOR +WITH KEY. After we are finished, let's go back to the café: UNLOCK DOOR +WITH KEY, OPEN DOOR, SOUTH. If the player is of the fastidious kind: CLOSE +DOOR, LOCK DOOR WITH KEY. This game features only one door, but if it had +three or four of them, players would grow restless (at the very least) if +they needed to type so many commands just to go through a door. This is +the kind of thing reportedly considered as poor design, because the game is +suddenly slowed down to get over a simple action which involves no secrets +or surprises. How exciting can the crossing of an ordinary door be, after +all? + +.. Generated by autoindex +.. index:: + pair: after; library property + pair: before; library property + +If a few lines of code can make the life of the player easier, it's worth a +shot. Let's provide a few improvements to our toilet door in +:prop:`before` and :prop:`after` properties: .. code-block:: inform @@ -572,96 +602,107 @@ worth a shot. Let's provide a few improvements to our toilet door in return true; ], -The basic idea here is to let the player who holds the key perform just -one action to both unlock *and* open the door (and, conversely, to close -*and* lock it). The relevant actions are ``Unlock`` and ``Open``, and -``Lock`` ( ``Close`` is not necessary; if players just close the door we -shouldn’t assume that they want to lock it as well). - -* **Open**: if the door isn't locked or the player doesn't hold the key, - keep going with the default ``Open`` action defined by the library. - That leaves a locked door and a player holding the key, so we - redirect processing to the ``Unlock`` action, giving as arguments the - door (self) and the toilet key. Since we are using single - angle-brackets ``<...>``, the action resumes after the unlocking is - done (note that the ``Unlock`` action also takes care of opening the - door). Finally, we ``return true`` to stop the library from trying to - open the door by itself. - -* **Lock**: if the door is already closed, keep going with the standard - library ``Lock`` action. If not, tell players that we are closing the - door for them, redirect the action briefly to actually close it, and - then ``return false`` to let the ``Lock`` action proceed as before. - -* **Unlock**: we place this action in the after property, so (let's - hope) the ``Unlock`` action has already happened. If the door is still - locked, something went wrong, so we ``return false`` to display the - standard message for an unsuccessful unlocking. Otherwise, the door is - now unlocked, so we inform the player that we are opening the door and - redirect the action to actually open it, returning ``true`` to +The basic idea here is to let the player who holds the key perform just one +action to both unlock *and* open the door (and, conversely, to close *and* +lock it). The relevant actions are :act:`Unlock` and :act:`Open`, and +:act:`Lock` (:act:`Close` is not necessary; if players just close the door +we shouldn’t assume that they want to lock it as well). + +* **Open**: if the door isn't locked or the player doesn't hold the key, + keep going with the default :act:`Open` action defined by the library. + That leaves a locked door and a player holding the key, so we redirect + processing to the :act:`Unlock` action, giving as arguments the door + (self) and the toilet key. Since we are using single angle-brackets + ``<...>``, the action resumes after the unlocking is done (note that the + :act:`Unlock` action also takes care of opening the door). Finally, we + ``return true`` to stop the library from trying to open the door by + itself. + +* **Lock**: if the door is already closed, keep going with the standard + library :act:`Lock` action. If not, tell players that we are closing the + door for them, redirect the action briefly to actually close it, and then + ``return false`` to let the :act:`Lock` action proceed as before. + +.. Generated by autoindex +.. index:: + pair: true; library constant + +* **Unlock**: we place this action in the after property, so (let's hope) + the :act:`Unlock` action has already happened. If the door is still + locked, something went wrong, so we ``return false`` to display the + standard message for an unsuccessful unlocking. Otherwise, the door is + now unlocked, so we inform the player that we are opening the door and + redirect the action to actually open it, returning :const:`true` to suppress the standard message. -In all processes there is a library variable called ``keep_silent``, -which can be either ``false`` (the normal state) or ``true``; when -``true``, the interpreter does not display the associated message of an -action in progress, so we can avoid things like:: +.. Generated by autoindex +.. index:: + pair: false; library constant + pair: keep_silent; library variable + +In all processes there is a library variable called :var:`keep_silent`, +which can be either :const:`false` (the normal state) or :const:`true`; +when :const:`true`, the interpreter does not display the associated message +of an action in progress, so we can avoid things like: + +.. code-block:: transcript >OPEN DOOR You open the door to the toilet. You unlock the door to the toilet and open it. -Although we want to set ``keep_silent`` to ``true`` for the duration of -our extra processing, we need to reset it afterwards. In a case like -this, good design practice is to preserve its initial value (which was -probably ``false``, but you should avoid risky assumptions); we use a -local variable ``ks`` to remember that initial setting so that we can -safely restore it afterwards. You’ll remember that a local variable in a -standalone routine is declared between the routine’s name and the -semicolon: +Although we want to set :var:`keep_silent` to :const:`true` for the +duration of our extra processing, we need to reset it afterwards. In a +case like this, good design practice is to preserve its initial value +(which was probably :const:`false`, but you should avoid risky +assumptions); we use a local variable ``ks`` to remember that initial +setting so that we can safely restore it afterwards. You’ll remember that +a local variable in a standalone routine is declared between the routine’s +name and the semicolon: .. code-block:: inform [ BeenToBefore this_room; -In exactly the same way, a local variable in an embedded routine is -declared between the ``[`` starting marker of the routine and the +In exactly the same way, a local variable in an embedded routine is +declared between the ``[`` starting marker of the routine and the semicolon: .. code-block:: inform before [ ks; -You can declare up to fifteen variables this way -- just separated by -spaces -- which are usable only within the embedded routine. When we +You can declare up to fifteen variables this way -- just separated by +spaces -- which are usable only within the embedded routine. When we assign it thus: .. code-block:: inform ks = keep_silent; -we are actually making ``ks`` equal to whatever value ``keep_silent`` -has (either ``true`` or ``false``; we actually don't care). We then set -``keep_silent`` to ``true``, make the desired silent actions, and we -assign: +we are actually making ``ks`` equal to whatever value :var:`keep_silent` +has (either :const:`true` or :const:`false`; we actually don't care). We +then set :var:`keep_silent` to :const:`true`, make the desired silent +actions, and we assign: .. code-block:: inform keep_silent = ks; -which restores the value originally stored in ``ks`` to ``keep_silent``. -The effect is that we manage to leave it as it was before we tampered -with it. +which restores the value originally stored in ``ks`` to :var:`keep_silent`. +The effect is that we manage to leave it as it was before we tampered with +it. -Well, that's about everything about doors. Everything? Well, no, not -really; any object can grow as complex as your imagination allows, but -we’ll drop the subject here. If you care to see more sophisticated -doors, check Exercises 3 and 4 in the *Inform Designer's Manual*, where -an obliging door opens and unlocks by itself if the player simply walks -in its direction. +Well, that's about everything about doors. Everything? Well, no, not +really; any object can grow as complex as your imagination allows, but +we’ll drop the subject here. If you care to see more sophisticated doors, +check Exercises :dm4:`3 and 4 ` in the |DM4|, where an +obliging door opens and unlocks by itself if the player simply walks in its +direction. -So far, we have the player in front of a locked door leading to the -toilet. A dead end? No, the description mentions a scribbled note on its -surface. This one should offer no problem: +So far, we have the player in front of a locked door leading to the toilet. +A dead end? No, the description mentions a scribbled note on its surface. +This one should offer no problem: .. code-block:: inform @@ -691,17 +732,16 @@ surface. This one should offer no problem: ], has scenery; -Just notice how we change the description after the first time the -player examines the note, using the local property ``read_once`` created -just for this purpose. We don’t want the player to walk off with the -note, so we intercept the ``Take`` action and display something more in -character than the default message for scenery objects: "That's hardly -portable". - -We've talked a lot about the toilet key; it seems about time to code it. -Originally, the key is in Benny's possession, and the player will have -to ask for it, just as the note explains. Although we'll define Benny in -detail throughout the next chapter, here we present a basic definition, +Just notice how we change the description after the first time the player +examines the note, using the local property ``read_once`` created just for +this purpose. We don’t want the player to walk off with the note, so we +intercept the :act:`Take` action and display something more in character +than the default message for scenery objects: "That's hardly portable". + +We've talked a lot about the toilet key; it seems about time to code it. +Originally, the key is in Benny's possession, and the player will have to +ask for it, just as the note explains. Although we'll define Benny in +detail throughout the next chapter, here we present a basic definition, largely so that the key has a parent object. .. code-block:: inform @@ -733,17 +773,17 @@ largely so that the key has a parent object. "Benny is trusting you to look after that key."; ]; -While Benny has the key, there's logically no way to examine it (or -perform any other action involving it), but we want to prevent the -interpreter from objecting that ``You can't see any such thing``. We've -made the ``toilet_key`` a child of the ``benny`` object, and you can see -that Benny's got a ``transparent`` attribute; this means that the key is -in scope, and enables the player to refer to it without the interpreter -complaining. Because Benny also has an ``animate`` attribute, the -interpreter would normally intercept a TAKE KEY action with "That seems -to belong to Benny"; however, the same wouldn't apply to other commands -like TOUCH KEY and TASTE KEY . So, to prevent any interaction with the -key while it’s in Benny’s pockets, we define a ``before`` property. +While Benny has the key, there's logically no way to examine it (or perform +any other action involving it), but we want to prevent the interpreter from +objecting that ``You can't see any such thing``. We've made the +``toilet_key`` a child of the ``benny`` object, and you can see that +Benny's got a :attr:`transparent` attribute; this means that the key is in +scope, and enables the player to refer to it without the interpreter +complaining. Because Benny also has an :attr:`animate` attribute, the +interpreter would normally intercept a TAKE KEY action with "That seems to +belong to Benny"; however, the same wouldn't apply to other commands like +TOUCH KEY and TASTE KEY. So, to prevent any interaction with the key while +it’s in Benny’s pockets, we define a :prop:`before` property. .. code-block:: inform @@ -755,18 +795,18 @@ key while it’s in Benny’s pockets, we define a ``before`` property. "Benny is trusting you to look after that key."; ]; -All of the ``before`` properties that we've so far created have contained -one or more labels specifying the actions which they are to intercept; -you'll remember that in "William Tell" we introduced the ``default`` action -(see :ref:`props-class`) to mean "any value not already catered -for". There's one of those labels here, for the Drop action, but that's -preceded by a piece of code that will be executed at the start of *every* -action directed at the key. If it’s still in Benny’s possession, we display -a polite refusal; if the player has it then we prevent careless disposal; -otherwise, the action continues unhindered. +All of the :prop:`before` properties that we've so far created have +contained one or more labels specifying the actions which they are to +intercept; you'll remember that in "William Tell" we introduced the +``default`` action (see :ref:`props-class`) to mean "any value not already +catered for". There's one of those labels here, for the Drop action, but +that's preceded by a piece of code that will be executed at the start of +*every* action directed at the key. If it's still in Benny’s possession, +we display a polite refusal; if the player has it then we prevent careless +disposal; otherwise, the action continues unhindered. (In fact, the hat-on-a-pole ``Prop`` introduced in :ref:`south-side` had -this all-exclusive ``before`` property: +this all-exclusive :prop:`before` property: .. code-block:: inform @@ -775,22 +815,26 @@ this all-exclusive ``before`` property: print_ret "You're too far away at the moment."; ], -It would have behaved exactly the same if we'd omitted the ``default`` +It would have behaved exactly the same if we'd omitted the ``default`` label, as we do here for Benny's key.) -Another small innovation here: the ``invent`` library property (we -didn’t make it up) which enables you to control how objects appear in -inventory listings, overriding the default. Left to itself, the -interpreter simply displays the object’s external name, preceded either -by a standard article like "a" or "some", or one specifically defined in -the object's ``article`` property. Here we replace "the toilet key" with -one of two more helpful descriptions, making it a most valuable object -in the eyes of John Covarth, and something to be despised haughtily by -Captain Fate once it's of no further use to him. - -When we had players in the street, we faced the problem that they might -choose to examine the café from the outside. While it's unlikely that -they'll try to examine the toilet room from the outside, it takes very +.. Generated by autoindex +.. index:: + pair: article; library property + +Another small innovation here: the :prop:`invent` library property (we +didn’t make it up) which enables you to control how objects appear in +inventory listings, overriding the default. Left to itself, the +interpreter simply displays the object's external name, preceded either by +a standard article like "a" or "some", or one specifically defined in the +object's :prop:`article` property. Here we replace "the toilet key" with +one of two more helpful descriptions, making it a most valuable object in +the eyes of John Covarth, and something to be despised haughtily by Captain +Fate once it's of no further use to him. + +When we had players in the street, we faced the problem that they might +choose to examine the café from the outside. While it's unlikely that +they'll try to examine the toilet room from the outside, it takes very little effort to offer a sensible output just in case: .. code-block:: inform @@ -825,17 +869,17 @@ little effort to offer a sensible output just in case: ], has scenery openable enterable; -As with the ``outside_of_cafe`` object, we intercept an ``Enter`` -action, to teleport players into the toilet room if they type ENTER -TOILET (or to display a refusal if the toilet door is closed). Players -may try to EXAMINE TOILET; they'll get a different message if the door -is open -- we invite them to enter it -- or if it's closed. OPEN TOILET -and CLOSE TOILET inputs are redirected to ``Open`` and ``Close`` actions -for the toilet door; remember that the double angle-brackets imply a -``return true``, so that the action stops there and the interpreter does -not attempt to ``Open`` or ``Close`` the ``outside_of_toilet`` object -itself after it has dealt with the door. - -You're right: the toilet looms large in this game (we blame it on early -maternal influences). We’ve introduced an ambiguity problem with the +As with the ``outside_of_cafe`` object, we intercept an :act:`Enter` +action, to teleport players into the toilet room if they type ENTER TOILET +(or to display a refusal if the toilet door is closed). Players may try to +EXAMINE TOILET; they'll get a different message if the door is open -- we +invite them to enter it -- or if it's closed. OPEN TOILET and CLOSE TOILET +inputs are redirected to :act:`Open` and :act:`Close` actions for the +toilet door; remember that the double angle-brackets imply a ``return +true``, so that the action stops there and the interpreter does not attempt +to :act:`Open` or :act:`Close` the ``outside_of_toilet`` object itself +after it has dealt with the door. + +You're right: the toilet looms large in this game (we blame it on early +maternal influences). We’ve introduced an ambiguity problem with the ``outside_of_toilet`` object, and we'll need some help in fixing it.