diff options
author | Georg Brandl <georg@python.org> | 2014-10-15 08:19:30 +0200 |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2014-10-15 08:19:30 +0200 |
commit | 02d812930d90c3e20a056796d182bf1ce80d24cd (patch) | |
tree | 3842bbaaba57168797a8240fdc4cb5336215403d /tests/examplefiles/tads3_example.t | |
parent | 698f1330db81976de249104496f831055c0bc79d (diff) | |
download | pygments-02d812930d90c3e20a056796d182bf1ce80d24cd.tar.gz |
Rename test file to use the correct lexer.
Diffstat (limited to 'tests/examplefiles/tads3_example.t')
-rw-r--r-- | tests/examplefiles/tads3_example.t | 1248 |
1 files changed, 1248 insertions, 0 deletions
diff --git a/tests/examplefiles/tads3_example.t b/tests/examplefiles/tads3_example.t new file mode 100644 index 00000000..41881c93 --- /dev/null +++ b/tests/examplefiles/tads3_example.t @@ -0,0 +1,1248 @@ +#charset "utf-8" + +#include <adv3.h> +#include <en_us.h> + +extern function extern_function; +extern method extern_method; +extern function extern_function(a, b=a, c='<<a>>', d:, e:=1, f?, ...); +extern method extern_method(a, b=a, c='<<a>>', d:, e:=1, f?, [g]);; +extern class extern_class; +extern object extern_object; +intrinsic 't3vm' { }; +#ifndef PropDefAny +intrinsic class Object 'root-object/030004' { }; +#endif +object /**//**/ // /* \\ +#define Room Unthing + template [lst]; + +/* + * Quotations from "Le Roman de la Rose" are transcribed from MS. Douce 195, + * owned by Bodleian Library, University of Oxford + * (http://image.ox.ac.uk/show?collection=bodleian&manuscript=msdouce195). + */ + +versionInfo: GameID + IFID = '17d8efc3-07da-4dde-a837-ff7c4e386a77' + name = 'Pygmentalion' + byline = 'by David Corbett' + htmlByline = 'by <a href="mailto:corbett.dav\100husky.neu.edu">David + Corbett</a>' + version = '1' + authorEmail = 'David Corbett\040<corbett.dav\x40husky.neu.edu>' + desc = 'You have fallen in love with a statue\x2e' + htmlDesc = 'You have fallen in love with a statue\x2E' +; + +/* + * Pymalion fu ẽtailleꝛꝛes. + * Poᷣtrayãs en fus ⁊ en peꝛꝛeˢ + * En metaulx en os ⁊ en cyꝛes + * Et en touteˢ aultres matires. + * Quon peult a tel oeuure trouuer. + * Poᷣ ſon grant engin eſpꝛouuer. + * Car maiſtre en fu bien dire loz. + * Ainſi com poᷣ acquerre loz + * Se voult a poᷣtraire deduyꝛe + * Si fiſt vng ymage diuuyꝛe + * Et miſt au faire tel entente + * Quel fu ſi plaiſãt et ſi gente + * Quel ſembloit eſtre auſſi viue. + * Com la plus belle riens q̇ viue + * (MS. Douce 195, fol. 149r) + */ + +modify _init() +{ + ({: local r, r = randomize, r})(); + replaced(); +} + +gameMain: GameMainDef + initialPlayerChar: Actor { + desc = "You look the same as usual, but you feel unusually + sentimental. " + location = entrance + } + showIntro + { + "The statue is undeniably a masterpiece: the most skillful carving you + have ever done, and the most beautiful woman you have ever seen. + Unfortunately, she is also an inanimate block, and now you can neither + work nor rest for unrequitable love.\b + Once again you stumble into your studio, hoping and praying to find + your statue brought to life.\b + <b><<versionInfo.name>></b>\r\n + <<versionInfo.byline>>\b"; + } +; + +enum token token, tokOp, token; + +modify cmdTokenizer + rules_ = static + [ + ['whitespace', new RexPattern('%s+'), nil, &tokCvtSkip, nil], + ['punctuation', new RexPattern('[.,;:?!]'), tokPunct, nil, nil], + ['spelled number', + new RexPattern('<NoCase>(twenty|thirty|forty|fifty|sixty|' + + 'seventy|eighty|ninety)-' + + '(one|two|three|four|five|six|seven|eight|nine)' + + '(?!<AlphaNum>)'), + tokWord, &tokCvtSpelledNumber, nil], + ['spelled operator', new RexPattern( + '<NoCase>(plus|positive|minus|negat(iv)?e|not|inverse(%s+of)?|' + + 'times|over|divided%s+by|mod(ulo)?|and|xor|or|[al]?sh[lr])' + + '(?!<AlphaNum>)'), + tokOp, &tokCvtSpelledOperator, nil], + ['operator', R'[-!~+*/%&^|]|<<|>>>?', tokOp, nil, nil], + ['word', new RexPattern('<Alpha|-|&><AlphaNum|-|&|squote>*'), + tokWord, nil, nil], + ['string ascii-quote', R"""<min>([`\'"])(.*)%1(?!<AlphaNum>)""", + tokString, nil, nil], + ['string back-quote', R"<min>`(.*)'(?!%w)", tokString, nil, nil], + ['string curly single-quote', new RexPattern('<min>\u2018(.*)\u2019'), + tokString, nil, nil], + ['string curly double-quote', new RexPattern('<min>\u201C(.*)\u201D'), + tokString, nil, nil], + ['string unterminated', R'''([`\'"\u2018\u201C](.*)''', tokString, + nil, nil], + ['integer', new RexPattern('[0-9]+'), tokInt, nil, nil] + ] + replace tokCvtSpelledOperator(txt, typ, toks) + { + toks.append([rexReplace(R'%s+', txt.toLower(), '\\'), typ, txt]); + } +; + +/* Tokens */ + +/* + * Puiˢ li reueſt en maĩteˢ guiſes. + * Robeˢ faicteˢ ꝑ grãˢ maiſtriſeˢ. + * De biaulx dꝛaps de ſoye ⁊ de laĩe. + * Deſcarlate de tiretaine + * De vert de pers ⁊ de bꝛunecte + * De couleᷣ freſche fine ⁊ necte + * Ou moult a riches paneˢ miſes. + * Herminees vaires et griſes + * Puis les li roſte puis reſſaye. + * Cõmant li ſiet robbe de ſaye + * Sendaulx meloguins galebꝛunˢ. + * Indes vermeilz iaunes ⁊ bꝛunˢ. + * [...] + * Aultre foiz luy repꝛẽd courage. + * De tout oſter ⁊ mectre guindeˢ. + * Iaunes vermeilles vers ⁊ indeˢ. + * (MS. Douce 195, fol. 150r) + */ + +class Token: Achievement +{ + points = 1; + desc = "<<before_>><<desc_>><<after_>>"; + before = before = '', before_ + after = (after = '', after_) +} + +Token template inherited 'before_' 'after_' 'desc_'; + +#define DefineToken(name, before, after) name##Token: Token before after #@name + +DefineToken(builtin, '<font color=green>', '</font>'); +DefineToken(comment, '<i><font color=#408080>', '</font></i>'); +DefineToken(decorator, '<font color=#aa22ff>', '</font>'); +DefineToken(error, '<U><FONT COLOR=RED>', '</FONT></U>'); +DefineToken(escape, '<b><font color=#bb6622>', '</font></b>'); +DefineToken(float, '<u><font color=gray>', '</font></u>'); +DefineToken(keyword, '<b><font face=TADS-Sans color=green>', '</font></b>'); +DefineToken(label, '<font color=#A0A000>', '</font>'); +DefineToken(long, '<i><font color=gray>', '</font></i>'); +DefineToken(name, '<u>', '</u>'); +DefineToken(operator, '<b><font color=\"#AA22FF\">', '</font></b>'); +DefineToken(string, '<font color=\'#BA2121\'>', '</font>'); +DefineToken(whitespace, '<font color="bgcolor"bgcolor=\'text\'>', '</font>'); + +function highlightToken(tokenString) +{ + local token = [ + 'built in' -> builtinToken, + 'comment' -> commentToken, + 'decorator' -> decoratorToken, + 'error' -> errorToken, + 'escape' -> escapeToken, + 'float' -> floatToken, + 'keyword' -> keywordToken, + 'label' -> labelToken, + 'long' -> longToken, + 'name' -> nameToken, + 'operator' -> operatorToken, + 'string' -> stringToken, + 'white space' -> whitespaceToken, + * -> nil + ][tokenString.toLower()]; + if (!token) + return tokenString; + token.awardPointsOnce(); + return '<<token.before>><<tokenString>><<token.after>>'; +} + +string /**//**/ // /* \\ +#define Room Unthing + template <<highlight *>> highlightToken; + +/* Grammar for materials */ + +dictionary property material; +grammar adjWord(material): <material material>->adj_ : AdjPhraseWithVocab + getVocabMatchList(resolver, results, extraFlags) + { + return getWordMatches(adj_, &material, resolver, extraFlags, + VocabTruncated); + } + getAdjustedTokens() + { + return [adj_, &material]; + } +; + +/* Rooms and objects */ + ++ property location; + +entrance: Room 'Entrance' + "You are in the entrance to your studio. This is where you carve great + works of art, not that you have felt like making any lately. A door leads + outside, and the studio itself is to the north and the east. " + north = workbenchRoom + northeast = sinkRoom + east = altarRoom + south = door + out asExit(south) +; + ++ door: LockableWithKey, Door 'door' 'door' + "It is a simple wooden door. " + material = 'wood' 'wooden' + keyList = [key] + cannotOpenLockedMsg = '{The dobj/He} {is} locked. You cannot + <<highlight 'escape'>>! ' +; + +key: PresentLater, Key 'key' 'key' @altar + "It is a <<unless clean>>grimy<<end>> bronze key. <<if clean>>On it is \ + etched the word <q><<keyword>></q>. " + material = 'bronze' + clean = nil + keyword = (keyword = randomGreekWord(), targetprop) + dobjFor(Clean) { verify { } action { askForIobj(CleanWith); } } + dobjFor(CleanWith) + { + verify + { + if (clean) + illogicalAlready('{The dobj/He} {is} already clean. '); + } + action + { + gDobj.clean = true; + "{You/He} clean{s} {the dobj/him}, revealing an inscription. "; + } + } + dobjFor(Read) { verify { nonObvious; } } +; + +workbenchRoom: Room 'At the Workbench' + "This workbench, in the northwest part of the studio, was where you would + create works of art. Now you just come here to contemplate your + creation’s beauty and lament your hopeless situation.\b + The statue stands on a plinth beside the workbench. " + east = sinkRoom + southeast = altarRoom + south = entrance + getDestName(actor, origin) { return 'the workbench'; } +; + ++ workbench: Fixture, Surface + 'workbench/bench/material/materials/tool/tools' 'workbench' + "Normally, the workbench would be scattered with half-finished projects, + but now your tools and materials lie abandoned. " +; + ++ plinth: Fixture, Thing 'marble plinth/pedestal' 'plinth' + "It’s a smoothed block of marble about a cubit high. " +; + +replace grammar predicate(Screw): ' ': object; +replace grammar predicate(ScrewWith): ' ': object; ++ + statue: Fixture, Surface + '"creation\'s" beauty/carving/creation/galatea/statue/woman' 'statue' + "This is a<<if nameToken.scoreCount>>n untitled<<end>> statue of a woman + carved from <<if errorToken.scoreCount>>flawless <<end>> + <<if whitespaceToken.scoreCount>>milk-white <<end>>ivory. + <<if escapeToken.scoreCount || longToken.scoreCount>>Her + <<if longToken.scoreCount>>long <<end>>hair is done up in a + chignon<<if escapeToken.scoreCount>>, with a few strands falling down her + neck<<end>><<if floatToken.scoreCount>>, and \v<<else>>.<<end>><<end>> + <<if floatToken.scoreCount>>She radiates an aura of contrapposto grace. + <<end>><<if keywordToken.scoreCount>>\bYou wonder what she + <<if labelToken.scoreCount>>is going to<<else>>will<<end>> be like as a + woman. + <<if decoratorToken.scoreCount>>Maybe she’ll be a painter and expand + your business.<<end>> + <<if operatorToken.scoreCount>>Maybe she’ll have a head for figures + and will put the accounts in order.<<end>> + <<if builtinToken.scoreCount>>She’ll love you, obviously, but beyond + that you don’t know.<<end>><<end>> + <<if commentToken.scoreCount>>If only Aphrodite would bring her to life + without this silly puzzle about tokens and mirrors!<<end>> " + material = 'ivory' + propertyset 'is*' + { + propertyset 'H*' + { + im = nil\ + er = true; + } + It = true + } + iobjFor(PutOn) + { + check + { + if (gDobj not /**//**/ // /* \\ +#define Room Unthing + in (necklace, __objref(necklace, warn))) + "How rude! You don’t know what you were thinking. "; + } + } + iobjFor(GiveTo) remapTo(PutOn, DirectObject, IndirectObject) +; + ++++ necklace: Wearable + 'pearl necklace/string pearls' '<<highlight 'string'>> of pearls' + "This is a masterfully crafted pearl necklace. You hope the statue + won’t mind if you hold onto it for a while. " + initDesc = "You gave the statue this pearl necklace yesterday. " + isPlural = true +; + +altarRoom: Room 'At the Altar' + "Light from the window illuminates a crude altar. Until recently, this + corner was your bedroom. The rest of the studio lies north and west. " + north = sinkRoom + northwest = workbenchRoom + west = entrance + getDestName(actor, origin) { return 'the altar'; } +; + ++ window: Fixture 'window' 'window' + "It’s just a window above the altar. <<one of>>The space under the + window is blank; as an interior <<highlight 'decorator'>>, you can’t + help but think the wall would benefit from a bas-relief, but – + <i>sigh</i> &endash you are too lovelorn to wield the chisel. <<||>>The + wall right below it is a boring <<highlight 'white space'>>. <<stopping>>" +; + ++ altar: Fixture, Surface 'crude rough altar/banker/slab' 'altar' + "A rough marble slab lies on a wooden banker. In your rush to construct an + altar, you neglected the usual surface finish and friezes, but you pray at + it anyway. You are sure the gods will understand. " + material = 'marble' 'wood' 'wooden' + bulkCapacity = 1 + dobjFor(PrayAt) + { + verify { } + action() + { + /* + * Biaulx dieux diſt il tout ce poez. + * Sil voꝰ plaiſt ma requeſte oez + * [...] + * Et la belle q̇ mon cueᷣ emble + * Qui ſi bien yuoyꝛe reſſemble. + * Deuiengne ma loyal amye + * De fẽme ait coꝛps ame et vie + * (MS. Douce 195, fol. 151r) + */ + local offering; + foreach (offering in contents); + if (!keywordToken.scoreCount) + "<<one of>><q>O Aphrodite,</q> you say, <q>comforter of + hopeless lovers, hear my prayer! May she to whom I have given + my heart be given body, soul, and life. And a colorful + personality. And&mdash</q>\b + You are interrupted by a shimmering about the altar. As you + watch, it takes the form of a callipygian goddess.\b + <q>Mortal, I have heard your heart-felt and oft-repeated plea, + and I will take pity on you,</q> says Aphrodite. <q>If you give + me a token of your love as an offering, I will give you the + <<highlight 'keyword'>> of life. Speak this word in the + presence of a mirror, and I will grant your request.</q>\b + She fades away, adding, <q>As for her colorful personality, + just look around you.</q> <<or>><<stopping>>"; + else if (key.location) + "<q>O Aphrodite,</q> you say, <q>what am I supposed to do + again?</q>\bThe goddess reappears and reminds you to speak the + keyword of life at a mirror. <<one of>><q>What’s the + keyword, then?</q> <q>Gods help those who help themselves. + Figure it out yourself.</q><<or>><q>Why a mirror?</q> <q>I like + mirrors.</q><<purely at random>> "; + else if (offering == necklace) + { + "Aphrodite reappears. <q>A necklace! Perfect!</q> The necklace + disappears in a bright flash. When your eyes readjust, you see + a key lying in its place. "; + necklace.moveInto(nil); + key.makePresent(); + } + else if (+offering) + "Aphrodite reappears. She eyes <<offering.theNameObj>> + skeptically. <q><<one of>>No <<highlight 'comment'>>.<<or>>You + call <i>that</i> a token of love?<<or>>\^<<offering.aNameObj>>? + Really?<<or>>Come on, mortal, it’s not that + difficult!<<then at random>></q> "; + else + "<q>I heard you the first time,</q> says Aphrodite. <q>Prove + your devotion by offering a token of your love at the altar, + or the deal’s off.</q> "; + } + } + iobjFor(GiveTo) remapTo(PutOn, DirectObject, IndirectObject) +; + +aphrodite: Unthing + '(love) aphrodite/cytherea/god/goddess/venus love' 'Aphrodite' + '<<if gActor.canSee(altar)>>You can only pray to a god. + <<else>>You need an altar to interact with a god. ' + location = (gPlayerChar) + isProperName = true + isHer = true + iobjFor(GiveTo) + { + verify + { + illogical('She isn’t here. You’ll have to leave {the + dobj/him} somewhere she can find it. '); + } + } + dobjFor(PrayAt) maybeRemapTo(gActor.canSee(altar), PrayAt, altar) +; + +sinkRoom: Room 'Washroom' + "Sculpting marble is a dusty business. You use this sink to clean off after + a hard day’s work. Beside the sink is a small end table, and on the + wall is a calculator. The rest of the studio is south and west. " + south = altarRoom + southwest = entrance + west = workbenchRoom +; + +property level, overflowing; +export overflowing; +export level 'waterLevel'; ++ sink: Fixture '(auto) (mop) auto-sink/autosink/bowl/drain/faucet/sink' 'sink' + "This is a state-of-the-art mop sink with anti-miasmic coating and bronze + backsplash. It is so modern, there are no handles or other obvious ways to + turn it on.\b + <<if overflowing>>It is overflowing. + <<else unless level < 19500>>It is full to the brim with water. + <<otherwise if level >= 15000>>It is full of water. + <<otherwise unless level < 10000>>It is half full of water. + <<else if level >= 2000>>There is some water in the sink. + <<else if level > 0>>A small puddle has formed at the bottom of the sink. + <<otherwise>>It is empty. + <<if level <= -1.0e+2>>It looks like it hasn’t been used in a + <<highlight 'long'>> time. " + level = not in ([lst]) { return argcount; } + not = in() + overflowing = nil + current = self + setLevel(level:) + { + targetobj.current.overflowing = level == nil; + targetobj.current.level = min(level ?? 0, 20000); + if (sink.overflowing || sink.level > 0e+1) + sinkWater.makePresent(); + if (basin.overflowing || basin.level > 0e-1) + basinWater.makePresent(); + } + iobjFor(CleanWith) remapTo(CleanWith, DirectObject, sinkWater) +; + +++ sinkWater: PresentLater, Fixture + '(sink) water sink water' 'water' "<<sink.desc>>" + disambigName = 'water in the sink' + dobjFor(Drink) + { + verify { illogical('''{You're} not thirsty. '''); } + } + iobjFor(CleanWith) + { + preCond = [] + verify { + if (!location) + illogicalNow('There is no water in the sink. '); + if (!sink.overflowing && sink.level < 1e2) + illogicalNow('There is not enough water in the sink. '); + } + } +; + ++ table: Fixture, Surface 'small end bracket/table' 'table' + "<<first time>>Upon closer inspection, you see that \v<<only>>The table is + bracketed to the wall. " +; + +++ Readable '"operator\'s" manual' 'manual' + "<center ><<highlight 'Operator'>>’s Manual<\center>\b + <bq>To control the auto-sink, use the calculator add-on to enter the + desired volume of water. For example,\n + \t\t<<aHref('calculate 69 * 105', 'CALCULATE 69 TIMES 105')>>\n + to fill the basin with <<% ,d 0x69 * 0105>> kochliaria<!-- an ancient Greek + unit, < 5 ml >.\b + Warning: Do not use big numbers or divide by zero!<\\bq>\b" + dobjFor(Read) asDobjFor(Examine) +; + ++ calculator: Fixture, Thing 'button/buttons/calculator/screen' 'calculator' + "The calculator is <<highlight 'built in'>>to the wall beside the sink. It + has buttons for all the standard unary and binary operations. + <<if(screen)>>The screen reads <<screen>>" + screen = nil + literalMatch = '' +; + +method wrongContextMsg() +{ + return '<font face="TADS-Typewriter"><<highlight '<<'ERROR'>>'>> {{can\'t + use\ \"<<self.literalMatch>>\" in that context}}</font>. '; +} + +portico: OutdoorRoom 'Portico' + "Columns line the portico stretching east and west, and steps lead down to + the south. The door leads back in, and beside the door is a basin. A + <<highlight 'label'>> is affixed to the doorpost. " + north = (__objref(error, error)) + in asExit(north) + south: FakeConnector + { + "You begin moving away from the door, but then you remember the statue. + The gods won’t bring her to life if you give up this easily! + <<setMethod(&isConnectorApparent, {origin, actor: nil})>>" + } + east asExit(south) + west asExit(south) + down asExit(south) +; + +error: LockableWithKey, Door ->door 'door' 'door' @portico "<<door.desc>>" + keyList = (otherSide.keyList) +; + ++ Fixture 'column*columns' 'columns' + "There are six <<one of>>short columns with simple capitals<<or>>slender + columns with scrollwork in the capitals<<or>>tall columns with ornate + capitals<<sticky random>>. Above the architrave is a frieze depicting some + of your wares. <<first time>>The cornice overhangs the frieze a bit too + much, you think; perhaps you should shorten it. You try to concentrate on + the architecture of the portico, stoically ignoring what you cannot change, + but it doesn’t work. It never does. <<only>>" + isPlural = true +; + ++ Fixture, Readable 'label/doorpost' '<<highlight 'label'>>' + "The <<highlight 'label'>> says <q>Pygmentalion</q><<first time>> (which is + your <<highlight 'name'>>)<<only>>. " + dobjFor(Read) asDobjFor(Examine) +; + ++ basin: RestrictedContainer, Fixture + '(bird) basin/bath/birdbath/fountain/mosaic/pool/tile/tiles' 'basin' + "It is shallow but wide, and lined with tiles. It used to be a fountain, + but it stopped working after they installed the new sink. Something to do + with water pressure, no doubt. Now you just use it as a birdbath.\b + <<if overflowing>>Water is spilling over the sides in a turbulent flow. + <<else if level >= 19500>>It is full to the brim with water. You can see + your reflection quite clearly. Gods, you look a mess. + <<else if level >= 15000>>It is full of water. You can see your reflection. + <<else if level >= 10000>>It is half full. From the right angle, you can + make out a shadowy reflection of the columns, but nothing more. + <<else if level >= 2000>>There is some water in it, but you can still make + out the mosaic lining the basin. + <<else if level > 0>>A small puddle has formed at the bottom of the basin. + <<else>>It is empty. + <<if level <= -1.0e+2>>It looks as if it has never been filled. " + level = 0 + overflowing = nil + isMirror = (level >= 15000) + setLevel(level:) + { + delegated sink.setLevel(_: sourceTextOrder ? level: nil, level: level); + } + iobjFor(CleanWith) maybeRemapTo(basinWater.location, CleanWith, + DirectObject, basinWater) +; + +++ basinWater: PresentLater, Fixture '(basin) water basin water' 'water' + "<<basin.desc>>" + disambigName = 'water in the basin' + dobjFor(Drink) + { + verify + { + illogical('Drinking from a birdbath might not be the best idea. '); + } + } + iobjFor(CleanWith) + { + preCond = [touchObj] + verify { + illogical('Washing something in a birdbath is unlikely to get it + clean. '); + } + } +; + +++ feather: PresentLater, Thing + '(bird) (dove) (pigeon) (turtle) (turtle-dove) (turtledove) feather' + 'feather' "It’s a turtle-dove feather: an auspicious omen! " + initSpecialDesc = "<<one of>>A little brown bird is splashing around in the + basin. When it notices you, it ruffles its feathers, one of which falls + out, and flies out between the columns. <<or>>A feather is + <<if basin.overflowing || basin.level > 0>><<highlight 'float'>>ing + <<else>>lying <<end>> in the basin. <<stopping>>" +; + +/* Water */ + +trickling(water) multimethod +{ + if (sink.overflowing) + { + dirs: for (local dir in Direction.allDirections) + { + if (dir.ofKind(RelativeDirection)) + continue; + if (dir.ofKind(ShipboardDirection)) + continue dirs; + if (water.eventualLocation.(dir.dirProp) == __objref(entrance)) + return 'trickling <<dir.name>>'; + } + } + return 'a stagnant puddle'; +} + +class Water:PresentLater,Fixture'(floor) (ground) water puddle water''water' + "The water on the floor is <<trickling(self)>>. " + disambigName = 'water on the floor' + specialDesc = "The floor is covered with water. " + dobjFor(Drink) + { + preCond = [touchObj] + verify { } + check { failCheck('{You\'re} not thirsty. '); } + } + iobjFor(CleanWith) + { + preCond = [touchObj] + verify { illogical('The water on the ground is too dirty. '); } + } +; + +Water template +location | ~location "specialDesc"? inherited; +Water +altarRoom; +Water +sinkRoom { ;; }; +Water { +workbenchRoom }; + +entranceWater: Water +entrance + "<<if sink.overflowing>>At your feet, all the water from the sink flows + into a <<%-o 02>>-dactyl slit in the baseboard. <<else>><<inherited>>" + vocabWords = 'water baseboard/puddle/slit water' +; +trickling(entranceWater w) +{ + return sink.overflowing ? 'trickling into the wall' : inherited<*>(w); +} + +porticoWater: Water ~portico; +trickling(porticoWater w) +{ + return basin.overflowing ? 'trickling down the stairs' : inherited<*>(w); +} + +/* Calculating */ + +;;;class is: Exception { finalize { } };;; // InvalidSpecificationError + +DefineLiteralAction(Calculate) + checkAction() + { + if (defined(calculator) && !gActor.canTouch(calculator)) + { + { gActor.failCheck('{You/He} {can\'t} do that kind of math in + {your} head. '); } + } + } + execAction() + { + local op = function(...) { throw new is(); }, a, b; + local opString = (literalMatch, literalMatch); + if (numMatch) + goto binary; + switch (opString) + { + case '!': + case 'not': + opString = '!'; + op = {x : !toInteger('<<%_\u0030[1]5.3\170x>>', 16)}; + break; + case '+': + case 'plus': + case 'positive': + opString = '+'; + op = {self_ : self_}; + break; + case '-': + case 'minus': + case 'negate': + case 'negative': + opString = '−'; + op = {x : -x}; + break; + case '~': + case 'inverse': + case 'inverse\\of': + opString = '~'; + op = {x : ~x}; + break; + } + goto doCalculation; + binary: binaryOp: + switch (opString) + { + case '+': + case 'plus': + opString = '+'; + op = {a, b : +a+++b}; + break binaryOp; + case '-': + case 'minus': + opString = '−'; + op = {a, b : -b-- - -a}; + break; + case '*': + case 'times': + opString = '×'; + op = new function(a, b) { return a * b; }; + break; + case '/': + case 'over': + case 'divided\\by': + opString = '/'; + op = function(a, b) { return a / b; }; + break; + case '%': + case 'mod': + case 'modulo': + opString = 'mod'; + op = function(a, b, multimethod=b) { return a % multimethod; }; + break; + case '\<<': + case 'shl': + case 'ashl': + case 'lshl': + opString = '<<'; + op = {a, b, c? : a << b}; + break; + case '&': + case 'and': + opString = '&'; + op = {a, b : local badness = a, local token = b, badness & token}; + break; + case '^': + case 'xor': + opString = '^'; + op = {a, b, c? : a ^ b}; + break; + case '|': + case 'or': + opString = '|'; + op = {a, b : a | b}; + break; + case '>\>': + case 'shr': + case 'ashr': + opString = '>>'; + op = {a, b : toInteger('<<(a >> b)>>')}; + break; + case '>>>': + case 'lshr': + opString = '>>>'; + op = {a, b : b ? invokee(a >>> 1, --b) : a}; + break; + } + opString = ' <<opString>> '; + doCalculation: + "The calculator outputs "; + try + { + a = numMatch ? numMatch.getval(colon : nil) : nil; + b = numMatch2.getval(); + local result = toInteger(numMatch ? op(a, b) : op(b)); + calculator.setMethod(&screen, method() + { + return '<font face="TADS-Typewriter"><<a>><<opString>><<b>> = + <<%d result>></font>. '; + }); + local oldLevel = sink.level; + sink.current.setLevel(level: result); + "<<calculator.screen()>> + <<if sink.current == basin>>The sink gurgles and the pipes rattle. + <<else if sink.level == oldLevel>>The sink gurgles. + <<else if sink.level <= 0 && oldLevel <= 0>>The pipes rattle for a + moment. + <<else if sink.level <= 0>>All the water drains from the sink. + <<else if oldLevel <= 0>>The sink begins to fill with water. + <<else if sink.level < oldLevel - 0xabc>>Some of the water drains + from the sink. + <<else if sink.level < oldLevel>>The water level drops slightly. + <<else if oldLevel < sink.level - 0XABC>>Water splashes into the + sink for a few seconds. + <<else if oldLevel < sink.level>>Water dribbles from the faucet. "; + } + catch (is in) + { + calculator.literalMatch = literalMatch; + calculator.setMethod(&screen, &wrongContextMsg); + "<<calculator.screen()>>"; + } + catch (RuntimeError e) + { + calculator.setMethod(&screen, new method + { + return '<font face=\"TADS-Typewriter\"><<highlight 'ERROR'>> + {{<<e.exceptionMessage>>}}</font>.\b'; + }); + "<<calculator.screen()>>"; + switch (e.errno_) + { + case 2008: // division by zero + "<<if sink.current == sink + && (sink.level > 0 || sink.overflowing)>>The water in the + sink is sucked down the drain. + <<else if basin.level > 0 || basin.overflowing>>Water comes up + from the drain and <<if basin.overflowing>>spills over + the edges of<<else>>begins to fill<<end>> the sink. + <<else>>The sink gurgles and the pipes rattle. "; + sink.current = sink.current == sink ? basin : sink; + local _tmp = sink.level; + sink.level = basin.level; + basin.level = _tmp; + _tmp = sink.overflowing; + sink.overflowing = basin.overflowing; + basin.overflowing = _tmp; + if (!sink.current.overflowing) + break; + // fall through + case 2023: // numeric overflow + if (!sink.current.overflowing) + "<<if sink.current == sink>>High-pressure water streams + from the faucet, filling the sink and spilling over the + edge. Rivulets begin running down the slight gradient of + the floor. <<else>>The pipes shake loudly. "; + forEachInstance(Water, function(w) { + if ((w.eventualLocation == portico) == + (sink.current == basin)) + w.makePresent(); + }); + sink.current.setLevel(level: nil); + break; + default: + throw e; + } + } + if (!gPlayerChar.hasSeen(feather)) + { + feather.makePresentIf(basin.isMirror); + feather.moved = nil; + } + } +; + +VerbRule(Calculate) + ('c' | 'calculate' | 'enter' | 'eval' | 'evaluate') (()|(singleNumber|)) + (tokOp->literalMatch | '!'->literalMatch) numberPhrase -> numMatch2 + : CalculateAction + verbPhrase = 'calculate/calculating (what) (how) (what)' +; + +/* Cleaning */ + +modify VerbRule(Clean) + [ /**//**/ // /* \\ +#define Room Unthing + badness 500] ('clean' | 'wash') dobjList: +; + +grammar predicate(CleanIn): + ('clean' | 'wash') dobjList ('at' | 'in' | 'with') singleIobj + : CleanWithAction + verbPhrase = 'clean/cleaning (what) (in what)' + askIobjResponseProd = inSingleNoun + omitIobjInDobjQuery = true +; + +/* Prayer */ + +VerbRule(Pray) + [badness 500] 'pray' singleDobj + : PrayAtAction + verbPhrase = 'pray/praying (at what)' +; + +VerbRule(PrayAt) + 'pray' ('at' | 'to') singleDobj + : PrayAtAction + verbPhrase = 'pray/praying (at what)' + askDobjResponseProd = singleNoun +; + +DefineTAction(PrayAt); +modify Thing + dobjFor(PrayAt) + { + verify + { + illogical('{You/He} {cannot} pray at {that dobj/him}. '); + } + } +; + +/* Extended grammar for 'in' and 'out' */ + +modify grammar directionName(in): 'in' | 'inside': + dir = inDirection +; +modify /**//**/ // /* \\ +#define Room Unthing + grammar directionName(out): 'out' | 'outside': + dir = outDirection +; + +/* Speech */ + +DefineLiteralAction(Say) + execAction + { + local literal = getLiteral().toLower(); + if (literal is in ('xyzzy', 'plugh')) + tryImplicitActionMsg(&silentImplicitAction, Xyzzy); + else if (literal != key.keyword) + "Nothing happens. "; + else if (literal not in ()) + { + if (gActor.location == portico && basin.isMirror) + { + if (feather.location == basin) + "The air above the basin shimmers, and the feather bobs on + the rippling water. After a moment, the shimmering + disappears."; + else + { + /* + * Venus q̇ la pꝛiere ouyt + * [...] + * A lymage ẽuoya loꝛs lame. + * Si deuĩt ſi treſbelle dame. + * Quoncq̄s en toute la contree. + * Not len ſi belle encontree. + * [...] + * Doulx amys aĩs ſuy vꝛ̄e amye. + * Pꝛeſte de voſtre compaignye. + * Receuoir ⁊ mamoᷣ voꝰ offre. + * Sil voꝰ plaiſt receuoir tel offre. + * (MS. Douce 195, fol. 151v) + */ + "The air above the basin shimmers for a moment. You hear + the door opening behind you. Turning around, you see a + woman who looks suspiciously like your statue, except not + the color of marble.\b + <q>Hello, world,</q> she says. <q>It’s nice to be + alive at last! Hello, dearest Pygmentalion.</q>\b + Ah, what beauty! What mastery of syntax! Praise be to + Aphrodite! "; + finishGameMsg(ftVictory, + [finishOptionUndo, finishOptionFullScore]); + } + } + else + "Nothing happens. <<if keywordToken.scoreCount>>Aphrodite said + you would need a mirror. <<end>>"; + } + } +; + +VerbRule(Say) + ('say' | 'shout') singleLiteral + : SayAction + verbPhrase = 'say/saying (what)' +; + +VerbRule(SayTo) + ('say' | 'shout') singleLiteral ('at' | 'to') singleIobj + : SayAction + verbPhrase = 'say/saying (what) (to what)' +; + +/**/ #if /* Revere the basileus. */ 0 \ + // Expel the barbarian. +; + #ifndef __DEBUG +; + #define __DEBUG +; +# else +; +#if 1 +; + #define DEBUG__ +; +#endif +; + #endif +;\\ +#endif +/* +#endif +?*/ +//\\ +#endif +''' +#endif +'\'''' +#endif +\\''' +""" +#endif +"\"""" +#endif +\\""" +' +#endif +\' +#endif +\\' +" +#endif +\" +#endif +\\" +'''<<'<<' +#endif +'>>'>> +#endif +''' +"""<<'<<' +#endif +'>>'>> +#endif +""" +'<<'<<' +#endif +'>>'>> +#endif +' +"<<'<<' +#endif +'>>'>> +#endif +"//" +\ + # endif +; +dictionary barbarianDict; +transient xyzzy: object; +DefineIAction(Xyzzy) + execAction + { + "Only a barbarian could pronounce such a word. "; + local oldSay = t3SetSay({str : nil}); + try + { + new transient Vector([ + '<<one of>><< cycling >>', + '<<one of>><< at random>>', + '<<one of>><<then purely at random>>', + '<<one of>><<as decreasingly likely outcomes>>', + '<<one of>><< shuffled>>', + '<<one of>><< half shuffled>>', + '<<one of>><<then shuffled>>', + '<<one of>><<then half shuffled>>']); + '''''<font x= color=red bgcolor='silver' face="TADS-Sans" + size=\'+1\' x=\"x\">{can't}</font>\'''' '' ''''; + """""<font x= color=red bgcolor='silver' face="TADS-Sans" + size=\'+1\' x=\"x\">{can't}</font>\"""" "" """"; + '<font x= color=red face="TADS-Sans" size=\'+1\' + x=\"x\">{can\'t}</font>\''; + "<font x= color=red bgcolor='silver' size=\'+1\' + x=\"x\">{can\'t}</font>\""; + '''''<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\'''' '' ''''; + """""<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\"""" "" """"; + '<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\''; + "<font <<'color=red'>> bgcolor<<'='>>silver + face=<<'"TADS-Sans"'>>>{ca<<'n\''>>t}</font>\""; + '''<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + c1="c{\>}" c2="{\>}c" c3="c{\>}c" d1=\'d{\>}\' d2=\'{\>}d\' + d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" e3=\"e{\>}e\"></s>'''; + """<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + c1="c{\>}" c2="{\>}c" c3="c{\>}c" d1=\'d{\>}\' d2=\'{\>}d\' + d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" e3=\"e{\>}e\"></s>"""; + '<s a1={\.}a a2=a{\>} a3=a{\>}a c1="c{\>}" c2="{\>}c" c3="c{\>}c" + d1=\'d{\>}\' d2=\'{\>}d\' d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" + e3=\"e{\>}e\"></s>'; + "<s a1={\.}a a2=a{\>} a3=a{\>}a b1='{\>}b' b2='b{\>}' b3='b{\>}b' + d1=\'d{\>}\' d2=\'{\>}d\' d3=\'d{\>}d\' e1=\"e{\>}\" e2=\"{\>}e\" + e3=\"e{\>}e\"></s>"; + '''{a<<1>>b}'''; """{a<<1>>b}"""; '{a<<1>>b}'; "{a<<1>>b}"; + '''<s a<<'='>>'1' b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" + <<'e'>>=5 f=6' g=7">'''; + """<s a<<'='>>'1' b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" + <<'e'>>=5 f=6' g=7">"""; + '<s b<<'='>>"2" c<<'='>>\'3\' d<<'='>>\"4\" <<'e'>>=5 g=7">'; + "<s a<<'='>>'1' c<<'='>>\'3\' d<<'='>>\"4\" <<'e'>>=5 f=6'>"; + '''<s a=v\\ a=v\ v\><s a='{'}'\><s a="{"}"\>'''; + """<s a=v\\ a=v\ v\><s a='{'}'\><s a="{"}"\>"""; + '<s a=v\\ a=v\ v\><s a=\'{\'}\'\><s a="{"}"\>'; + "<s a=v\\ a=v\ v\><s a='{'}'\><s a=\"{\"}\"\>"; + '''<font color='purple>igram</font>'''; '''<t a={'''; '''}'''; + '''<font color="purple>igram</font>'''; '''<t a='{'''; '''}'''; + '''<font color=\'purple>igram</font>'''; '''<t a="{'''; '''}'''; + '''<font color=\"purple>igram</font>'''; + """<font color='purple>igram</font>"""; """<t a={"""; """}"""; + """<font color="purple>igram</font>"""; """<t a='{"""; """}"""; + """<font color=\'purple>igram</font>"""; """<t a=\"{"""; """}"""; + """<font color=\"purple>igram</font>"""; + '<font color="purple>igram</font>'; '<t a={'; '}'; + '<font color=\'purple>igram</font>'; '<t a=\'{'; '}'; + '<font color=\"purple>igram</font>'; '<t a="{'; '}'; + "<font color=\"purple>igram</font>"; "<t a={"; "}"; + "<font color='purple>igram</font>"; "<t a='{"; "}"; + "<font color=\'purple>igram</font>"; "<t a=\"{"; "}\""; + '''<xmp a=v>&\x26<b><\xmp></xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp></xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp></xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp></xmp a=v>"; + '''<xmp a=v>&\x26<b><\xmp><\Xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp><\Xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp><\Xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp><\Xmp a=v>"; + '''<xmp a=v>&\x26<b><\xmp><\\xmp a=v>'''; + """<xmp a=v>&\x26<b><\xmp><\\xmp a=v>"""; + '<xmp a=v>&\x26<b><\xmp><\\xmp a=v>'; + "<xmp a=v>&\x26<b><\xmp><\\xmp a=v>"; + '''<xmp>'''; """<xmp>"""; '<xmp>'; "<xmp>"; + '''<listing a=v>&\x26<b><listing><xmp></listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp></listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp></listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp></listing a=v>"; + '''<listing a=v>&\x26<b><listing><xmp><\listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp><\listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp><\listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp><\listing a=v>"; + '''<listing a=v>&\x26<b><listing><xmp><\\listing a=v>'''; + """<listing a=v>&\x26<b><listing><xmp><\\listing a=v>"""; + '<listing a=v>&\x26<b><listing><xmp><\\listing a=v>'; + "<listing a=v>&\x26<b><listing><xmp><\\listing a=v>"; + '''<listing>'''; """<listing>"""; '<listing>'; "<listing>"; + } + finally + { + t3SetSay(oldSay); + } + } +; + +VerbRule(Xyzzy) + "xyzzy" | "plugh" * + : XyzzyAction + verbPhrase = 'babble/talking like a barbarian' +; + +randomGreekWord() +{ + local vowels = ['a', 'e', 'e', 'i', 'o', 'y', 'o']; + local consonants = ['p', 't', 'k', 'b', 'd', 'g', 's', 'm', 'n', 'l', 'r']; + local clusters = + ['pn', 'pl', 'pr', 'tm', 'tr', 'kn', 'kl', 'kr', 'bl', 'br']; + local ends = consonants - ['b', 'd', 'g']; + local word; + local retries = 0; + for (local r in 0 .. -1 step -1) + { + for ((r), local i = 0, local j = 2; i < j; ++i, --j) + { + for (local s = 0, local n in [90, 30, 10]; ; --s) + retries -= s * n; + } + } + retries *= 2; + retries >>= 1; + retries /= 2; + retries <<= 1; + retries >>>= 2; + retries %= 16; + retries &= ~1; + retries |= 2; + retries ^= retries ^ retries; + do + { + word = rand('[ptkbdgsm]?'); + for (local i in 0 .. __TADS3) + word += concat(rand(rand('', clusters, consonants)), rand('"h"?'), + rand(vowels...), rand('','', 'i', 'u', rand(ends))); + word += rand('"s"?'); + word = rexReplace(R'^[pk](?![tnlrhaeioy]|[tnlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^b(?![dlrhaeioy]|[dlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^g(?![nlrhaeioy]|[nlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^t(?![mrhaeioy]|[mlr]h?[^aeioy])', word, ''); + word = rexReplace(R'^d(?![rhaeioy]|rh?[^aeioy])', word, ''); + word = rexReplace(R'^m(?![nhaeioy]|nh?[^aeioy])', word, ''); + word = rexReplace(R'^[^aeioy]h?(([^haeioy]h?){2})', word, '%1'); + word = rexReplace(R'[ptkbdgs]([ptkbdg][^haeioy])', word, '%1'); + word = rexReplace(R'([mnlr])h', word, 'h%1'); + word = rexReplace(R'(?<!(^|[ptk]))h', word, ''); + word = rexReplace(R'^h(?![aeioy])', word, ''); + word = rexReplace(R'h(?=.*h)', word, ''); + word = rexReplace(R'(?<=^|r)r', word, 'rh'); + word = rexReplace(R'([iy]+)[iu]', word, '%1'); + word = rexReplace(R'nl', word, 'll'); + word = rexReplace(R'n(?=[pbm])', word, 'm'); + word = rexReplace(R'(?<.)m(?=[tdn])', word, 'n'); + word = rexReplace(R'pb|bp', word, 'pp'); + word = rexReplace(R'td|dt', word, 'tt'); + word = rexReplace(R'kg|gk', word, 'kk'); + word = rexReplace(R'bs', word, 'ps'); + word = rexReplace(R'ds|sd', word, 'z'); + word = rexReplace(R'gs', word, 'ks'); + word = rexReplace(R'ts', word, 'ss'); + word = rexReplace(R'[^pkaeioyusnr]+(s?)$', word, '%1'); + word = rexReplace(R'[pk]+$', word, ''); + word = rexReplace(R'(.h?)%1{2,}', word, '%1%1'); + word = rexReplace(R'^(.h?)%1', word, '%1'); + word = rexReplace(R'(.h?)%1$', word, '%1'); + word = rexReplace(R'^y', word, 'hy'); + word = rexReplace(R'([ptk])([ptk])h', word, '%1h%2h'); + word = rexReplace(R'([ptk])h%1h', word, '%1%1h'); + word = rexReplace(R'ks', word, 'x'); + word = rexReplace(R'gg', word, 'kg'); + word = rexReplace(R'kh', word, 'ch'); + } while (retries-- && (word.length() < 4 || !rexSearch( + new RexPattern('^(eu|hy|[pgm]n|bd|tm|rh)|(.h.|pp|kc|rr)h|ch([^aeioy])|' + + '([^aeioy])y([^aeioy])$|(ps|x|o[ius])$'), word))); + return word; +} |