! --------------------------------------------------------------------- ! StrNames.inf ! Release 1/Serial 070603 ! by Chipjack ! --------------------------------------------------------------------- ! Please report bugs on rec.arts.int-fiction, rather than by email. ! StrNames has been released into the Public Domain; you may use it ! in any way you wish. ! ! Demonstrates the use of StrNames.h, which provides a mechanism to ! assign an array of strings to an object to be used like words in the ! names property. ! --------------------------------------------------------------------- ! Release History ! --------------------------------------------------------------------- ! 2007-06-03 v0.2 (Chipjack): ! Added modified versions of the Featureless Cubes and the Coins ! classes found in the back of the DM4 to provide examples of more ! advanced usages. ! 2007-06-01 v0.1 (Chipjack): ! Initial Version. ! --------------------------------------------------------------------- Constant Story "StrNames"; Constant Headline "^An example of using strings for names.^"; Release 1; Serial "070603"; Constant DIALECT_US; Constant NO_PLACES; Constant DEATH_MENTION_UNDO; Constant NO_SCORE; Include "parser"; Include "verblib"; Include "strnames"; Include "menus"; Attribute legible; Class Coin class LObject with name 'coin', long_names _PLURAL_ "coins", description "A round unstamped disc, presumably local currency.", list_together "coins", plural [; print (address) self.&name-->0; if (~~(listing_together ofclass Coin)) print " coins"; ], short_name [; print (address) self.&name-->0; if (~~(listing_together ofclass Coin)) print " coin"; rtrue; ], article [; if (listing_together ofclass Coin) print "one"; else print "a"; ]; Class GoldCoin class Coin with name 'gold'; Class SilverCoin class Coin with name 'silver'; Class BronzeCoin class Coin with name 'bronze'; Array cube_text_buffer -> 8; Global the_named_word = 0; Global from_char; Global to_char; Class FeaturelessCube class LObject with number 0 0 0 0, ! There's room for 8 bytes of text in these 4 entries description "A perfect white cube, four inches on a side.", long_names "featureless-cube" _PLURAL_ "featureless-cubes", parse_name [ i j flag; if (parser_action == ##TheSame) { ! call LObject parse_name first, to differentiate between objects if( (i = self.LObject::parse_name()) == -2) return i; ! then carry on as needed if it didn't report a difference for (i = 0: i < 8: i++) if ((parser_one.&number)->i ~= (parser_two.&number)->i) return -2; return -1; } for ( : : i++) { j=NextWord(); flag=0; if (j == 'cube' or 'white' || (j == 'featureless' or 'blank' && ((self.&number)->0) == 0)) flag = 1; if (j == 'cubes') { flag = 1; parser_action = ##PluralFound; } ! and now, call LObject's routine for checking the long_names property, if needed if (flag == 0) { flag = self._match_long_names(); ! it returns the number of words matched, and leaves wn where it was to begin with if (flag) i = i + flag; } if (flag == 0 && ((self.&number)->0) ~= 0) { wn--; if (TextReader(0) == 0) return i; for (j = 0: j < 8: j++) if ((self.&number)->j ~= cube_text_buffer->j) return i; flag = 1; } if (flag == 0) return i; } ], article "a", short_name [ i; if (((self.&number)->0) == 0) print "featureless white cube"; else { print "~"; while (((self.&number)->i) ~= 0) print (char) (self.&number)->i++; print "~ cube"; } rtrue; ], plural [; self.short_name(); print "s"; ], baptise [ i; wn = the_named_word; if (TextReader(1) == 0) return i; for (i = 0: i < 8: i++) (self.&number)->i = cube_text_buffer->i; self.article="the"; print_ret "It is now called ", (the) self, "."; ]; ! Copies word "wn" from what the player most recently typed, putting it as ! plain text into cube_text_buffer, returning false if no such word is there [ TextReader flag point i j len; if (flag == 1 && from_char ~= to_char) { for (i = from_char, j = 0: i <= to_char && j < 7: i++) { cube_text_buffer->j = buffer->i; if (buffer->i ~= ' ' or ',' or '.') j++; } for ( : j<8: j++) cube_text_buffer->j = 0; from_char=0; to_char=0; rtrue; } for (i = 0: i < 8: i++) cube_text_buffer->i = 0; if (wn > parse->1) { wn++; rfalse; } i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1); for (i = 0: i < len && i < 7: i++) cube_text_buffer->i = point->i; wn++; rtrue; ]; Object burin "magic burin" with name "magic" "magical" "burin" "pen", description "This is a magical burin, used for inscribing objects with words or runes of magical import. Such a burin also gives you the ability to write spell scrolls.", before [; WriteOn: if (second ofclass FeaturelessCube) { if (second notin player) "Writing on a cube is such a fiddly process that you need to be holding it in your hand first."; if (burin notin player) "You would need some powerful implement for that."; second.baptise(); rtrue; } !if (second ofclass SpellBook) ! "If a burin could write in a spell book, you wouldn't need the gnusto spell!"; !if (second ofclass Scroll) ! "You cannot write just anything on the magic parchment of a scroll: you can only ~copy~ a spell to it."; ]; [ WriteOnSub; "Graffiti is banned."; ]; [ChooseObjects obj code; if(code ==2 && obj ofclass FeaturelessCube) { if(action_to_be == ##WriteOn) { if(obj.&number->0 ~= 0) return 1; if(obj in player) return 3; return 2; } } ]; Object crawlspace "Dingy Crawlspace" has light with description "The musty crawlspace behind the shelves in the decrepit backroom of the Miskatonic University Library's archive annex (none of which is implemented)."; LObject -> book "The Necronomicon" with name 'book' 'volume' 'tome' 'evil' 'sinister' 'looking' 'black', description "The fabled volume, The Necronomicon, supposedly written by the Mad Arab Abdul Alhazred and rumored to be a tome of unspeakable evil.", initial "A sinister-looking black book lies on the floor.", long_names "necronomicon" "sinister-looking" "book of the dead" _PLURAL_ "books of the dead", before [; Read, Search, Consult, Open: deadflag = 3; "Its the Necronomicon, not a Harry Potter novel.^^A mere glance into the vile pages of this eldritch tome and you fall into an abject terror so deep that your mind snaps.^^(Then again, the earlier Harry Potter books can have that effect too.)"; ] has proper legible; GoldCoin ->; GoldCoin ->; GoldCoin ->; SilverCoin ->; SilverCoin ->; BronzeCoin ->; FeaturelessCube ->; FeaturelessCube ->; FeaturelessCube ->; Menu info "Information"; Option -> "About..." with description "This game demonstrates StrNames.h, which allows a property array of strings to act as names for an object.^^Written by Chipjack on June 3, 2007, this code has been released into the public domain.^"; Option -> "What It Does" with description [; print "Most of the words that an Inform game understands are kept in the story file's ", (i) "dictionary", ". Only the first nine letters of the words in the dictionary are stored, sometimes less if you're using accented characters and such, so if you need longer names for things, StrNames.h is for you.^^"; print "To try it out, try calling the Necronomicon various things. Any combination of words in its name property will work, of course. (So 'black book', 'sinister volume', and even 'looking book volume black' all refer to the book.)^^"; print "Strings from the long_name property work too: 'sinister-looking black Necronomicon', for example. They may be mixed in with words from the name property with no trouble.^^"; print "The entire string must match. 'Necronomicon' works, but 'Necronomic' results in ~You can't see any such thing.~ Note that 'Book of the Dead' works, but not 'Book of the'. This time, though, the parser recognizes 'book' as the Necronomicon, but can't make sense of the words that follow it, so it responds with ~I only understood you as far as...~^^"; print "There are also some coins, and a few featureless white cubes -- items with which you might be familiar if you've been poking about in the Inform 6 examples. The coins demonstrate listing and addressing indistinguishable objects, and the featureless white cubes take that a step further, letting you name the objects whatever you wish, thus making them distinguishable.^^"; print "To get a list of the long_names entries for an object, type ~names ", (i) "object", "~ where ", (i) "object", " is whatever object you want to mess with.^^"; ]; Option -> "Using StrNames.h In Your Game" with description [; print "To use StrNames.h, include it somewhere after VerbLib.h. You can then use the LObject class to create objects that support strings for names.^^"; print " LObject myObj^"; print " with name 'my' 'object',^"; print " long_name ~string~ ~another string~^"; print " ;^^"; print "To write your own class that supports strings for names:^^"; print " Class myClass^"; print " class LObject^"; print " with ...^^"; print "The Z-Machine converts the players commands to lower-case, so any string in an object's long_name property ", (b) "must", " be in lower-case to work.^^"; print "If a long_name entry ought to be treated as plural, put the constant _PLURAL_ before it.^^"; print " Class Coin^"; print " class LObject^"; print " with name 'coin',^"; print " long_name _PLURAL_ ~coins~,^"; print " ...^^"; print "The constant _PLURAL_ has no value, and putting a zero (0) there would work just as well, but it wouldn't be as easy to understand later when you're looking at code you wrote months ago.^^"; print "For a more thorough example of how to use StrNames.h and the LObject class, you might like to look over this story file's source code. The featureless white cubes make a nice example of integrating the LObject class with complex parse_name routines of your own. (They respond to the long_names ~featureless-cube~ and ~featureless-cubes~ if you want to play with them a bit.)^^"; ]; [Initialise; location = crawlspace; move burin to player; print "^^You're filthy--wrapped in cobwebs and coated in dust. But, at last, you've found what you are seeking...^^"; Banner(); print "Type ~info~ at any prompt for helpful information.^"; return 2; ]; [ DeathMessage; if (deadflag == 3) print "You've gone insane"; ]; [ReadSub; "That's rather pointless."; ]; [InfoSub; info.select(); ]; [LongNamesSub i; if(noun provides name) { print (The) noun, " answers to the following names:^"; for(i = 0: i < noun.#name / 2: i++) { print (address) noun.&name-->i, "^"; } print "^"; } if(noun ofclass LObject) if(noun provides long_names) { print (The) noun, " answers to the following long_names:^"; for(i = 0: i < noun.#long_names / 2: i++) { if(noun.&long_names-->i == _PLURAL_) print "(plural) "; else print (string) noun.&long_names-->i, "^"; } } else print (The) noun, " hasn't any long_names defined.^"; else print (The) noun, " isn't an LObject.^"; ]; [b text; style bold; print (string) text; style roman; ]; [i text; style underline; print (string) text; style roman; ]; Include "grammar"; [ AnyWord; from_char=0; to_char=0; the_named_word=wn++; return burin; ]; [ QuotedText i j f; i = WordAddress(wn++); i=i-buffer; if (buffer->i=='"') { for (j=i+1:j<=(buffer->1)+1:j++) if (buffer->j=='"') f=j; if (f==0) return -1; from_char = i + 1; to_char = f - 1; if (from_char > to_char) return -1; while (buffer + f > WordAddress(wn)) wn++; wn++; return burin; } return -1; ]; Verb "write" "scribe" * AnyWord "on" held -> WriteOn * QuotedText "on" held -> WriteOn; Extend only 'read' first * legible -> Read; Verb meta 'info' 'help' 'about' 'hint' 'hints' * -> Info; Verb meta 'names' * noun -> LongNames;