X-Git-Url: https://jxself.org/git/?p=ibg.git;a=blobdiff_plain;f=chapters%2F13.rst;h=a36a32bdf96224ce908e7738802ecbd0a0390a35;hp=d4c86424f3f91a115d0d66bb60f4e8f82c4e637f;hb=4381288eeb792adb3672ef747013c02815fa760a;hpb=4261ff48a6357e2af0957f5e1b88bdc022243d16 diff --git a/chapters/13.rst b/chapters/13.rst index d4c8642..a36a32b 100644 --- a/chapters/13.rst +++ b/chapters/13.rst @@ -13,7 +13,7 @@ Captain Fate: the final cut :align: left |Y|\ou'll probably be pleased to hear that Captain Fate has almost run his -allotted span. There are some minor objects still to be defined -- the +allotted span. There are some minor objects still to be defined -- the toilet, our hero’s clothes, the all-important costume -- but first we need to decorate the café a little more. @@ -77,45 +77,48 @@ And a not-so-trivial object: it's Colombian."; ]; -There's nothing really new in this object (other than that the :prop:`name` -property caters for orthographically challenged players), but notice how -we don't ``remove`` it after the player drinks it. In an apparently -absurd whim, the coffee returns to Benny magically (although this is not -information that the player needs to know). Why? After you remove an -object from the game, if the player attempts, say, to EXAMINE it, the -interpreter will impertinently state that "You can't see any such -thing". Moreover, if the player asks Benny for a second coffee, once the -first one has been removed, Benny will complain "I don’t think that’s on -the menu, sir" -- a blatant lie -- which was the default in Benny’s -orders property. Since the removed coffee object does not belong to -Benny, it's not a noun that the player can ASK Benny FOR. By making it a -child of the barman (who has the :attr:`transparent` attribute set), the -coffee is still an object that players can refer to. We ensure that they -don't get more cups thanks to Benny's ``coffee_asked_for`` property, -which will remain :const:`true` after the first time. - -We also ensure that Benny doesn't ask for money from players who have -already paid, by first printing a "You pick up the cup..." message and -then testing Benny's ``coffee_not_paid`` property. If its value is -:const:`true`, we can finish the message with the "quidbuck" print-and-return -statement. If its value is :const:`false`, the player has previously paid, -and so there's nothing else to say. However, we still need to terminate -the incomplete message with a newline, and to return :const:`true` from the -property routine; we *could* have used the statements ``{ print "^"; -return true; }``, but an empty ``""`` statement does the same thing more -neatly. - +There's nothing really new in this object (other than that the :prop:`name` +property caters for orthographically challenged players), but notice how we +don't ``remove`` it after the player drinks it. In an apparently absurd +whim, the coffee returns to Benny magically (although this is not +information that the player needs to know). Why? After you remove an +object from the game, if the player attempts, say, to EXAMINE it, the +interpreter will impertinently state that "You can't see any such thing". +Moreover, if the player asks Benny for a second coffee, once the first one +has been removed, Benny will complain "I don’t think that’s on the menu, +sir" -- a blatant lie -- which was the default in Benny’s orders property. +Since the removed coffee object does not belong to Benny, it's not a noun +that the player can ASK Benny FOR. By making it a child of the barman (who +has the :attr:`transparent` attribute set), the coffee is still an object +that players can refer to. We ensure that they don't get more cups thanks +to Benny's ``coffee_asked_for`` property, which will remain :const:`true` +after the first time. + +.. Generated by autoindex +.. index:: + pair: false; library constant + +We also ensure that Benny doesn't ask for money from players who have +already paid, by first printing a "You pick up the cup..." message and +then testing Benny's ``coffee_not_paid`` property. If its value is +:const:`true`, we can finish the message with the "quidbuck" +print-and-return statement. If its value is :const:`false`, the player has +previously paid, and so there's nothing else to say. However, we still +need to terminate the incomplete message with a newline, and to return +:const:`true` from the property routine; we *could* have used the +statements ``{ print "^"; return true; }``, but an empty ``""`` statement +does the same thing more neatly. Toilet or dressing room? ======================== -Rather more of the latter, actually, since it's the only place away from -curious eyes where our hero will be able to metamorphose from weakling -into the bane of all evildoers. And we *really* don't want to become, -erm, bogged down with details of the room's function or plumbing. +Rather more of the latter, actually, since it's the only place away from +curious eyes where our hero will be able to metamorphose from weakling into +the bane of all evildoers. And we *really* don't want to become, erm, +bogged down with details of the room's function or plumbing. -There's not a lot about the toilet room and its contents, though there -will be some tricky side effects: +There's not a lot about the toilet room and its contents, though there will +be some tricky side effects: .. code-block:: inform @@ -159,32 +162,38 @@ will be some tricky side effects: ], has scored; -We initially place the coin as a child of the lavatory (just so that we -can easily make the ``if (coin in self)`` one-time test). Since the -lavatory does not have the :attr:`transparent` attribute set, the coin will -be invisible to players until they try to inspect the lavatory, an -action that will move the coin into the toilet room. Once taken, the -coin will remain in the inventory until the player gives it to Benny, -because we trap any ``Drop`` actions to help the player to Do the Right -Thing. - -The lavatory object includes a load of helpful synonyms in its name -property, including our favourite word ``'toilet'`` . That won't be a -problem: the other objects here which may have TOILET in their names -- -the key and the door -- both use the ``pname`` property to turn their -use of ``'toilet'`` into a lower-priority adjective. - -See that here we have the only two :attr:`scored` attributes of the game. -The player will be awarded one point for entering the toilet room, and +We initially place the coin as a child of the lavatory (just so that we can +easily make the ``if (coin in self)`` one-time test). Since the lavatory +does not have the :attr:`transparent` attribute set, the coin will be +invisible to players until they try to inspect the lavatory, an action that +will move the coin into the toilet room. Once taken, the coin will remain +in the inventory until the player gives it to Benny, because we trap any +:act:`Drop` actions to help the player to Do the Right Thing. + +The lavatory object includes a load of helpful synonyms in its name +property, including our favourite word ``'toilet'`` . That won't be a +problem: the other objects here which may have TOILET in their names -- the +key and the door -- both use the ``pname`` property to turn their use of +``'toilet'`` into a lower-priority adjective. + +.. Generated by autoindex +.. index:: + pair: scored; library attribute + +See that here we have the only two :attr:`scored` attributes of the game. +The player will be awarded one point for entering the toilet room, and another for finding and picking up the coin. -You might have noticed that we are forcefully clearing the :attr:`light` -attribute, inherited from the ``Room`` class. This will be a windowless -space and, to add a touch of realism, we'll make the room a dark one, -which will enable us to tell you about Inform's default behaviour when -there's no light to see by. However, let's define first the light switch -mentioned in the room's description to aid players in their dressing -duties. +.. Generated by autoindex +.. index:: + pair: light; library attribute + +You might have noticed that we are forcefully clearing the :attr:`light` +attribute, inherited from the ``Room`` class. This will be a windowless +space and, to add a touch of realism, we'll make the room a dark one, which +will enable us to tell you about Inform's default behaviour when there's no +light to see by. However, let's define first the light switch mentioned in +the room's description to aid players in their dressing duties. .. code-block:: inform @@ -208,10 +217,10 @@ duties. ], has switchable ~on; -Please notice the appearance of new attributes :attr:`switchable` and -:attr:`on`. switchable enables the object to be turned on and off, and is -typical of lanterns, computers, television sets, radios, and so on. The -library automatically extends the description of these objects by +Please notice the appearance of new attributes :attr:`switchable` and +:attr:`on`. :attr:`switchable` enables the object to be turned on and off, +and is typical of lanterns, computers, television sets, radios, and so on. +The library automatically extends the description of these objects by indicating if they are currently on or off: .. code-block:: transcript @@ -220,20 +229,19 @@ indicating if they are currently on or off: A notorious ACHIEVEMENT of technological SCIENCE, elegant yet EASY to use. The light switch is currently switched on. -Two new actions are ready to use, ``SwitchOn`` and ``SwitchOff``. Left -to themselves, they toggle the object's state between ON and OFF and +Two new actions are ready to use, :act:`SwitchOn` and :act:`SwitchOff`. +Left to themselves, they toggle the object's state between ON and OFF and display a message like: .. code-block:: transcript You switch the brass lantern on. -They also take care of checking if the player fumbled and tried to turn -on (or off) an object which was already on (or off). How does the -library know the state of the object? This is thanks to the :attr:`on` -attribute, which is set or cleared automatically as needed. You can, of -course, set or clear it manually like any other attribute, with the -``give`` statement: +They also take care of checking if the player fumbled and tried to turn on +(or off) an object which was already on (or off). How does the library +know the state of the object? This is thanks to the :attr:`on` attribute, +which is set or cleared automatically as needed. You can, of course, set +or clear it manually like any other attribute, with the ``give`` statement: .. code-block:: inform @@ -249,59 +257,62 @@ and check if a :attr:`switchable` object is on or off with the test: if (light_switch hasnt on) ... -A :attr:`switchable` object is OFF by default. However, you’ll notice that +A :attr:`switchable` object is OFF by default. However, you’ll notice that the has line of the object definition includes ``~on`` : .. code-block:: inform has switchable ~on; -Surely that’s saying "not-on"? Surely that's what would have happened +Surely that’s saying "not-on"? Surely that's what would have happened anyway if the line hadn't mentioned the attribute at all? .. code-block:: inform has switchable; -Absolutely true. Adding that ``~on`` attribute has no effect whatsoever -on the game -- but nevertheless it's a good idea. It's an aide-mémoire, -a way of reminding ourselves that we start with the attribute clear, and -that at some point we'll be setting it for some purpose. Trust us: it's -worthwhile taking tiny opportunities like this to help yourself. - -Let’s see how our light switch works. We trap the ``SwitchOn`` and -``SwitchOff`` actions in the :prop:`after` property (when the switching has -successfully taken place) and use them to give :attr:`light` to the light -switch. - -Uh, wait. To the light switch? Why not to the toilet room? Well, there's -a reason and we'll see it in a minute. For now, just remember that, in -order for players to see their surroundings, you need only one object in -a room with the :attr:`light` attribute set. It doesn't have to be the room +Absolutely true. Adding that ``~on`` attribute has no effect whatsoever on +the game -- but nevertheless it's a good idea. It's an aide-mémoire, a way +of reminding ourselves that we start with the attribute clear, and that at +some point we'll be setting it for some purpose. Trust us: it's worthwhile +taking tiny opportunities like this to help yourself. + +.. Generated by autoindex +.. index:: + pair: after; library property + +Let’s see how our light switch works. We trap the :act:`SwitchOn` and +:act:`SwitchOff` actions in the :prop:`after` property (when the switching +has successfully taken place) and use them to give :attr:`light` to the +light switch. + +Uh, wait. To the light switch? Why not to the toilet room? Well, there's +a reason and we'll see it in a minute. For now, just remember that, in +order for players to see their surroundings, you need only one object in a +room with the :attr:`light` attribute set. It doesn't have to be the room itself (though this is usually convenient). -After setting the :attr:`light` attribute, we display a customised message, +After setting the :attr:`light` attribute, we display a customised message, to avoid the default: .. code-block:: transcript You switch the light switch on. -which, given the name of the object, doesn't read very elegantly. We -foresee that players might try to PUSH SWITCH, so we trap this attempt -in a :prop:`before` property and redirect it to ``SwitchOn`` and -``SwitchOff`` actions, checking first which one is needed by testing the -:attr:`on` attribute. Finally, we have made the switch a member of the class -``Appliance``, so that the player doesn't walk away with it. +which, given the name of the object, doesn't read very elegantly. We +foresee that players might try to PUSH SWITCH, so we trap this attempt in a +:prop:`before` property and redirect it to :act:`SwitchOn` and +:act:`SwitchOff` actions, checking first which one is needed by testing the +:attr:`on` attribute. Finally, we have made the switch a member of the +class ``Appliance``, so that the player doesn't walk away with it. .. note:: - Remember what we said about class inheritance? No matter what you - define in the class, the object’s definition has priority. The class - ``Appliance`` defines a response for the ``Push`` action, but we + Remember what we said about class inheritance? No matter what you define + in the class, the object’s definition has priority. The class + ``Appliance`` defines a response for the :act:`Push` action, but we override it here with a new behaviour. - And there was light =================== @@ -312,13 +323,12 @@ So the player walks into the toilet and Darkness It is pitch dark, and you can't see a thing. -Oops! No toilet description, no mention of the light switch, nothing. It -is reasonable to think that if we have opened the toilet door to access -the toilet, some light coming from the café room will illuminate our -surroundings -- at least until the player decides to close the door. So -perhaps it would be a good idea to append a little code to the door -object to account for this. A couple of lines in the after property will -suffice: +Oops! No toilet description, no mention of the light switch, nothing. It +is reasonable to think that if we have opened the toilet door to access the +toilet, some light coming from the café room will illuminate our +surroundings -- at least until the player decides to close the door. So +perhaps it would be a good idea to append a little code to the door object +to account for this. A couple of lines in the after property will suffice: .. code-block:: inform @@ -336,19 +346,19 @@ suffice: ], -And this is the reason why the light switch didn't set the :attr:`light` -attribute of the toilet room, but did it to itself. We avoid running -into trouble if we let the open/closed states of the door control the -light of the room object, and the on/off states of the switch control -the light of the switch. So it is one shiny light switch. Fortunately, -players are never aware of this glowing artefact. +And this is the reason why the light switch didn't set the :attr:`light` +attribute of the toilet room, but did it to itself. We avoid running into +trouble if we let the open/closed states of the door control the light of +the room object, and the on/off states of the switch control the light of +the switch. So it is one shiny light switch. Fortunately, players are +never aware of this glowing artefact. .. note:: - Now, could they? Well, if players could TAKE the light switch (which - we have forbidden) and then did INVENTORY, the trick would be given - away, because all objects with the :attr:`light` attribute set are listed - as ``(providing light)`` . + Now, could they? Well, if players could TAKE the light switch (which we + have forbidden) and then did INVENTORY, the trick would be given away, + because all objects with the :attr:`light` attribute set are listed as + ``(providing light)`` . So the player walks into the toilet and @@ -361,7 +371,7 @@ So the player walks into the toilet and [Your score has just gone up by one point.] -Better. Now, suppose the player closes the door. +Better. Now, suppose the player closes the door. .. code-block:: transcript @@ -372,7 +382,7 @@ Better. Now, suppose the player closes the door. The player might try then to LOOK: -Well, no problem. We have mentioned that there is a light switch. Surely +Well, no problem. We have mentioned that there is a light switch. Surely the player will now try to: .. code-block:: transcript @@ -380,7 +390,7 @@ the player will now try to: >TURN ON LIGHT SWITCH You can't see any such thing. -Oops! Things are getting nasty here in the dark. It's probably time to +Oops! Things are getting nasty here in the dark. It's probably time to leave this place and try another approach: .. code-block:: transcript @@ -388,41 +398,40 @@ leave this place and try another approach: >OPEN DOOR You can't see any such thing. -And this illustrates one of the terrible things about darkness in a -game. You can't see anything; you can do very little indeed. All objects -except those in your inventory are out of scope, unreachable, as if -non-existent. Worse, if you DROP one of the objects you are carrying, it -will be swallowed by the dark, never to be found until there is light to -see by. - -The player, who is doubtless immersed in the fantasy of the game, will -now be a little annoyed. "I am in a small bathroom and I can't even -reach the door I have just closed?" The player's right, of -course [#dark]_. Darkened rooms are one cliché of traditional games. -Usually you move in one direction while looking for treasure in some -underground cave, and suddenly arrive at a pitch black place. It's good -behaviour of the game to disallow exploration of unknown dark territory, -and it's a convention to bar passage to players until they return with a -light source. However, if the scenario of the game features, say, the -player character's home, a little apartment with two rooms, and there’s -no light in the kitchen, we could expect the owner of the house to know -how to move around a little, perhaps groping for the light switch or -even going to the refrigerator in the dark. - -We are in a similar situation. The inner logic of the game demands that -blind players should be able to open the door and probably operate the -light switch they've just encountered. We have been telling you that an -object is in scope when it’s in the same room as the player. Darkness -changes that rule. All objects not directly carried by the player become +And this illustrates one of the terrible things about darkness in a game. +You can't see anything; you can do very little indeed. All objects except +those in your inventory are out of scope, unreachable, as if non-existent. +Worse, if you DROP one of the objects you are carrying, it will be +swallowed by the dark, never to be found until there is light to see by. + +The player, who is doubtless immersed in the fantasy of the game, will now +be a little annoyed. "I am in a small bathroom and I can't even reach the +door I have just closed?" The player's right, of course [#dark]_. +Darkened rooms are one cliché of traditional games. Usually you move in +one direction while looking for treasure in some underground cave, and +suddenly arrive at a pitch black place. It's good behaviour of the game to +disallow exploration of unknown dark territory, and it's a convention to +bar passage to players until they return with a light source. However, if +the scenario of the game features, say, the player character's home, a +little apartment with two rooms, and there’s no light in the kitchen, we +could expect the owner of the house to know how to move around a little, +perhaps groping for the light switch or even going to the refrigerator in +the dark. + +We are in a similar situation. The inner logic of the game demands that +blind players should be able to open the door and probably operate the +light switch they've just encountered. We have been telling you that an +object is in scope when it’s in the same room as the player. Darkness +changes that rule. All objects not directly carried by the player become out of scope. -One of the advantages of an advanced design system like Inform is the -flexibility to change all default behaviours to suit your particular -needs. Scope problems are no different. There is a set of routines and -functions to tamper with what's in scope when. We'll see just a tiny -example to fix our particular problem. In the section "``Entry point -routines``" of our game -- after the ``Initialise`` routine, for -instance -- include the following lines: +One of the advantages of an advanced design system like Inform is the +flexibility to change all default behaviours to suit your particular needs. +Scope problems are no different. There is a set of routines and functions +to tamper with what's in scope when. We'll see just a tiny example to fix +our particular problem. In the section "``Entry point routines``" of our +game -- after the ``Initialise`` routine, for instance -- include the +following lines: .. code-block:: inform @@ -436,20 +445,24 @@ instance -- include the following lines: :samp:`InScope({actor_obj_id})` is an entry point routine that can tamper with the scope rules for the given :samp:`{actor_obj_id}` (either the -player character or a NPC). We define it with one variable (which we name +player character or a NPC). We define it with one variable (which we name as we please; it's also a good idea to name variables in an intuitive way to remind us of what they represent), ``person`` , and then we make a complex test to see if the player is actually in the toilet and in the dark. -We have told you that the library variable :var:`location` holds the -current -room that the player is in. However, when there is no light, the -variable location gets assigned to the value of the special library -object thedark . It doesn't matter if we have ten dark rooms in our -game; location will be equal to thedark in all of them. There is yet -another variable, called :var:`real_location`, which holds the room the -player is in *even when there is no light to see by*. +.. Generated by autoindex +.. index:: + pair: location; library variable + pair: real_location; library variable + +We have told you that the library variable :var:`location` holds the +current room that the player is in. However, when there is no light, the +variable location gets assigned to the value of the special library object +thedark . It doesn't matter if we have ten dark rooms in our game; +location will be equal to thedark in all of them. There is yet another +variable, called :var:`real_location`, which holds the room the player is +in *even when there is no light to see by*. So the test: @@ -457,19 +470,22 @@ So the test: if (person == player && location == thedark && real_location == toilet) ... -is stating: if the specified actor is the :var:`player` character *and* he -finds himself in the dark *and* he actually happens to be in the -toilet... +is stating: if the specified actor is the :var:`player` character *and* he +finds himself in the dark *and* he actually happens to be in the toilet... + +.. Generated by autoindex +.. index:: + pair: true; library constant Then we make a call to one of the library routines, :samp:`PlaceInScope({obj_id})`, which has a very descriptive name: it -places in scope the given object. In our case, we want both the door and +places in scope the given object. In our case, we want both the door and the light switch to be within reach of the player, hence both additional -lines. Finally, we must ``return false``, because we want the normal scope +lines. Finally, we must ``return false``, because we want the normal scope rules for the defined actor -- the player -- to apply to the rest of the -objects of the game (if we returned :const:`true`, players would find that they -are able to interact with very little indeed). Now we get a friendlier and -more logical response: +objects of the game (if we returned :const:`true`, players would find that +they are able to interact with very little indeed). Now we get a +friendlier and more logical response: .. code-block:: transcript @@ -484,39 +500,44 @@ more logical response: little more than a lavatory and a light switch. The only exit is south, through the door and into the cafe. -And the same would happen with the door. Notice how the room description -gets displayed after we pass from dark to light; this is the normal -library behaviour. +And the same would happen with the door. Notice how the room description +gets displayed after we pass from dark to light; this is the normal library +behaviour. -There is still one final problem which, admittedly, might originate from -an improbable course of action; however, it could be a nuisance. Suppose -that the player enters the toilet, locks the door -- which is possible -in the dark now that the door is in scope -- and then drops the key. -There's no way to exit the toilet -- because the door is locked and the -key has disappeared, engulfed by the darkness -- unless the player -thinks to turn on the light switch, thereby placing the key in scope -once more. +There is still one final problem which, admittedly, might originate from an +improbable course of action; however, it could be a nuisance. Suppose that +the player enters the toilet, locks the door -- which is possible in the +dark now that the door is in scope -- and then drops the key. There's no +way to exit the toilet -- because the door is locked and the key has +disappeared, engulfed by the darkness -- unless the player thinks to turn +on the light switch, thereby placing the key in scope once more. Why don't we add a :samp:`PlaceInScope({toilet_key})` to the above routine? Well, for starters, the key can be moved around (as opposed to the door or -the light switch, which are fixed items in the toilet room). Suppose the +the light switch, which are fixed items in the toilet room). Suppose the player opens the door of the toilet, but drops the key in the café, then -enters the toilet and closes the door. The condition is met and the key is -placed in scope, when it's in another room. Second, this is a simple game +enters the toilet and closes the door. The condition is met and the key is +placed in scope, when it's in another room. Second, this is a simple game with just a few objects, so you can define a rule for each of them; but in any large game, you might like to be able to refer to objects in bunches, and make general rules that apply to all (or some) of them. -We need to add code to the ``InScope`` routine, telling the game to -place in scope all objects that we drop in the dark, so that we might -recover them (maybe going on all fours and groping a little, but it’s a -possible action). We don’t want the player to have other objects in -scope (like the coin, for instance), so it might be good to have a way -of testing if the objects have been touched and carried by the player. -The attribute :attr:`moved` is perfect for this. The library sets it for -every object that the player has picked up at one time in the game; -:attr:`scenery` and :attr:`static` objects, and those we have not yet seen don't -have :attr:`moved`. Here is the reworked ``InScope`` routine. There are a +.. Generated by autoindex +.. index:: + pair: moved; library attribute + pair: scenery; library attribute + pair: static; library attribute + +We need to add code to the ``InScope`` routine, telling the game to place +in scope all objects that we drop in the dark, so that we might recover +them (maybe going on all fours and groping a little, but it’s a possible +action). We don’t want the player to have other objects in scope (like the +coin, for instance), so it might be good to have a way of testing if the +objects have been touched and carried by the player. The attribute +:attr:`moved` is perfect for this. The library sets it for every object +that the player has picked up at one time in the game; :attr:`scenery` and +:attr:`static` objects, and those we have not yet seen don't have +:attr:`moved`. Here is the reworked ``InScope`` routine. There are a couple of new concepts to look at: .. code-block:: inform @@ -532,25 +553,25 @@ couple of new concepts to look at: return false; ]; -We have added one more local variable to the routine, ``item`` -- again, -this is a variable we have created and named on our own; it is not part -of the library. We make now a new test: if the actor is the player and -the location is any dark room, then perform a certain action. We don't -need to specify the toilet, because we want this rule to apply to all -dark rooms (well, the only dark room in the game *is* the toilet, but we -are trying to provide a general rule). +We have added one more local variable to the routine, ``item`` -- again, +this is a variable we have created and named on our own; it is not part of +the library. We make now a new test: if the actor is the player and the +location is any dark room, then perform a certain action. We don't need to +specify the toilet, because we want this rule to apply to all dark rooms +(well, the only dark room in the game *is* the toilet, but we are trying to +provide a general rule). :samp:`objectloop (variable) {statement};` -is a loop statement, one of the four defined in Inform. A loop statement is -a construct that allows you to run several times through a statement (or a -statement block). ``objectloop`` performs the :samp:`{statement}` once for -every object defined in the (:samp:`{variable}`) . If we were to code: +is a loop statement, one of the four defined in Inform. A loop statement +is a construct that allows you to run several times through a statement (or +a statement block). ``objectloop`` performs the :samp:`{statement}` once +for every object defined in the (:samp:`{variable}`) . If we were to code: :samp:`objectloop (item) {statement};` then the :samp:`{statement}` would be executed once for each object in the -game. However, we want to perform the statement only for those objects +game. However, we want to perform the statement only for those objects whose parent object is the same as the player's parent object: that is, for objects in the same room as the player, so we instead code: @@ -563,25 +584,24 @@ What is the actual :samp:`{statement}` that we'll repeatedly execute? if (item has moved) PlaceInScope(item); -The test: ``if (item has moved)`` ensures that ``PlaceInScope(item)`` -deals only with objects with the :attr:`moved` attribute set. So: if the -player is in the dark, let’s go through the objects which are in the -same room, one at a time. For each of them, check if it's an item that -the player has at some time carried, in which case, place it in scope. -All dropped objects within the room were carried at one time, so we let -players recollect them even if they can’t see them. - -As you see, darkness has its delicate side. If you plan to have dark -rooms galore in your games, bear in mind that you are in for some -elaborate code (unless you let the library carry on with default rules, -in which case there won't be much for your players to do). +The test: ``if (item has moved)`` ensures that ``PlaceInScope(item)`` deals +only with objects with the :attr:`moved` attribute set. So: if the player +is in the dark, let’s go through the objects which are in the same room, +one at a time. For each of them, check if it's an item that the player has +at some time carried, in which case, place it in scope. All dropped +objects within the room were carried at one time, so we let players +recollect them even if they can’t see them. +As you see, darkness has its delicate side. If you plan to have dark rooms +galore in your games, bear in mind that you are in for some elaborate code +(unless you let the library carry on with default rules, in which case +there won't be much for your players to do). Amazing techicolour dreamcoats ============================== -This leaves us the clothing items themselves, which will require a few -tailored actions. Let's see first the ordinary garments of John Covarth: +This leaves us the clothing items themselves, which will require a few +tailored actions. Let's see first the ordinary garments of John Covarth: .. code-block:: inform @@ -645,43 +665,47 @@ tailored actions. Let's see first the ordinary garments of John Covarth: ], clothing proper pluralname; -See how the object deals only with ``Wear``, ``Disrobe`` and ``Change``. -``Wear`` and ``Disrobe`` are standard library actions already defined in -Inform, but we'll have to make a new verb to allow for CHANGE CLOTHES. -In this game, ``Disrobe`` and ``Change`` are considered synonymous for -all purposes; we'll deal with them first. - -The goal of the game is for players to change their clothes, so we might -expect them to try this almost anywhere; but first of all we have to -check that the ``clothes`` object is actually being worn. If not, we -display a message reminding the player that this action has become -irrelevant. What we do with the ``switch`` statement is to offer a -variety of responses according to the :var:`location` variable. The street -(in or out of the booth) and the café all display refusals of some kind, -until the player character manages to enter the toilet, where we -additionally require that he locks the door before taking off his -clothes. If the door is closed but not locked, he is interrupted in his -naked state by a nervous woman who starts shouting, and the game is lost -(this is not as unfair as it seems, because the player may always revert -to the previous state with UNDO). If the door is locked, he succeeds in -his transformation (we take away the :attr:`worn` attribute from the -``clothes`` and give it to the ``costume`` instead). We add a special -refusal to change in the dark, forcing players to turn on the light and -then, we hope, to find the coin. And finally we code a ``default`` -entry; you'll remember that, in a ``switch`` statement, this is supposed -to cater for any value not explicitly listed for the expression under -control -- in this case, for the variable :var:`location`. Since we have -already gone through all the possible locations of the game, this entry -appears only as a defensive measure, just in case something unexpected -happens (for instance, we might extend the game with another room and -forget about this ``switch`` statement). In normal and controlled -conditions, it should never be reached, but it doesn't hurt one bit to -have it there. - -The ``Wear`` action just checks if these clothes are already being worn, -to offer two different rejection responses: the goal of the game is to -change into the hero's suit, after which we'll prevent a change back -into ordinary clothes. So now we are dealing with a Captain Fate in full +See how the object deals only with :act:`Wear`, :act:`Disrobe` and +:act:`Change`. :act:`Wear` and :act:`Disrobe` are standard library actions +already defined in Inform, but we'll have to make a new verb to allow for +CHANGE CLOTHES. In this game, :act:`Disrobe` and :act:`Change` are +considered synonymous for all purposes; we'll deal with them first. + +.. Generated by autoindex +.. index:: + pair: location; library variable + pair: worn; library attribute + +The goal of the game is for players to change their clothes, so we might +expect them to try this almost anywhere; but first of all we have to check +that the ``clothes`` object is actually being worn. If not, we display a +message reminding the player that this action has become irrelevant. What +we do with the ``switch`` statement is to offer a variety of responses +according to the :var:`location` variable. The street (in or out of the +booth) and the café all display refusals of some kind, until the player +character manages to enter the toilet, where we additionally require that +he locks the door before taking off his clothes. If the door is closed but +not locked, he is interrupted in his naked state by a nervous woman who +starts shouting, and the game is lost (this is not as unfair as it seems, +because the player may always revert to the previous state with UNDO). If +the door is locked, he succeeds in his transformation (we take away the +:attr:`worn` attribute from the ``clothes`` and give it to the ``costume`` +instead). We add a special refusal to change in the dark, forcing players +to turn on the light and then, we hope, to find the coin. And finally we +code a ``default`` entry; you'll remember that, in a ``switch`` statement, +this is supposed to cater for any value not explicitly listed for the +expression under control -- in this case, for the variable :var:`location`. +Since we have already gone through all the possible locations of the game, +this entry appears only as a defensive measure, just in case something +unexpected happens (for instance, we might extend the game with another +room and forget about this ``switch`` statement). In normal and controlled +conditions, it should never be reached, but it doesn't hurt one bit to have +it there. + +The :act:`Wear` action just checks if these clothes are already being worn, +to offer two different rejection responses: the goal of the game is to +change into the hero's suit, after which we'll prevent a change back into +ordinary clothes. So now we are dealing with a Captain Fate in full costume: .. code-block:: inform @@ -709,11 +733,10 @@ costume: ], has clothing proper; -Note that we intercept the action WEAR COSTUME and hint that players -should try TAKE OFF CLOTHES instead. We don't let them take off the -costume once it’s being worn, and we certainly don't let them misplace -it anywhere, by refusing to accept a ``Drop`` action. - +Note that we intercept the action WEAR COSTUME and hint that players should +try TAKE OFF CLOTHES instead. We don't let them take off the costume once +it’s being worn, and we certainly don't let them misplace it anywhere, by +refusing to accept a :act:`Drop` action. It's a wrap =========== @@ -722,9 +745,9 @@ Nearly there; just a few minor odds and ends to round things off. .. rubric:: Initialise routine -All the objects of our game are defined. Now we must add a couple of -lines to the ``Initialise`` routine to make sure that the player does -not start the game naked: +All the objects of our game are defined. Now we must add a couple of lines +to the ``Initialise`` routine to make sure that the player does not start +the game naked: .. code-block:: inform @@ -741,39 +764,39 @@ not start the game naked: Captain FATE costume fast...!^^"; ]; -Remember that we included a disambiguation package, ``pname.h``? There -were some additional comments in the accompanying text file that should -be taken in consideration: +Remember that we included a disambiguation package, ``pname.h``? There +were some additional comments in the accompanying text file that should be +taken in consideration: - pname.h provides a pname_verify routine. When DEBUG is defined, you - may call pname_verify() in your Initialise() routine to verify the pname + pname.h provides a pname_verify routine. When DEBUG is defined, you may + call pname_verify() in your Initialise() routine to verify the pname properties in your objects. -The designer of the package has made a debugging tool (a routine) to -check for errors when using his library, and he tells us how to use it. -So we include the suggested lines into our ``Initialise`` routine: +The designer of the package has made a debugging tool (a routine) to check +for errors when using his library, and he tells us how to use it. So we +include the suggested lines into our ``Initialise`` routine: .. code-block:: inform #Ifdef DEBUG; pname_verify(); #Endif; -As the text explains, what this does is: first check whether the game is -being compiled in Debug mode; if this is the case, run the -``pname_verify`` routine, so that it tests all ``pname`` properties to -see if they are written correctly. +As the text explains, what this does is: first check whether the game is +being compiled in Debug mode; if this is the case, run the ``pname_verify`` +routine, so that it tests all ``pname`` properties to see if they are +written correctly. .. rubric:: Demise of our hero We have made three possible endings: -#. The player attempts to change in the toilet with an unlocked door. +#. The player attempts to change in the toilet with an unlocked door. -#. The player tries to attack Benny while wearing the costume. +#. The player tries to attack Benny while wearing the costume. -#. The player manages to exit the café dressed as Captain Fate. +#. The player manages to exit the café dressed as Captain Fate. -(1) and (2) lose the game, (3) wins it. The library defaults for these -two states display, respectively, +(1) and (2) lose the game, (3) wins it. The library defaults for these two +states display, respectively, .. code-block:: transcript @@ -781,13 +804,13 @@ two states display, respectively, *** You have won *** -These states correspond to the values of the :var:`deadflag` variable: 1 -for losing, 2 for winning. However, we have made up different messages, -because our hero does not really die -- ours suffers a FATE worse than -death -- and because we want to give him a more descriptive winning -line. Therefore, we must define a ``DeathMessage`` routine as we did in -"William Tell", to write our customised messages and assign them to -:var:`deadflag` values greater than 2. +These states correspond to the values of the :var:`deadflag` variable: 1 +for losing, 2 for winning. However, we have made up different messages, +because our hero does not really die -- ours suffers a FATE worse than +death -- and because we want to give him a more descriptive winning line. +Therefore, we must define a ``DeathMessage`` routine as we did in "William +Tell", to write our customised messages and assign them to :var:`deadflag` +values greater than 2. .. code-block:: inform @@ -799,9 +822,9 @@ line. Therefore, we must define a ``DeathMessage`` routine as we did in .. rubric:: Grammar -Finally, we need to extend the existing grammar, to allow for a couple -of things. We have already seen that we need a verb CHANGE. We'll make -it really simple: +Finally, we need to extend the existing grammar, to allow for a couple of +things. We have already seen that we need a verb CHANGE. We'll make it +really simple: .. code-block:: inform @@ -814,19 +837,23 @@ it really simple: Verb 'change' 'exchange' 'swap' 'swop' * noun -> Change; -Just notice how the verb handler checks whether the noun given is plural -or singular, to display a suitable pronoun. +Just notice how the verb handler checks whether the noun given is plural or +singular, to display a suitable pronoun. + +A further detail: when players are in the café, they might ask Benny for +the coffee (as we intend and heavily hint), for a sandwich or a pastry +(both mentioned in the café description), for food or a snack (mentioned +here and there, and we have provided for those); but what if they try a +meat pie? Or scrambled eggs? There’s just so much decoration one can +reasonably insert in a game, and loading the dictionary with Benny’s full +menu would be overdoing it a bit. -A further detail: when players are in the café, they might ask Benny for -the coffee (as we intend and heavily hint), for a sandwich or a pastry -(both mentioned in the café description), for food or a snack (mentioned -here and there, and we have provided for those); but what if they try a -meat pie? Or scrambled eggs? There’s just so much decoration one can -reasonably insert in a game, and loading the dictionary with Benny’s -full menu would be overdoing it a bit. +.. Generated by autoindex +.. index:: + pair: Give; library action -One might reasonably imagine that the ``default`` line at the end of the -``Give`` action in the orders property handles every input not already +One might reasonably imagine that the ``default`` line at the end of the +:act:`Give` action in the orders property handles every input not already specified: .. code-block:: inform @@ -843,7 +870,7 @@ specified: } ], -Not so. The library grammar that deals with ASK BENNY FOR... is this +Not so. The library grammar that deals with ASK BENNY FOR... is this (specifically, the last line): .. code-block:: inform @@ -852,50 +879,45 @@ Not so. The library grammar that deals with ASK BENNY FOR... is this * creature 'about' topic -> Ask * creature 'for' noun -> AskFor -You'll see the :var:`noun` token, which means that whatever the player asks -him for must be a real game object, visible at that moment. Assuming -that the player mentions such an object, the interpreter finds it in the -dictionary and places its internal ID in the :var:`noun` variable, where -our ``switch`` statement can handle it. So, ASK BENNY FOR KEY assigns -the ``toilet_key`` object to the noun variable, and Benny responds. ASK -BENNY FOR CUSTOMERS also works; the ``default`` case picks that one up. -But, ASK BENNY FOR SPAGHETTI BOLOGNESE won't work: we have no object for -Spaghetti Bolognese (or any other delicacy from Benny's kitchen) -- the -words ``'spaghetti'`` and ``'bolognese'`` simply aren't in the -dictionary. This is perhaps not a major deficiency in our game, but it -takes very little to allow Benny to use his default line for *any* -undefined input from the player. We need to extend the existing ASK -grammar: +You'll see the :var:`noun` token, which means that whatever the player asks +him for must be a real game object, visible at that moment. Assuming that +the player mentions such an object, the interpreter finds it in the +dictionary and places its internal ID in the :var:`noun` variable, where +our ``switch`` statement can handle it. So, ASK BENNY FOR KEY assigns the +``toilet_key`` object to the noun variable, and Benny responds. ASK BENNY +FOR CUSTOMERS also works; the ``default`` case picks that one up. But, ASK +BENNY FOR SPAGHETTI BOLOGNESE won't work: we have no object for Spaghetti +Bolognese (or any other delicacy from Benny's kitchen) -- the words +``'spaghetti'`` and ``'bolognese'`` simply aren't in the dictionary. This +is perhaps not a major deficiency in our game, but it takes very little to +allow Benny to use his default line for *any* undefined input from the +player. We need to extend the existing ASK grammar: .. code-block:: inform Extend 'ask' * creature 'for' topic -> AskFor; -This line will be added to the end of the existing grammar for Ask, so -it doesn’t override the conventional noun-matching line. ``topic`` is a -token that roughly means “any input at all”; the value of noun isn't -important, because it'll be handled by the default case. Now players may -ask Benny for a tuna sandwich or a good time; they'll get: "I don’t -think that’s on the menu, sir", which makes Benny a barman with -attitude. - -And that's it; on the slightly surreal note of ASK BENNY FOR A GOOD TIME -we've taken "Captain Fate" as far as we intend to. The guide is nearly -done. All that's left is to recap some of the more important issues, -talk a little more about compilation and debugging, and send you off -into the big wide world of IF authorship. +This line will be added to the end of the existing grammar for Ask, so it +doesn’t override the conventional noun-matching line. ``topic`` is a token +that roughly means "any input at all"; the value of noun isn't important, +because it'll be handled by the default case. Now players may ask Benny +for a tuna sandwich or a good time; they'll get: "I don’t think that’s on +the menu, sir", which makes Benny a barman with attitude. +And that's it; on the slightly surreal note of ASK BENNY FOR A GOOD TIME +we've taken "Captain Fate" as far as we intend to. The guide is nearly +done. All that's left is to recap some of the more important issues, talk +a little more about compilation and debugging, and send you off into the +big wide world of IF authorship. .. rubric:: Footnotes .. [#dark] - - We're alluding here to the Classical concept of mimesis. In an - oft-quoted essay from 1996, Roger Giner-Sorolla wrote: "I see - successful fiction as an imitation or 'mimesis' of reality, be it - this world's or an alternate world's. Well-written fiction leads the - reader to temporarily enter and believe in the reality of that world. - A crime against mimesis is any aspect of an IF game that breaks the - coherence of its fictional world as a representation of reality." - + We're alluding here to the Classical concept of mimesis. In an + oft-quoted essay from 1996, Roger Giner-Sorolla wrote: "I see successful + fiction as an imitation or 'mimesis' of reality, be it this world's or + an alternate world's. Well-written fiction leads the reader to + temporarily enter and believe in the reality of that world. A crime + against mimesis is any aspect of an IF game that breaks the coherence of + its fictional world as a representation of reality."