============================================================================ Errata (16 May 1997) for correcting The Inform Designer's Manual, 3rd Ed. (4 September 1996) ============================================================================ In February I published a draft list of errata, and here is the final list: new or altered corrections (since the draft, that is) are marked with asterisks in the margin. If these corrections are made then the manual becomes fully up to date with state-of-the-art Inform, i.e., Inform 6.13 and library 6/5. The primary version of the manual -- the TeX source code -- I've updated myself. Conversions should please note on their title pages that these errata have been absorbed, if they have been. For example, Stephen van Egmond's plain text copy might begin The Inform Designer's Manual by Graham Nelson Third edition 4 September 1996 as updated 16 May 1997 (note: the update date is the date of this errata list, not the date when the corrections were actually made by Stephen or whoever). What has been changed? Firstly there are a few dozen tiny mistakes, mostly typographical but some actually changing the meaning of the text. Secondly the manual reflects improved facilities in Inform for grammar, for enterable objects and for touchability rules, as well as subtle changes brought on by these. Thirdly a few passages have been clarified, usually at somebody's request. Fourthly almost all the exercise solutions have been tidied up and debugged. (For some months the "Museum of Inform" example game has contained much better coded solutions to the exercises than the manual gave.) I am especially indebted to Miron Schmidt for combing through the manual with infinite patience; and to several of the galley-slaves who spotted mistakes while reformatting, particularly Allison Weaver and Christopher Madsen. I would also like to acknowledge the trouble taken by Torbj|rn Andersson, Timothy Buege, Kevin Bracey, Linards Ticmanis, Anson Turner, Lucian Smith and above all Charles Briscoe-Smith in commenting on and adding to the draft errata. Graham Nelson 16 May 1997 [MORE] References mainly given to page numbers in the TeX typeset original (4 September 1996) but note that Stephen van Egmond's plain text copy (11 October 1996) uses the same pagination and is easier to search. Italics below are written _thus_. The notation \S indicates a section sign. Text in a typewriter-style font is written between vertical strokes |thus|. Exercise, book and section numbering is unchanged: thus the old exercise 63 is still called exercise 63 in the corrected version, and so on. Part I -- All alterations except those to exercise solutions and to the list of library messages ================================================== detailed contents of section 28: * replace "which applies to other people as well;" with * "touchability is stricter than scope;" contents: Change the title of section 3.14 from * "Footnote on common vs. individual objects" * to * "Footnote on common vs. individual properties" p.6 The contents have the order of the appendices juggled. The correct sequence of A7, A8, A9 is: A7 Library-defined objects and routines A8 Library actions A9 Library message numbers p.7 After "...becoming someone else in mid-game." and before "The world-model includes...", insert the sentence "It can be configured to languages other than English." p.8 Alter "with a line reading just |...|" * to "with a line reading just ``|...|''", i.e., put the ellipsis * in quotation marks. p.8 Delete first "from" in "To keep from Book Two from ...". p.8 Delete the sentence "There is also a 'Shell' game ... anyway." p.8 Replace "The best source for Inform..." with "The Internet * source for Inform..." and change the sentence giving the ftp * directory to: * * Inform can be found at: * |ftp://ftp.gmd.de/if-archive/infocom/compilers/inform6| p.8 Delete the passage Another useful resource is the Inform home page on the `World Wide Web', currently maintained by Gareth Rees at: |http://www.cl.cam.ac.uk/users/gdr11/inform| and replace with Another useful resource is the Inform 6 home page on the `World Wide Web', which includes Gareth Rees's `Alice' tutorial, located at: |http://www.gnelson.demon.co.uk/inform.html| p.9 Rewrite the sentence This manual describes Inform release 6.04 (or later), using library release 6/2 (or later). Inform 6.01 to 6.03 and library 6/1 are very similar but Inform 5.5 and 5/12 very different. as * This manual describes Inform release 6.13 (or later), using * library release 6/5 (or later). Earlier Inform 6 compilers and * libraries are very similar but Inform 5.5 and 5/12 are very * different. p.9 Correct "So there are three `companion volumes'." to "So there are four `companion volumes'." At the end of this paragraph add the sentence _The Inform Translator's Manual_ describes how to write a language definition file for games which speak languages other than English. p.10 Correct the signing-off date to May 1997. p.18 Replace "One such operator is =:" with "One such operator is `set equals':" p.20 Remove "(there can be any number from none up to 7)". Instead add a new sentence after this one, reading: Usually, there can be any number of arguments from none up to 7, though a limit of 3 applies if Inform has been told to compile an early-model story file (see \S 31 for details). p.21 To the end of the text about |or|, continue with the following: * For example * | if (player in Forest or Village or Building) ...| * often makes code much clearer than writing three separate conditions * out; or * | if (x > 100 or y) ...| * can be convenient to check whether |x| is bigger than the minimum of * 100 or |y|. p.25 (foot of page) replace "...is deferred until \S 3." with "...is deferred until \S 3.4." p.27 Replace But there is always an escape. One drastic solution is to return from the current routine, in which case any loops are forgotten about. Another is to use |jump| (see later on) to run away. But the tidiest solution is to execute the statement |break|, which causes execution to "break out of" the current innermost loop or |switch| statement: it can be read as "finish early". with But there is always an escape. One way is to |return| from the current routine. Another is to |jump| to a label outside the loop (|jump| will be covered in \S 1.13 below). It's neater to use the statement |break|, which causes execution to "break out of" the current innermost loop or |switch| statement: it can be read as "finish early". All these ways out are entirely "safe", and there is no harm in leaving a loop only half-done. p.31 The first line of the examples on accents should read: * print "Les @oeuvres d'@Aesop en fran@ccais, mon @'el@`eve!"; (The previous macaronic version was a sort of unfunny joke) p.31 For "Arvo Part", read "Arvo P@:art", that is, place a double-dot accent over the "a" in "Part". p.34 At the end of 1.14, after the table of printing rules, insert: * Note that |(the)| in lower case does something different from |(The)| * with an upper case T. This is very unusual! (Directive names, * which will turn up in \S 2, variable names and so on are allowed to * use upper case and the case is simply ignored, so that |fRoG| * means the same as |frog|. But statement keywords, like |print| * or |(name)|, have to be in lower case -- except for |(The)|.) and then insert a paragraph break so that the sentence starting "To create a new rule..." is now a paragraph in its own right. p.36 (closing words of section 1) Change "See \S 2 for details." to "See \S 2.5 for details." p.39 In "To recapitulate, Inform provides four kind of array in all:" "kind" should be "kinds". p.39 (just after the |primes| array) "is is a word array" should read "is a word array". p.39 An invisible mistake: ``text buffers'' (in the Frank Booth paragraph) should be index-marked, but in the TeX source it isn't, because of a mistype. p.40 Replace "There are more efficient ways to shuffle the pack." with "The example code shuffles the pack in a simple way, but there are more efficient methods." p.43 Replace * |parse_buffer-->(n*2 - 2)| * with * |parse_buffer-->(n*2 - 1)| p.44 Remove the sentence "The point has already been made that Inform's routines satisfy all the philosophical criteria to be called objects." (Who wrote this pompous drivel?) p.47 In the syntax of the Object directive, exchange and . Thus it should read Object "textual name" Similarly exchange notes 1. and 2. explaining what these are. Thus note 1. should now start "The ..." and note 2. should now start "The ...". (This should correct what Miron Schmidt was kind enough to call "an outright lie".) p.55 Delete "an" from * "one of the four kinds of an object" p.55 At the end of the "For example, |print kestrel.flying_strength| paragraph, add the sentence: (You can see all the messages being sent in a game as it runs with the debugging verb "messages": see \S 30 for details.) p.56 "or |nothing| if it wasn't sent from |Object|" should read "or |nothing| if it wasn't sent from an |Object|". p.62 Change the title of section 3.14 from * "Footnote on common vs. individual objects" * to * "Footnote on common vs. individual properties" p.62 Replace the entire footnote (that is, the whole text of section 3.14, though the title should remain) with the following: The properties used in the sections above are all examples of ``individual properties'', which some objects provide and others do not. There are also ``common properties'' which, because they are inherited from the class |Object|, are provided by every member of |Object|. * An example is |capacity|. The |capacity| can be read for an * ordinary game object (say, a crate) even if it doesn't specify a * |capacity| for itself, and the resulting ``default'' value will * be 100. However, this is only a very weak form of inheritance -- * you can't change the crate's |capacity| value and the condition * |crate provides capacity| evaluates to |false|. The properties defined by the Inform library, such as |capacity|, are all common: mainly because common properties are marginally faster to access and marginally cheaper on memory. * Only 62 are available, of which the library uses up 48. * Individual properties, on the other hand, are practically * unlimited. It is therefore worth declaring a common property only * in those cases where it will be used very often in your program. * You can declare common properties with the directive: |Property| |;| which should be made after the inclusion of "Parser" but before first use of the new name. The class |Object| will now pass on this property, with value 0, to all its members. This so-called ``default value'' can optionally be specified. For example, the library itself makes the declaration |Property capacity 100;| which is why all containers in a game which don't specify any particular |capacity| can hold up to 100 items. p.64 In the paragraph ending "on-line documentation.", add a new final sentence: Note however that a filename can contain spaces if it is written in double-quotes. p.65 Replace "set these switches" (top of page) with: * set these switches; or unset any switch preceded by a tilde |~|. * (For example, |-a~bc| sets |a|, unsets |b| and sets |c|.) p.65 under "|+=|", alter "the filename for a directory" * to "one or more filenames of directories, separated by commas". p.65 Add the following to the end of the first paragraph in section 4.2: (The rules for how Inform interprets |"filename"| vary from machine to machine: run Inform with the |-h1| switch for information.) Note that you can write |Include ">shortname";| to mean "the file called |"shortname"| which is in the same directory that the present file came from". This is convenient if all the files making up the source code of your game are housed together. p.67 In the code example beginning "For example, |Ifndef VN_1601|" and the sentence after it, correct 1601 to 1610 and 6.01 to 6.10. p.69 Add the switches: * |d2 contract double spaces after exclamation and question marks, too| * |g2 traces calls to all functions| * |E2 Macintosh MPW-style error messages| and correct the -g switch entry to * |g traces calls to functions (except those in the library)| p.70 The reference to \S 4.5 in the entry under the |M| switch should be to \S 4.3. p.73 "If this limit is passed, the error" should read "If this limit is passed, Inform generates the error". p.74 In "one syntax mistake threw Inform off the right track, so that continued not to know" insert "it" between "that" and "continued". p.77 Delete one of the two identical "'Ifnot' without..." lines listed just under "8. Conditional compilation". p.77 Delete one of the two dollar signs $ in the code line Iftrue #strings_offset==$$4a50; p.77 Delete one of the two "must"s in the third line under "9. Miscellaneous". p.80 Replace: * For instance, ordinarily ``take'', ``get'', ``carry'' and * ``hold'' are one single Inform verb, but this directive * could split off ``carry'' and ``get'' from the other two. * The warning would arise if one tried to split off ``take'' * and ``drop'' together, which come from different original * Inform verbs. with: * For instance, ordinarily ``examine'', ``watch'', ``check'' and * ``describe'' are one single Inform verb, but this directive * could split off ``examine'' and ``watch'' from the other two. * The warning would arise if one tried to split off ``examine'' * and ``search'' together, which come from different original * Inform verbs. p.82 (foot of page) The reference to \S 4 should be to \S 4.3. p.89 "the idea is clear enought" should read "the idea is clear enough". p.93 ThrowAt occurs twice in the list of group 3 actions. * Delete the first occurrence. p.98 After the sunlight object code example, add the sentence: (The |^| symbol in |"sun^s"| means an apostrophe, so the word is "sun's".) section 14 Add a new second and third paragraph: * If the player gets into a |container| and then closes it, the * effect is like being in a different location. (Unless the container * has the |transparent| attribute and is therefore see-through.) * The interior may be dark, but if there's light to see by, the * player will want to see some kind of room description. In any case, * many enterable objects ought to look different from inside or on * top. Inside a vehicle, a player might be able to see a steering * wheel and a dashboard, for instance. On top of a cupboard, it * might be possible to see through a skylight window. * For this purpose, any |enterable| object can provide a property * called |inside_description|, which can be a string or a routine * to print one, as usual. If the exterior location is still * visible, then the "inside description" is added to the * normal room description, and otherwise it becomes that * description. As an extreme example, suppose that the player * gets into a huge cupboard, closes the door behind her and * then gets into a plastic cabinet inside that. The resulting * room description might read like so: * * _The huge cupboard_ (in the plastic cabinet) * It's a snug little cupboard in here, almost a room in itself. * * In the huge cupboard you can see a pile of clothes. * * The plastic walls of the cabinet distort the view. * * The second line is the |inside_description| for the huge * cupboard, and the fourth is that for the plastic cabinet. p.116 "...overlap much more with Chapter ***" should read "...overlap much more with Chapter V". p.118 (in References) Delete the bulleted sentence beginning "|orders| and |grammar| are newly introduced..." section 17 The definitions for light are slightly altered and now read: * An object `offers light' if: * it itself has the |light| attribute set, or * any of its immediate possessions `have light', or * it is see-through and its parent offers light; * while an object `has light' if: * it currently has the |light| attribute set, or * it is see-through and one of its immediate possessions * has light, or * any of the things it ``adds to scope'' (see Chapter V) have light. p.122 Top line: replace the word "alternatively" with "also". Delete the entire next sentence: "Alternatively because an object can't have both a |timer| and a |daemon| going at the same time." p.122 Replace 'Each turn' is entirely separate from daemons and timers. Although an object can't have both a timer and a daemon at the same time, it can have an |each_turn| at the same time, and this is quite useful, especially to run creatures. with 'Each turn' is especially useful to run creatures which stay in one room and are only active when the player is nearby. p.132 (second triangle-marked paragraph) "because haven't got default values" should be "because they haven't got default values". p.134 (references to section 22) * Delete the reference to "pluralobj.h" (it's now incorporated * into the library). p.133 (top of page) The reference to \S A8, in the paragraph beginning "The |Jump| action...", should to be \S A9. p.136 Replace the paragraph: The indefinite article for an object is held in the property |article| and is assumed to be `a' if none is declared. That means that if the short name starts with a vowel, you need to set it to `an'. But article offers much more amusement: with: Inform tries to work out the right indefinite article for any object automatically. In English-language games, it uses `an' when the short name starts with a vowel and `a' when it does not (unless the name is plural, when `some' is used in either case). You can override this by setting |article| yourself. Here are some possibilities: p.136 Delete the words: , in case, let us say, "a pregnant mouse" has to change to "some mice" p.136 After the articles discussion, and just before the paragraph beginning "The short name of an object...", add two new paragraphs. First an ordinary one in running text: A single object whose name is plural, such as "grapes" or "marble pillars", should be given the attribute |pluralname|. As a result the library might say, e.g., "You can't open those" instead of "You can't open that". It also affects the pronoun "them" and makes the usual indefinite article "some". Second, immediately following, a new triangle-marked paragraph: You can give |animate| objects the attributes |male|, |female| or |neuter| to help the parser understand pronouns properly. |animate| objects are assumed to be male if you set neither alternative. p.139 (in the numbered small print, mid-page, point 3) delete the second "then" (there are two "then"s in a row, one bold-face, the other Roman). p.139 (paragraph before Exercise 51) Reference to \S A9 should be to \S A7. p.143 The word "catachrestic" is correctly spelt in the text, but incorrectly spelt "catchrestic" in the index mark. p.144 After the sentence "Remember that the dictionary only has 9-character resolution." add "(And only 6 if Inform has been told to compile an early-model story file: see \S 31.)" p.146 (start of exercise 63) "There is no problem with a calling" should read "There is no problem with calling" p.148 Replace the sentence The simplest way to do this is just to put "crowns" in their |name| lists, and this works perfectly well most of the time. with: Putting the word |"crowns"| in their |name| lists is not quite right, because the parser will still think that ``crowns'' might refer to a specific item. Instead, put in the word |"crowns//p"|. The |//p| marks out the dictionary word "crowns" as one that can refer to more than one game object at once. (So that you shouldn't set this for the word "grapes" if a bunch of * grapes was a single game object; you should give that object * the |pluralname| attribute instead.) For example the |GoldCoin| class would read: |Class GoldCoin with name "gold" "coin" "coins//p", short_name "gold coin", plural "gold coins";| and now when the player types ``take coins'', the parser interprets this as ``take all the coins within reach''. p.148 In the immediately following double-triangle paragraph, replace the opening sentence and next eight words: But it isn't ideal, because ... available crowns. So the complicated (but better) way is to with: The only snag is that now the word |"coins"| is marked as |//p| everywhere in the game, in all circumstances. Here is * a more complicated way to achieve the same result, but * strictly in the context of these objects alone. We need to p.149 Change the list of equal verbs from "take" = "get" = "carry" = "hold" to "take" = "carry" = "hold" p.151 At the very top of the page, i.e. after the sample grammar at the foot of p.150 and before the words "Each line of grammar" insert the sentence: (You can look at the grammar being used in a game with the debugging verb "showverb": see \S 30 for details.) p.151 In the double-triangle section, replace the opening sentence: "As mentioned above, the parser thinks "take" and "get" are exactly the same." with: Since this book was first written, the library has been improved so that "take" and "get" each have their own independent grammars. But for the sake of example, suppose they share the grammar written out above. p.151 After the paragraph in which XyzzySub is written out, add a new single-triangle paragraph: Finally, the line can end with the word |reverse|. This is only useful if there are objects and numbers in the line are parsed in the wrong order. An example from the library's grammar: |Verb "show" "present" "display" * creature held -> Show reverse * held "to" creature -> Show;| The point is that the |Show| action expects the first parameter to be an item, and the second to be a person. When the text ``show him the shield'' is typed in, the parser must reverse the two parameters ``him'' and ``the shield'' before causing a |Show| action. On the other hand, in ``show the shield to him'' the parameters are in the right order already. p.153 (foot of page) After the first paragraph on prepositions, and before the triangle-marked second paragraph, insert the (ordinary) paragraph: It often happens that several prepositions really mean the same thing for a given verb: "in", "into" and "inside" are often equally sensible. As a convenient shorthand you can write a series of prepositions with slash marks |/| in between, to mean "one of these words". For example: | * noun "in"/"into"/"inside" noun -> Insert| (Note that |/| can only be used with prepositions.) p.154 Add a new token to the table, just before [special]: [topic] any text at all p.157 Add a new paragraph just before the one explaining [special]: [topic] This token matches as much text as possible. It should either be at the end of its grammar line, or be followed by a preposition. (The only way it can fail to match is if it finds no text at all.) The library's grammar uses this token for topics of conversation and topics looked up in books (see \S\S 15, 16), hence the name. The parser ignores the text for now (your own code will have to think about it later), and simply sets the variables |consult_from| to the first word of the matched text and |consult_words| to the number of words. p.159 (final words of section 27) "see the specification of the |NounDomain| library routine in \S A9." Reference should be to \S A7. after the "megalook" exercise and before "The rest of this section...": insert the passage * Formally, scope determines what you can talk about, which usually * means what you can see. But what can you touch? Suppose a locked * chest is inside a sealed glass cabinet. The Inform parser will * allow the command ``unlock chest with key'' and generate the * appropriate action, |Unlock chest key|, because the chest is in * scope, so the command at least makes sense. * But it's impossible to carry out, because the player can't reach * through the solid glass. So the library's routine for handling the * |Unlock| action needs to enforce this. The library does this * using a stricter rule called ``touchability''. The rule is that * you can touch anything in scope unless there's a closed container * between you and it. This applies either if you're in the container, * or if it is. * Some purely visual actions don't require touchability -- |Examine| * or |LookUnder|, for instance. But most actions are tactile, and * so will many actions created by designers. If you want to make * your own action routines enforce touchability, you can call the * library routine |ObjectIsUntouchable(obj)|. This either returns * |false| if there's no problem in touching |obj|, or returns |true| * and prints a suitable message (such as ``The solid glass cabinet * is in the way.''). Thus, the first line of many of the library's * action routines is: * * if (ObjectIsUntouchable(noun)) return; * * You can also call |ObjectIsUntouchable(obj, true)| to simply return * true or false, and print nothing, if you'd rather provide your * own failure message. p.162 "it should execute |InScope| and |ScopeWithin|" should read "it should execute |PlaceInScope| and |ScopeWithin|". p.164 Replace apply to all three pronouns ("it", "him" and "her") with apply to all pronouns (in English, "it", "him", "her" and "them") * Replace the bracketed clause in the next sentence, * * ('it', 'him' or 'her') * * with * * ('it', 'him', etc.) Delete the sentence: Note that the variables |itobj|, |himobj| and |herobj| hold the current settings of the pronouns. And add a new (normal) paragraph immediately after this point: You can find out the current setting of a pronoun using the library's |PronounValue| routine: for instance, |PronounValue('it')| would give the object which "it" currently refers to (possibly |nothing|). Similarly |SetPronoun('it', magic_ruby)| would set "it" to mean the magic ruby object. (When something like a magic ruby suddenly appears in the middle of a turn, players will habitually call it "it".) A better way to adjust the pronouns is to call |PronounNotice(magic_ruby)|, which sets whatever pronouns are appropriate. That is, it works out if the object is a thing or a person, of what number and gender, which pronouns apply to it in the parser's current language, and so on. In code predating Inform 6.1 you may see variables called |itobj|, |himobj| and |herobj| holding the English pronoun values: these still work properly, but please use the modern system in new games. p.164 Replace 0 means the parser is intending not to include it, 1 means it intends not to. with 0 means the parser has decided against, 1 means it has decided in favour. In numbered lines 1 and 2 immediately following, replace "it" with "the object". p.165 (Yes, It's Infocom Nostalgia Pedantry Time!) Replace "and the original Infocom parser" with "and the parsers in most of the Infocom games". p.166 Opening line: for "Sorceror" read "Sorcerer". p.166 Replace the sentence beginning "Inform provides a small suite..." up to "...including the library files." with: Inform provides a small suite of debugging verbs, which will be added to any game compiled with the |-D| switch. If you prefer, you can include them manually by writing |Constant DEBUG;| somewhere in the program before the library files are included. p.166 Three additional lines for the table of debugging verbs. Add to the top of the list: |showobj | Insert after the "scope" line: |showverb | Insert after the "routines" line: |messages messages on messages off| p.167 Corresponding changes in the big paragraph describing these verbs. Insert a new first sentence: "showobj" is very informative about the current state of an object. After the "scope" sentence, add: "showverb" will display the grammar being used when the given verb is parsed. Before the "timers" sentence, add: It also describes all messages sent in the game, which is why it can also be written as "messages". p.167 Replace the two short paragraphs about Infix with the latest prevarication: * A source-level debugger for Inform, called Infix, * has been planned for some years, and may possibly be coming * to fruition soon. * (danger) For the benefit of such tools, Inform (if compiling * with the |-k| option set) produces a file of "debugging * information" (cross-references of the game file with the * source code), and anyone interested in writing an Inform * utility program may want to know the format of this file: * see the _Technical Manual_ for details. p.167 In the next paragraph replace "Zip is better here and" with "A Standard interpreter" p.168 References: delete the reference to David Wagner's "showobj". p.169 In the table of maximum sizes of games in different versions, the entry for V6 should read 512, not 576. (Not a typo but a reconsideration.) p.170 (passage on memory management) "restrictions" should read "restriction". p.170 (limit for function calls) Alter "(Or, in V3, at most 3.)" to "(Or, in V3 and V4, at most 3.)". p.170 (passage on Abbreviate) Replace "A good list of abbreviations can be found in the _Technical Manual_: basically," with "When choosing abbreviations,". Insert a new sentence to follow that one: Good choices include |" the "|, |"The"|, |", "|, |"and"|, |"you"|, |" a "|, |"ing"|, |" to"|. p.171 Delete the initial WARNING. (Support for V3 games is gradually being withdrawn, and this warning only puts people needlessly off.) p.174 (top) Delete the sentence "The author recommends that anyone using exotic assembly-language... on both." Replace the next sentence, "All three common interpreters are, in fact, pretty reliable." with: * Interpreters conforming to the Z-Machine Standard, usually * but not always derived from Frotz or Zip, are reliable and * widely available. p.175 (passage on buffer_mode) "This turns on (|flag=1|) or off (|flag=1|)...": the second time should be |flag=0|. p.177 For "Torbj@/orn Andersson", read "Torbj@:orn Andersson", * that is, replace the slash on the second "o" with a * diaresis (double-dot) accent. p.177 Replace the WARNING with the following: WARNING: Some of these features may not work well on obsolete interpreters which do not adhere to the Z-Machine Standard. Standard interpreters are widely available, but if seriously worried you can test whether your game is running on a good interpreter: |if (standard_interpreter == 0)| |{ print "This game must be played on an interpreter obeying the| | Z-Machine Standard.^";| | @quit;| |}| p.179 Table of operator precedences: in the line for level 11, on function calls, replace the text function call with function call on right hand side and add a new bottom line: 14 (...) binary left function call on left hand side p.183 In the syntax explanation: replace the 6 (the maximum number of tokens per line) with 31. At the end of the syntax paragraph insert the following new paragraph: A grammar line can optionally be followed by the word |reverse|. This signals that the action to be generated has two parameters, but which have been parsed in the wrong order and need to swapped over. (Note that a |topic| is not a parameter, and nor is a preposition.) p.183 Add a new token to the summary table, just before [special]: [topic] any text at all p.183 Add a new paragraph immediately after the summary table: Two or more literal words (only) can be written with slash signs |/| between them as alternatives. E.g., |"in"/"on"| matches either the word "in" or the word "on". p.185 Entry for the attribute |female|: replace with the following: This object has a feminine name. In games written in English, this makes her a female person, though in other languages it might be inanimate. The parser uses this information when considering pronouns like "her". (In English, anything |animate| is assumed to be male unless |female| or |neuter| is set.) Insert the following similar entry for new attribute |male|: This object has a masculine name. In games written in English, this makes him a male person, though in other languages it might be inanimate. The parser uses this information when considering pronouns like "him". (In English, anything |animate| is assumed to be male unless |female| or |neuter| is set.) And then for the new attribute |neuter|: This object's name is neither masculine nor feminine. (In English, anything without |animate| is assumed neuter, because only people and higher animals have gender. Anything |animate| is assumed male unless |female| or |neuter| is set. A robot, for instance, might be an |animate| object worth making |neuter|.) p.185 Insert the following entry for new attribute |pluralname|: This single object's name is in the plural. For instance, an object called "seedless grapes" should have |pluralname| set. The library will then use the pronoun "them" and the indefinite article "some" automatically. p.186 Insert a new property entry: articles Array of strings For objects: If given, these are the articles used with the object's name. (Provided for non-English languages where irregular nouns may have unusual vowel-contraction rules with articles: e.g. with French non-mute H.) p.187 Under |daemon|: remove the warning line "The same object cannot..." another new property entry: * inside_description String or routine * For objects: Printed as part or all of a room description * when the player is inside the given object, which must be * |enterable|. p.190 Insert a new property entry: short_name_indef Routine For objects: If set, this form of the short name is used when the name is prefaced by an indefinite article. (This is not useful in English-language games, but in other languages adjectival parts of names agree with the definiteness of the article.) p.190 Under |time_out|: remove the warning line "The same object cannot..." p.191 Add two new objects to the end of the list of special objects defined by the library: InformLibrary Represents the library. You never need to use it, but it might sometimes be the value of |sender| when a message is received. InformParser Represents the parser. list of library routines: add * |ObjectIsUntouchable(obj,flag)| * Determines whether any solid barrier (that is, any |container| that * is not |open|) lies between the player and |obj|. If |flag| is set, * this routine never prints anything; otherwise it prints a message * like ``You can't, because ... is in the way.'' if any barrier is * found. Returns |true| if a barrier is found, |false| if not. p.200 (in rule 5) "Properties, attributes and classes must..." should read "Attributes and classes must...". p.202 Lexicon definition of "common property": replace the first sentence with: Any _property_ set by the _class_ |Object| is passed on to every _object_, and is called a ``common property'': for example, |description|. All others are _individual properties_. New properties can be declared as common with the |Property| directive. and delete the final bracketed sentence about the library's properties, which doesn't belong in a definition. Part II -- Alterations to exercise solutions ================================= In each case the full revised text of the solution is given. Some are hardly altered but others are expanded (e.g. exercise 35) or simplified (exercise 54). However, the prefix #r$ has been deleted in the few cases when they occur without giving details (see exercises 79, 80). This matters too little to fuss over. Exercise 4: ---------- Put any validation rules desired into the |GamePreRoutine|. For example, the following will filter out any stray |Drop| actions for unheld objects: [ GamePreRoutine; if (action==Drop && noun notin player) "You aren't holding ", (the) noun, "."; rfalse; ]; ---------- Exercise 9: ---------- Object -> bag "toothed bag" with name "toothed" "bag", description "A capacious bag with a toothed mouth.", before [; LetGo: "The bag defiantly bites itself shut on your hand until you desist."; Close: "The bag resists all attempts to close it."; ], after [; Receive: "The bag wriggles hideously as it swallows ", (the) noun, "."; ], has container open; ---------- Exercise 14: ---------- Object -> cage "iron cage" with name "iron" "cage" "bars" "barred" "iron-barred", when_open "An iron-barred cage, large enough to stoop over inside, looms ominously here.", when_closed "The iron cage is closed.", inside_description "You stare out through the bars.", has enterable container openable open transparent static; ---------- Exercise 17: ---------- Object -> bible "black Tyndale Bible" with name "bible" "black" "book", initial "A black Bible rests on a spread-eagle lectern.", description "A splendid foot-high Bible, which must have survived the burnings of 1520.", before [ w x; Consult: wn = consult_from; w = NextWord(); switch(w) { 'matthew': x="Gospel of St Matthew"; 'mark': x="Gospel of St Mark"; 'luke': x="Gospel of St Luke"; 'john': x="Gospel of St John"; default: "There are only the four Gospels."; } if (consult_words==1) "You read the ", (string) x, " right through."; w = TryNumber(wn); if (w==-1000) "I was expecting a chapter number in the ", (string) x, "."; "Chapter ", (number) w, " of the ", (string) x, " is too sacred for you to understand now."; ]; ---------- Exercise 19: ---------- Add the following lines, after the inclusion of |Grammar|: [ SayInsteadSub; "[To talk to someone, please type ~someone, something~ or else ~ask someone about something~.]"; ]; Extend "answer" replace * topic -> SayInstead; Extend "tell" replace * topic -> SayInstead; A slight snag is that this will throw out ``nigel, tell me about the grunfeld defence'' (which the library will normally convert to an |Ask| action, but can't if the grammar for ``tell'' is missing). To avoid this, you could (instead of making the above directives) |Replace| the |TellSub| routine (see \S 21) by the |SayInsteadSub| one. ---------- Exercise 21: ---------- Object -> Charlotte "Charlotte" with name "charlotte" "charlie" "chas", grammar [; give self ~general; wn=verb_wordnum; if (NextWord()=='simon' && NextWord()=='says') { give self general; verb_wordnum=verb_wordnum+2; } ], orders [ i; if (self hasnt general) "Charlotte sticks her tongue out."; WaveHands: "Charlotte waves energetically."; default: "~Don't know how,~ says Charlotte."; ], initial "Charlotte wants to play Simon Says.", has animate female proper; (The variable |i| isn't needed yet, but will be used by the code added in the answer to the next exercise.) ---------- Exercise 27: ---------- Object replicator "replicator" with name "replicator", grammar [; return 'rc,'; ], orders [; Give: if (noun in self) "The replicator serves up a cup of ", (name) noun, " which you drink eagerly."; "~That is not something I can replicate.~"; default: "The replicator is unable to oblige."; ], life [; Ask, Answer, Tell: "The replicator has no conversation skill."; ], has talkable; Object -> "Earl Grey tea" with name "earl" "grey" "tea"; Object -> "Aldebaran brandy" with name "aldebaran" "brandy"; Object -> "distilled water" with name "distilled" "water"; ... Verb "rc," * held -> Give; The point to note here is that the [held] token means `held by the replicator' here, as the |actor| is the replicator, so this is a neat way of getting a `one of the following phrases' token into the grammar. ---------- Exercise 28: ---------- This is similar to the previous exercises. One creates an attribute called |crewmember| and gives it to the crew objects: the |orders| property is orders [; Examine: if (parent(noun)==0) "~", (name) noun, " is no longer aboard this demonstration game.~"; "~", (name) noun, " is in ", (name) parent(noun), ".~"; default: "The computer's only really good for locating the crew."; ], and the |grammar| simply returns |'stc,'| which is defined as [ Crew i; switch(scope_stage) { 1: rfalse; 2: objectloop (i has crewmember) PlaceInScope(i); rtrue; } ]; Verb "stc," * "where" "is" scope=Crew -> Examine; An interesting point is that the scope routine doesn't need to do anything at stage 3 (usually used for printing out errors) because the normal error-message printing system is never reached. Something like ``computer, where is Comminder Doto'' causes a |##NotUnderstood| order. ---------- Exercise 29: ---------- Object Zen "Zen" Flight_Deck with name "zen" "flight" "computer", initial "Square lights flicker unpredictably across a hexagonal fascia on one wall, indicating that Zen is on-line.", grammar [; return 'zen,'; ], orders [; Show: "The main screen shows a starfield, turning through ", noun, " degrees."; Go: "~Confirmed.~ The ship turns to a new bearing."; SetTo: if (noun==0) "~Confirmed.~ The ship comes to a stop."; if (noun>12) print_ret "~Standard by ", (number) noun, " exceeds design tolerances.~"; print_ret "~Confirmed.~ The ship's engines step to standard by ", (number) noun, "."; Take: if (noun~=force_wall) "~Please clarify.~"; "~Force wall raised.~"; Drop: if (noun~=blasters) "~Please clarify.~"; "~Battle-computers on line. Neutron blasters cleared for firing.~"; default: "~Language banks unable to decode.~"; ], has talkable proper static; Object -> force_wall "force wall" with name "force" "wall" "shields"; Object -> blasters "neutron blasters" with name "neutron" "blasters"; ... Verb "zen," * "scan" number "orbital" -> Show * "set" "course" "for" Planet -> Go * "speed" "standard" "by" number -> SetTo * "raise" held -> Take * "clear" held "for" "firing" -> Drop; Dealing with |Ask|, |Answer| and |Tell| are left to the reader. ---------- Exercise 33: ---------- We could solve this using a daemon, but for the sake of demonstrating a feature of |thedark| we won't. In |Initialise|, write |thedark.initial = GoMothGo;| and add the routine: [ GoMothGo; if (moth in player) { remove moth; "As your eyes try to adjust, you feel a ticklish sensation and hear a tiny fluttering sound."; } ]; ---------- Exercise 34: ---------- This is a crude implementation, for brevity (the real Zork thief has an enormous stock of attached messages). A |life| routine is omitted, and of course this particular thief steals nothing. See `The Thief' for a much fuller, annotated implementation. \beginlines Object -> thief "thief" with name "thief" "gentleman" "mahu" "modo", each_turn "^The thief growls menacingly.", daemon [ i p j n k; if (random(3)~=1) rfalse; p=parent(thief); objectloop (i in compass) { j=p.(i.door_dir); if (j ofclass Object && j hasnt door) n++; } if (n==0) rfalse; k=random(n); n=0; objectloop (i in compass) { j=p.(i.door_dir); if (j ofclass Object && j hasnt door) n++; if (n==k) { move self to j; if (p==location) "^The thief stalks away!"; if (j==location) "^The thief stalks in!"; rfalse; } } ], has animate; \endlines (Not forgetting to |StartDaemon(thief)| at some point, for instance in the game's |Initialise| routine.) So the thief walks at random but never via doors, bridges and the like (because these may be locked or have rules attached); it's only a first approximation, and in a good game one should occasionally see the thief do something surprising, such as open a secret door. As for the |name|, note that `The Prince of darkness is a gentleman. Modo he's called, and Mahu' (William Shakespeare, _King Lear_ III iv.) ---------- Exercise 35: ---------- We shall use a new property called |weight| and decide that any object which doesn't provide any particular weight will weigh 10 units. Clearly, an object which contains other objects will carry their weight too, so: [ WeightOf obj t i; if (obj provides weight) t = obj.weight; else t = 10; objectloop (i in obj) t = t + WeightOf(i); return t; ]; Once every turn we shall check how much the player is carrying and adjust a measure of the player's fatigue accordingly. There are many ways we could choose to calculate this: for the sake of example we'll define two constants: Constant CARRYING_STRENGTH = 500; Constant HEAVINESS_THRESHOLD = 100; Initially the player's strength will be the maximum possible, which we'll set to 500. Each turn the amount of weight being carried is substracted from this, but 100 is also added on (without exceeding the maximum value). So if the player carries more than 100 units, then her strength declines, but by dropping things to get the weight below 100 she can allow it to recover. If she drops absolutely everything, her entire strength will recuperate in at most 5 turns. Exhaustion sets in if her strength reaches 0, and at this point she is forced to drop something, which gives her strength a slight boost. Anyway, here's an implementation of all this: Object weight_monitor with players_strength, warning_level 5, activate [; self.players_strength = CARRYING_STRENGTH; StartDaemon(self); ], daemon [ w s b bw; if (location ~= Weights_Room) { StopDaemon(self); return; } s = self.players_strength - WeightOf(player) + HEAVINESS_THRESHOLD; if (s<0) s=0; if (s>CARRYING_STRENGTH) s=CARRYING_STRENGTH; self.players_strength = s; if (s==0) { bw=-1; objectloop(b in player) if (WeightOf(b) > bw) { bw = WeightOf(b); w=b; } self.players_strength = self.players_strength + bw; print "^Exhausted with carrying so much, you decide to discard ", (the) w, ": "; <>; } w=s/100; if (w==self.warning_level) return; self.warning_level = w; switch(w) { 3: "^You are feeling a little tired."; 2: "^You possessions are weighing you down."; 1: "^Carrying so much weight is wearing you out."; 0: "^You're nearly exhausted enough to drop everything at an inconvenient moment."; } ]; Notice that items are actually dropped with |Drop| actions: one of them might be, say, a wild boar, which would bolt away into the forest when released. The daemon tries to drop the heaviest item. (Obviously a little improvement would be needed if the game contained, say, an un-droppable but very heavy ball and chain.) Finally, of course, at some point the weight monitor has to be sent an |activate| message to get things going. ---------- Exercise 44: ---------- The common man's _wayhel_ was a lowly mouse. Since we think much more highly of the player: Object hog "Warthog" Caldera with name "wart" "hog" "warthog", description "Muddy and grunting.", number 0, initial "A warthog snuffles and grunts about in the ash.", orders [; Go, Look, Examine, Eat, Smell, Taste, Touch: rfalse; default: "Warthogs can't do anything as tricky as that!"; ], has animate proper; and we just |ChangePlayer(warthog);|. Note that the same |orders| routine applies to the player-as-human typing "warthog, listen" as to the player-as-warthog typing just "listen". ---------- Exercise 48: ---------- See the _Inform Translator's Manual_. One must provide a new grammar file (generating the same actions but from different syntax), tables showing how pronouns, possessives and articles work in the new language, a sheaf of translated library messages and so on. But it can be done. ---------- Exercise 54: ---------- Class Coin with name "coin" "coins//p", description "A round unstamped disc, presumably local currency.", list_together "coins", plural [; print (string) (self.&name)-->0; if (~~(listing_together ofclass Coin)) print " coins"; ], short_name [; if (listing_together ofclass Coin) { print (string) (self.&name)-->0; rtrue; } ], article [; if (listing_together ofclass Coin) print "one"; else print "a"; ]; Class Gold_coin class Coin with name "gold"; Class Silver_coin class Coin with name "silver"; Class Bronze_coin class Coin with name "bronze"; SilverCoin -> "silver coin"; ... and so on ---------- Exercise 55: ---------- Firstly, a printing rule to print the state of coins. Coin-objects will have a property called |way_up| which is always either 1 or 2: [ Face x; if (x.way_up==1) print "Heads"; else print "Tails"; ]; There are two kinds of coin but we'll implement them with three classes: |Coin| and two sub-categories, |GoldCoin| and |SilverCoin|. Since the coins only join up into trigrams when present in groups of three, we need a routine to detect this: [ CoinsTogether cla i x y; objectloop (i ofclass cla) { x=parent(i); if (y==0) y=x; else { if (x~=y) return 0; } } return y; ]; Thus |CoinsTogether(cla)| decides whether all objects of class |cla| are in the same place. (|cla| will always be either |GoldCoin| or |SilverCoin|.) We must now write the class definitions: Class Coin with name "coin" "coins//p", way_up 1, article "the", after [; Drop, PutOn: self.way_up = random(2); print (Face) self; if (CoinsTogether(self.which_class)) { print ". The "; if (self.which_class == GoldCoin) print "gold"; else print "silver"; " trigram is now ", (Trigram) self.which_class; } "."; ]; [ CoinLT k i c; if (inventory_stage==1) { if (self.which_class == GoldCoin) print "the gold"; else print "the silver"; print " coins "; k=CoinsTogether(self.which_class); if (k==location || k has supporter) { objectloop (i ofclass self.which_class) { print (name) i; switch(++c) { 1: print ", "; 2: print " and "; 3: print " (showing the trigram ", (Trigram) self.which_class, ")"; } } rtrue; } if (~~(c_style & ENGLISH_BIT)) c_style = c_style + ENGLISH_BIT; if (~~(c_style & NOARTICLE_BIT)) c_style = c_style + NOARTICLE_BIT; if (c_style & NEWLINE_BIT) c_style = c_style - NEWLINE_BIT; if (c_style & INDENT_BIT) c_style = c_style - INDENT_BIT; } rfalse; ]; Class GoldCoin class Coin with name "gold", which_class GoldCoin, list_together [; return CoinLT(); ]; Class SilverCoin class Coin with name "silver", which_class SilverCoin, list_together [; return CoinLT(); ]; (There are two unusual points here. Firstly, the |CoinsLT| routine is not simply given as the common |list_together| value in the |coin| class since, if it were, all six coins would be grouped together: we want two groups of three, so the gold and silver coins have to have different |list_together| values. Secondly, if a trigram is together and on the floor, it is not good enough to simply append text like "showing Tails, Heads, Heads (change)" at |inventory_stage| 2 since the coins may be listed in a funny order: for example, in the order snake, robin, bison. In that event, the order the coins are listed in doesn't correspond to the order their values are listed in, which is misleading. So instead |CoinsLT| takes over entirely at |inventory_stage| 1 and prints out the list of three itself, returning true to stop the list from being printed out by the library as well.) To resume: whenever coins are listed together, they are grouped into gold and silver. Whenever trigrams are visible they are to be described by either |Trigram(GoldClass)| or |Trigram(SilverClass)|: Array gold_trigrams --> "fortune" "change" "river flowing" "chance" "immutability" "six stones in a circle" "grace" "divine assistance"; Array silver_trigrams --> "happiness" "sadness" "ambition" "grief" "glory" "charm" "sweetness of nature" "the countenance of the Hooded Man"; [ Trigram cla i k state; objectloop (i ofclass cla) { print (Face) i; if (k++<2) print ","; print " "; state=state*2 + (i.way_up-1); } if (cla == GoldCoin) i=gold_trigrams; else i=silver_trigrams; print "(", (string) i-->state, ")"; ]; (These interpretations of the coins are quite bogus.) Finally we have to make the six actual coins: GoldCoin -> "goat" with name "goat"; GoldCoin -> "deer" with name "deer"; GoldCoin -> "chicken" with name "chicken"; SilverCoin -> "robin" with name "robin"; SilverCoin -> "snake" with name "snake"; SilverCoin -> "bison" with name "bison"; ---------- Exercise 57: ---------- Object -> "/?%?/ (the artiste formally known as Princess)" with name "princess" "artiste" "formally" "known" "as", short_name [; if (self hasnt general) { print "Princess"; rtrue; } ], react_before [; Listen: print_ret (name) self, " sings a soft siren song."; ], initial [; print_ret (name) self, " is singing softly."; ], parse_name [ x n; if (self hasnt general) { if (NextWord()=='princess') return 1; return 0; } x=WordAddress(wn); if ( x->0 == '/' && x->1 == '?' && x->2 == '%' && x->3 == '?' && x->4 == '/') { while (wn<=parse->1 && WordAddress(wn++)0 == '#') return 1; return -1; ---------- Exercise 62: ---------- [ ParseNoun; if (WordLength(wn)==1 && WordAddress(wn)->0 == '#') return 1; if (WordLength(wn)==1 && WordAddress(wn)->0 == '*') { parser_action = ##PluralFound; return 1; } return -1; ]; ---------- Exercise 65: ---------- Because the parser might go on to reject the line it's working on: for instance, if the player typed "shazam splurge" then the message "Shazam!" followed by a parser complaint will be somewhat unedifying. ---------- Exercise 66: ---------- The scheme will work like this: any room that ought to have a name should have a |place_name| property set to a dictionary word; say, the Bedquilt cave could be called |'bedquilt'|. Clearly you should only be allowed to type this from adjacent rooms. So we'll implement the following: you can only move by name to those rooms listed in the current room's |to_places| property. For instance, the Soft Room might have |to_places| set to to_places Bedquilt Slab_Room Twopit_Room; Now the code: if the player's verb is not otherwise understood, we'll check it to see if it's a place name of a nearby room, and if so store that room's object number in |goto_room|, converting the verb to |'go#room'| (which we'll deal with below). Global goto_room; [ UnknownVerb word p i; p = location.&to_places; if (p==0) rfalse; for (i=0:(2*i)i).place_name) { goto_room = p-->i; return 'go#room'; } rfalse; ]; [ PrintVerb word; if (word=='go#room') { print "go to ", (name) goto_room; rtrue; } rfalse; ]; (The supplied |PrintVerb| is icing on the cake: so the parser can say something like "I only understood you as far as wanting to go to Bedquilt." in reply to, say, "bedquilt the nugget".) It remains only to create the dummy verb: [ GoRoomSub; if (goto_room hasnt visited) "But you have never been there."; PlayerTo(goto_room); ]; Verb "go#room" * -> GoRoom; Note that if you don't know the way, you can't go there! A purist might prefer instead to not recognise the name of an unvisited room, back at the |UnknownVerb| stage, to avoid the player being able to deduce names of nearby rooms from this `error message'. ---------- Exercise 71: ---------- Again, the first question is how to store the number dialled: in this case, into a |string| array. The token is: Constant MAX_PHONE_LENGTH = 30; Array dialled_number string MAX_PHONE_LENGTH; [ PhoneNumber f a l ch pp i; pp=1; if (NextWordStopped()==-1) return 0; do { a=WordAddress(wn-1); l=WordLength(wn-1); for (i=0:ii; if (ch<'0' || ch>'9') { if (ch~='-') { f=1; if (i~=0) return -1; } } else { if (pp(pp++)=ch-'0'; } } } until (f==1 || NextWordStopped()==-1); if (pp==1) return -1; dialled_number->0 = pp-1; return 0; ]; To demonstrate this in use, [ DialPhoneSub i; print "You dialled <"; for (i=1:i<=dialled_number->0:i++) print dialled_number->i; ">"; ]; Verb "dial" * PhoneNumber -> DialPhone; ---------- Exercise 81: ---------- A slight refinement of such a "purloin" verb is already defined in the library (if the constant |DEBUG| is defined), so there's no need. But here's how it could be done: [ Anything i; if (scope_stage==1) rfalse; if (scope_stage==2) { objectloop (i ofclass Object) PlaceInScope(i); rtrue; } "No such in game."; ]; (This disallows multiple matches for efficiency reasons -- the parser has enough work to do with such a huge scope definition as it is.) Now the token |scope=Anything| will match anything at all, even things like the abstract concept of `east'. Part III -- Alterations to library messages (section A9) ============================================ The text is altered throughout, so here is an entirely new version of section A9. Answer "There is no reply." Ask "There is no reply." Attack "Violence isn't the answer to this one." Blow "You can't usefully blow that/those." Burn "This dangerous act would achieve little." Buy "Nothing is on sale." Climb "I don't think much is to be achieved by that." Close 1. "That's/They're not something you can close." 2. "That's/They're already closed." 3. "You close ." Consult "You discover nothing of interest in ." Cut "Cutting that/those up would achieve little." Dig "Digging would achieve nothing here." Disrobe 1. "You're not wearing that/those." 2. "You take off ." Drink "There's nothing suitable to drink here." Drop 1. "The is/are already here." 2. "You haven't got that/those." 3. "(first taking off)" 4. "Dropped." Eat 1. "That's/They're plainly inedible." 2. "You eat . Not bad." EmptyT 1. " can't contain things." 2. " is/are closed." " is/are empty already." Enter 1. "But you're already on/in ." 2. "That's/They're not something you can enter." 3. "You can't get into the closed ." 4. "You can only get into something freestanding." 5. "You get onto/into ." Examine 1. "Darkness, noun. An absence of light to see by." 2. "You see nothing special about ." 3. " is/are currently switched on/off." Exit 1. "But you aren't in anything at the moment." 2. "You can't get out of the closed ." 3. "You get off/out of ." Fill "But there's no water here to carry." FullScore 1. "The score is/was made up as follows:|^|" 2. "finding sundry items" 3. "visiting various places" 4. "total (out of |MAX_SCORE|)" GetOff "But you aren't on at the moment." Give 1. "You aren't holding ." 2. "You juggle for a while, but don't achieve much." 3. " doesn't/don't seem interested." Go 1. "You'll have to get off/out of first." 2. "You can't go that way." 3. "You are unable to climb ." 4. "You are unable to descend ." 5. "You can't, since is/are in the way." 6. "You can't, since leads nowhere." Insert 1. "You need to be holding before you can put it/them into something else." 2. "That/Those can't contain things." 3. " is/are closed." 4. "You'll need to take it/them off first." 5. "You can't put something inside itself." 6. "(first taking it/them off)|^|" 7. "There is no more room in ." 8. "Done." 9. "You put into ." Inv 1. "You are carrying nothing." 2. "You are carrying" Jump "You jump on the spot, fruitlessly." JumpOver "You would achieve nothing by this." Kiss "Keep your mind on the game." Listen "You hear nothing unexpected." LMode1 " is now in its normal ~brief~ printing mode, which gives long descriptions of places never before visited and short descriptions otherwise." LMode2 " is now in its ~verbose~ mode, which always gives long descriptions of locations (even if you've been there before)." LMode3 " is now in its ~superbrief~ mode, which always gives short descriptions of locations (even if you haven't been there before)." Lock 1. "That doesn't/They don't seem to be something you can lock." 2. "That's/They're locked at the moment." 3. "First you'll have to close ." 4. "That doesn't/Those don't seem to fit the lock." 5. "You lock ." Look 1. " (on )" 2. " (in )" 3. " (as )" 4. "|^|On is/are " 5. "[On/In ] you/You can also see [here]." 6. "[On/In ] you/You can see [here]." LookUnder 1. "But it's dark." "You find nothing of interest." Mild "Quite." ListMiscellany 1. " (providing light)" 2. " (which is/are closed)" 3. " (closed and providing light)" 4. " (which is/are empty)" 5. " (empty and providing light)" 6. " (which is/are closed and empty)" 7. " (closed, empty and providing light)" 8. " (providing light and being worn" 9. " (providing light" 10. " (being worn" 11. " (which is/are " 12. "open" 13. "open but empty" 14. "closed" 15. "closed and locked" 16. " and empty" 17. " (which is/are empty)" 18. " containing " 19. " (on " 20. ", on top of " 21. " (in " 22. ", inside " Miscellany 1. "(considering the first sixteen objects only)|^|" 2. "Nothing to do!" 3. " You have died " 4. " You have won " 5. (The RESTART/RESTORE/QUIT and possibly FULL and AMUSING query, printed after the game is over.) 6. "[Your interpreter does not provide undo. Sorry!]" 7. "Undo failed. [Not all interpreters provide it.]" 8. "Please give one of the answers above." 9. "|^|It is now pitch dark in here!" 10. "I beg your pardon?" 11. "[You can't "undo" what hasn't been done!]" 12. "[Can't "undo" twice in succession. Sorry!]" 13. "[Previous turn undone.]" 14. "Sorry, that can't be corrected." 15. "Think nothing of it." 16. ""Oops" can only correct a single word." 17. "It is pitch dark, and you can't see a thing." 18. "yourself" (the short name of the |selfobj| object) 19. "As good-looking as ever." 20. "To repeat a command like "frog, jump", just say "again", not "frog, again"." 21. "You can hardly repeat that." 22. "You can't begin with a comma." 23. "You seem to want to talk to someone, but I can't see whom." 24. "You can't talk to ." 25. "To talk to someone, try "someone, hello" or some such." 26. "(first taking <|not_holding|>)" 27. "I didn't understand that sentence." 28. "I only understood you as far as wanting to " 29. "I didn't understand that number." 30. "You can't see any such thing." 31. "You seem to have said too little!" 32. "You aren't holding that!" 33. "You can't use multiple objects with that verb." 34. "You can only use multiple objects once on a line." 35. "I'm not sure what "" refers to." 36. "You excepted something not included anyway!" 37. "You can only do that to something animate." 38. "That's not a verb I recognise." 39. "That's not something you need to refer to in the course of this game." 40. "You can't see "" () at the moment." 41. "I didn't understand the way that finished." 42. "None/only of those is/are available." 43. "Nothing to do!" 44. "There are none at all available!" 45. "Who do you mean, " 46. "Which do you mean, " 47. "Sorry, you can only have one item here. Which exactly?" 48. "Whom do you want [] to ?" 49. "What do you want [] to ?" 50. "Your score has just gone up/down by point/points." 51. "(Since something dramatic has happened, your list of commands has been cut short.)" 52. "Type a number from 1 to , 0 to redisplay or press ENTER." 53. "[Please press SPACE.]" No see \bf Yes NotifyOff "Score notification off." NotifyOn "Score notification on." Objects 1. "Objects you have handled:|^|" 2. "None." 3. " (worn)" 4. " (held)" 5. " (given away)" 6. " (in )" [without article] 7. " (in )" [with article] 8. " (inside )" 9. " (on )" 10. " (lost)" Open 1. "That's/They're not something you can open." 2. "It seems/They seem to be locked." 3. "That's/They're already open." 4. "You open , revealing " 5. "You open ." Order " has/have better things to do." Places "You have visited: " Pray "Nothing practical results from your prayer." Prompt 1. "|^>|" Pronouns 1. "At the moment, " 2. "means " 3. "is unset " 4. "no pronouns are known to the game." Pull 1. "It is/Those are fixed in place." 2. "You are unable to." 3. "Nothing obvious happens." 4. "That would be less than courteous." Push see \bf Pull PushDir 1. "Is that the best you can think of?" 2. "That's not a direction." 3. "Not that way you can't." PutOn 1. "You need to be holding before you can put it/them on top of something else." 2. "You can't put something on top of itself." 3. "Putting things on would achieve nothing." 4. "You lack the dexterity." 5. "(first taking it/them off)|^|" 6. "There is no more room on ." 7. "Done." 8. "You put on ." Quit 1. "Please answer yes or no." 2. "Are you sure you want to quit? " Remove 1. "It is/They are unfortunately closed." 2. "But it isn't/they aren't there now." 3. "Removed." Restart 1. "Are you sure you want to restart? " 2. "Failed." Restore 1. "Restore failed." 2. "Ok." Rub "You achieve nothing by this." Save 1. "Save failed." 2. "Ok." Score "You have so far/In that game you scored out of a possible |MAX_SCORE|, in turn/turns" ScriptOn 1. "Transcripting is already on." 2. "Start of a transcript of" ScriptOff 1. "Transcripting is already off." 2. "|^|End of transcript." Search 1. "But it's dark." 2. "There is nothing on ." 3. "On is/are ." 4. "You find nothing of interest." 5. "You can't see inside, since is/are closed." 6. " is/are empty." 7. "In is/are ." Set "No, you can't set that/those." SetTo "No, you can't set that/those to anything." Show 1. "You aren't holding ." 2. " is/are unimpressed." Sing "Your singing is abominable." Sleep "You aren't feeling especially drowsy." Smell "You smell nothing unexpected." Sorry "Oh, don't apologise." Squeeze 1. "Keep your hands to yourself." 2. "You achieve nothing by this." Strong "Real adventurers do not use such language." Swim "There's not enough water to swim in." Swing "There's nothing sensible to swing here." SwitchOff 1. "That's/They're not something you can switch." 2. "That's/They're already off." 3. "You switch off." SwitchOn 1. "That's/They're not something you can switch." 2. "That's/They're already on." 3. "You switch on." Take 1. "Taken." 2. "You are always self-possessed." 3. "I don't suppose would care for that." 4. "You'd have to get off/out of first." 5. "You already have that/those." 6. "That seems/Those seem to belong to ." 7. "That seems/Those seem to be a part of ." 8. "That isn't/Those aren't available." 9. " isn't/aren't open." 10. "That's/They're hardly portable." 11. "That's/They're fixed in place." 12. "You're carrying too many things already." 13. "(putting into |SACK_OBJECT| to make room)" Taste "You taste nothing unexpected." Tell 1. "You talk to yourself a while." 2. "This provokes no reaction." Touch 1. "Keep your hands to yourself!" 2. "You feel nothing unexpected." 3. "If you think that'll help." Think "What a good idea." Tie "You would achieve nothing by this." ThrowAt 1. "Futile." 2. "You lack the nerve when it comes to the crucial moment." Turn see \bf Pull Unlock 1. "That doesn't/They don't seem to be something you can unlock." 2. "It's/They're unlocked at the moment." 3. "That doesn't/Those don't seem to fit the lock." 4. "You unlock ." VagueGo "You'll have to say which compass direction to go in." Verify 1. "The game file has verified as intact." 2. "The game file did not verify properly, and may be corrupted (or you may be running it on a very primitive interpreter which is unable properly to perform the test)." Wait "Time passes." Wake "The dreadful truth is, this is not a dream." WakeOther "That seems unnecessary." Wave 1. "But you aren't holding that/those." 2. "You look ridiculous waving ." WaveHands "You wave, feeling foolish." Wear 1. "You can't wear that/those!" 2. "You're not holding that/those!" 3. "You're already wearing that/those!" 4. "You put on ." Yes "That was a rhetorical question."