#charset "us-ascii" /* * Copyright (c) 1999, 2002 by Michael J. Roberts. Permission is * granted to anyone to copy and use this file for any purpose. * * This is a starter TADS 3 source file. This is a complete TADS game * that you can compile and run. * * To compile this game in TADS Workbench, open the "Build" menu and * select "Compile for Debugging." To run the game, after compiling it, * open the "Debug" menu and select "Go." * * Please note that this file contains considerably more than the * minimal set of definitions necessary to create a working game; this * file has numerous examples meant to help you start making progress on * your game more quickly, by giving you a few concrete examples that * you can copy and modify. As you flesh out your game, you should * modify the objects we define here, or simply remove them when you no * longer need them in your game. * * If you want a truly minimal set of definitions, create another new * game in TADS Workbench, and choose the "advanced" version when asked * for the type of starter game to create. */ /* * Include the main header for the standard TADS 3 adventure library. * Note that this does NOT include the entire source code for the * library; this merely includes some definitions for our use here. The * main library must be "linked" into the finished program by including * the file "adv3.tl" in the list of modules specified when compiling. * In TADS Workbench, simply include adv3.tl in the "Source Files" * section of the project. * * Also include the US English definitions, since this game is written * in English. */ #include #include /* * Our game credits and version information. This object isn't required * by the system, but our GameInfo initialization above needs this for * some of its information. * * IMPORTANT - You should customize some of the text below, as marked: * the name of your game, your byline, and so on. */ versionInfo: GameID name = 'Cheeseshop' byline = 'by David Welbourn' htmlByline = 'by David Welbourn' version = '1.0' authorEmail = 'David Welbourn ' desc = 'An interactive re-creation of the famous Cheeseshop sketch by Monty Python\'s Flying Circus.' htmlDesc = 'An interactive re-creation of the famous Cheeseshop sketch by Monty Python\'s Flying Circus.' showCredit() { /* show our credits */ /* * The game credits are displayed first, but the library will * display additional credits for library modules. It's a good * idea to show a blank line after the game credits to separate * them visually from the (usually one-liner) library credits * that follow. */ "\b"; } showAbout() { "CHEESESHOP is, of course, based on the famous Cheeseshop sketch by Monty Python's Flying Circus, and its original text may be found in Monty Python's Flying Circus: Just the Words Volume Two. But what you may not know is that I first wrote this interactive version of Cheeseshop in JotaCode for the ifMud, and the source code for that version may be found at http://webhome.idirect.com/~dswxyz/cheeseshop.html.\b In case you're not familiar with the sketch, you are playing the role of Mousebender, who attempts to buy many varieties of cheese from Wensleydale, the shopkeeper. To do this, type commands like ASK MAN ABOUT BRIE or BUY GOUDA. Only varieties of cheese are recognized; the game doesn't know about brand names like Kraft or Velveeta. If you can't think of a new variety of cheese, type THINK.\b If you are familiar with the sketch, be assured that this is an interactive variant, which means that you can try to ask for different varieties of cheeses in any order (not just in the same order as in the original sketch), and do a few other things besides. On the other hand, the game remains somewhat on the rails in other ways, mostly so that progress through the dialogue occurs in reasonable order. (For example, the game will dissuade you from buying cheddar until late in the game.)\b It's just a short little game, but I do hope you have fun with it. And thanks to folks on the ifMud for help and beta-testing, you know who you are. Especial thanks go to Søren Løvborg; without his generous help, this TADS 3 version of the game would not have been possible."; } ; enum youLost, youWon; function endGame(flag, endMsg, postMsg) { local lst = [finishOptionUndo]; local msg = 'You have lost'; if (flag == youWon) { msg = 'You have won'; lst += finishOptionAmusing; } if (endMsg != nil) msg = endMsg; "\b\b*** << msg >> ***\b"; if (postMsg != nil) "<< postMsg >>\b"; finishGame(lst); // finishOptions are described in misc.t } modify finishOptionAmusing doOption() { "\bDid you try: \n... EXAMINE SHOP when outside? \n... GO a direction other than south from Outside Shop? \n... TAKE ALL when in the shop? \n... ASK the shopkeeper about non-cheese items, like the cat, the Viking, or even her breasts? \n... DANCE in the shop? (It is licensed for public dancing, after all.) \n... DANCERS, SHUT UP after the music has become annoying? \n... Avoid doing BUY CHEESE or GREET MAN (or similar commands) until after the dancers are gone, and then GREET MAN? \n... EXAMINE GUN twice? \n... TAKE the corpse or ASK it about something? \n... RING BELL after you've killed the shopkeeper? Multiple times? \n... XYZZY? <.p>Also, if this game has made you hungry for more cheese-filled adventures, I recommend a visit to the Cheese-Friendly Game Directory at http://emshort.home.mindspring.com/cheese.htm, maintained by Emily Short.<.p> "; return true; } ; outShop: OutdoorRoom 'Outside the Cheeseshop' "Ah! How wonderful. You were just thinking how nice a piece of cheese would be, and look. Here is a pleasant little cheeseshop, whose door beckons to the south. " in asExit(south) south : TravelMessage { travelDesc = "Feeling somewhat peckish, you decide to sally forth and infiltrate this place of purveyance to negotiate the vending of cheesy comestibles.<.p> " destination = inShop } cannotGoThatWay { reportFailure('(Be a lamb and just enter the shop to the south, would you, hon? Thanks. Kiss, kiss.) '); } ; + cheeseshop : Enterable 'cheese cheeseshop/shop/store/sign' 'cheeseshop' "It's an Edwardian-style shop with a large sign above it reading 'Ye Olde Cheese Emporium'. Another sign below the first reads 'Henry Wensleydale, Purveyor of Fine Cheese to the Gentry and the Poverty Stricken Too', and a sign below that reads 'Licensed for Public Dancing'. " connector = outShop.south ; inShop : Room name = 'Ye Olde Cheese Emporium' desc { if (dancers.isIn(inShop)) say(calcMusic()); "The cheeseshop is large and redolent of the charm and languidity of a bygone age. "; if (mgr.curState == deadShopkeeper) "The door out is to the north. "; if (dancers.isIn(inShop)) "In the corner, two men are Greek dancing to the music of a bouzouki. "; if (mgr.curState == deadShopkeeper) "<.p>{The mgr/he}'s dead body has fallen behind the counter. "; else if (mgr.isIn(inShop)) "<.p>{The mgr/he} stands behind the counter. "; else "<.p>On the counter is a small handbell. "; } north : FakeConnector { travelDesc() { if (!mgr.isIn(inShop)) "Oh, please. You haven't even talked to the shopkeeper yet. "; else if (mgr.curState == deadShopkeeper) { "You put on your cowboy hat, stride out the shop, and ride your horse into the sunset.<.p>\tTHE END<.p> "; endGame(youWon,'You have gained satisfaction','Thanks for playing! <.p>And now for something completely different: '); } else { "Frustrated with your lack of progress, you stride out the shop, taking your custom elsewhere. "; endGame(youLost,'You failed to get cheese', 'This will never do. Would you rather eat ' + rand([ 'spam, spam, spam, baked beans, and spam? ', 'a strawberry tart that doesn\'t have too much rat in it? ', 'a blancmange? ' ]) ); } } } ; + counter : Fixture, Surface 'counter' 'counter' dobjFor(Search) { action() { "You don't find any cheese on the counter. Only a small handbell. "; } } dobjFor(Smell) { action() { "You smell nothing untowards on the counter. "; } } dobjFor(Take) { verify() { illogical('Perhaps a purchase of cheese would be a more suitable souvenir of your visit. '); } } ; ++ handbell : Button 'small handbell/bell' 'small handbell' "The small handbell is on the counter. It<< mgr.curState == deadShopkeeper ? ' still ' : ' '>>looks quite ringable. " isListed = nil dobjFor(Push) { action() { if (!mgr.isIn(inShop)) { mgr.moveInto(inShop); me.noteConversation(mgr); // Note we are now talking to mgr. "You ring the handbell, and immediately, the shopkeeper pops up from behind the counter.<.p> \tGood morning, sir, the man says. \n\tYou say to him, Good morning. I'd like to buy some cheese, please. \n\tYes, certainly, sir. What would you like? "; } else if (mgr.curState == deadShopkeeper) { say('You ring the handbell, but ' + rand([ 'the dead manager ignores it. ', // {mgr/he} doesn't work! '{the mgr/he} fails to come back to life. ', 'the shop doesn\'t magically fill with cheese. ', 'the sketch fails to continue past this point. '])); } else say(rand(['No need. ','Why bother? ']) + '{The mgr/he} is already here. '); } } dobjFor(Ring) remapTo(Push,self) dobjFor(Take) { action() { "You can't take the small handbell. You could try ringing it, though. "; } } ; + dancers : Person 'two greek dancing corner*dancers/men/musicians' 'Greek dancers' "Two men in casual city wear are dancing a Greek folk dance while a third provides musical accompaniment with his bouzouki. " aName = 'the Greek dancers' isPlural = true actorHereDesc = '' dobjFor(Attack) { action() { "Loud words ought to suffice for dealing with these noisemakers. "; } } dobjFor(Kiss) { action() { "A BBC news reporter and camera crew suddenly pop in from nowhere! The reporter shouts into his microphone, Mousebender tries to pick up strange Greek men in a cheeseshop! Film at eleven! Then he and his film crew race out the door to file their story. "; } } dobjFor(ListenTo) { action() { music.desc(); } } dobjFor(ShoutAt) { action() { doShoutedAt(); } } doShoutedAt() { if (music.noiselevel == 1) "Let them be. They're not that annoying... yet. "; else { music.noiselevel = 0; dancers.moveInto(nil); music.moveInto(nil); "You suddenly turn to the dancers, and shout, <.p>\tWILL YOU SHUT BLOODY DANCING UP! <.p>[the music stops]"; if (mgr.isIn(inShop) && mgr.curState != deadShopkeeper) "<.p>{The mgr/he} tells the dancers, Told you so, as they sneak out the door. "; else "<.p>Grumbling, the dancers scurry out the door. "; } } dobjFor(Smell) { action() { "Come, come. Gentlepersons such as yourself do not go about smelling other people. "; } } dobjFor(Take) remapTo(Kiss,self) obeyCommand(issuer, action) { if (issuer == me && action.ofKind(ShutUpAction)) return true; "The Greek dancers ignore you and continue dancing. "; if (music.noiselevel == 2) "(Can they even hear you over the noise they're making?) "; return nil; } ; ++ bouzouki : Decoration 'bouzouki/instrument' 'bouzouki' "Ah, the bouzouki. You know, of course, that it's practically the signature sound of both rebetiko and Greek folk music. " dobjFor(ListenTo) { verify() { } action() { music.desc(); } } ; //TODO Listen: <>; // sourceDesc = appended to parent's desc. // descWithSource = the desc, when the parent is here. + music : SimpleNoise 'music/song/tune/melody/melos/noise' 'music' noiselevel = 1 // should go up to 2 when .trillNum is 10 or more last_turn = 0 // track turn when music last played. isMassNoun = true desc { // was descWithSource if (noiselevel >= 1) "Unless you're badly mistaken, it's the title instrumental theme from 'Zorba the Greek'. "; if (noiselevel == 2) "But frankly, it's getting on your nerves. You have half a mind to tell them to shut up just so a body could think. "; if (noiselevel == 0) "That bloody annoying music has finally ceased and replaced with blessed silence. "; } // hereWithSource { descWithSource(); } // soundHereDesc = "(music: oompah oompah) " dobjFor(Take) { verify() { illogical('Trying to pick up the melody, eh? '); } } trillNum = 0 // which trill to play next (0..35) trills = [ 'doo\ \ da\ \ doo\ \ da\ \ doo\ \ dah\ \ doo\ \ da', 'pa-plink! da doo da pa-plink! da doo da', 'padaplink da doo da pa-plink da doo da', 'puh-plunk da doo da padaplunk da doo da', 'pa-plunk dah doo padadaplunk dah doo dah', 'dadadadadadang doo da doo da doo da ...', 'ta-ting! da doo da, ta-ting! da doo da', 'tata-ting! da doo da, ta-ting! da doo da', 'ta-tang! da doo da, tata-tang! da doo da', 'ta-tang da doo tadadatang da doo ta', 'tadadadatang da doo da doo da doo da ...', 'dinga-dinga-dinga-dinga-dinga-dinga-dinga-dinga', 'dinga-dinga-dinga-dinga-dinga-dinga-dinga-dahding', 'dinga-dinga-dinga-dinga-dinga-dinga-dinga-dinga', 'dinga-dinga-dinga-dinga-dinga-dinga-dinga-dinga', 'zinga-zinga-zinga-zinga-zinga-zinga-zinga-zahzing', 'zinga-zinga-zinga-zinga-zinga-zinga-zinga-zinga', 'zonga-zinga-zinga-zinga-zinga-zinga-zinga-zahzing', 'zinga-zinga-zinga-zinga-zinga-zinga-zinga-zahzonga', 'zonga-zonga-zonga-zonga-zonga-zonga-zonga-zonga ...', 'ZahZing!bingabingabingabingabingabinga!', 'ZahZing!bingabingabingabingabingabinga!', 'ZuhZung!bingabingabingabingabingabinga!', 'ZatuhZung!bingabingabingabingabingabinga!', 'ZahZung!bingabingabingabingabingabinga!', 'ZatazataZung!bingabingabingabingabingabinga! ...', 'ZahZing! ta OompahOompah Oompah ZahZing! ta OompahOompahOompah', 'paTAhZing! ta OompahOompahOompah ZahZing! ta OompahOompahOompah', 'ZahZung! ta OompahOompahOompah paTAhZung! ta OompahOompahOompah', 'ZahZung! ta OompahOompahOompah paDaDaDaZung! ta OompahOompahOompah', 'paDaDaZung! PATABADALADAZING! PATABADALADAZING! PATABADALADAZING!', 'PATABADALADAZING! PATABADALADAZING! PATABADALADAZING!', 'PATABADALADAZING! PATABADALADAZING! PATABADALADAZING!', 'PATABADALADAZING! PA-tA-BAHTA!-PATATA!-PATABADALADAZING!!', 'PA-tA-BAHTA!-PATATA!-PATABADALADAZING! PINGA!PINGADABINGADAPINGADAPINGADADING!!', 'BINGABINGBINGBINGAGAPINGABINGBING!! PINGA!PINGADABINGADAPINGADAPINGADADING!!' ] ; modify Action beforeActionMain() { if (parentAction == nil && me.isIn(inShop) && dancers.isIn(inShop) && !gActionIs(Look) && gAction.actionTime > 0) extraReport(calcMusic()); } ; function calcMusic() { if (music.trillNum < music.trills.length) music.trillNum++; if (music.trillNum > 10) music.noiselevel = 2; return '[music: ' + music.trills[music.trillNum] + ']\b'; } ++ DefaultAskTellTopic "The Greek dancers ignore you and continue dancing.<< (music.noiselevel == 2) ? ' (Can they even hear you over the noise they\'re making?)' : ''>> "; ++ DefaultGiveShowTopic "They're not paying attention to you. "; // This is a joke object which is only seen via TAKE ALL. + cyanide: Decoration '' 'cyanide' hideFromAll(action) { /* if the command is TAKE, include me in ALL */ if (action.ofKind(TakeAction)) return nil; return true; /* but hide from X ALL, SMELL ALL, etc. */ } dobjFor(Take) { verify() { logicalRank(110,'surprise'); } action() { self.moveInto(nil); "You take the cyanide capsule that you've held onto for years for just such a situation as this, swallow it dry, and die. (No, sorry, just kidding. There's no cyanide in this game.) "; } } ; // This is the concept of cheese. // cheese.weakTokens = nil is done in mainCommon() + cheese : CheeseTopic, SimpleOdor 'cheese' 'cheese that you don\'t actually have' "You smell in vain for a whiff of cheese. " dobjFor(Examine) { action() { "You don't actually see any cheese. But surely there's some behind the counter or in a back room.<.p>"; nestedAction(Think); } } dobjFor(Smell) { action() { "You smell in vain for a whiff of cheese. "; } } handleBuySpecial() { isVague = true; "\tYou tell {the mgr/him}, I was walking by your shop when suddenly I came over all peckish for a little fermented curd. \n\tPeckish?, he asks, puzzled.\n\tEsurient, you say.\n\tEh? \n\tEee I were all hungry, like, you say, in a broad Yorkshire accent. "; if (music.noiselevel >= 1) "\n\tOh, hungry, agrees {the mgr/he}. I thought you were complaining about the music.\n\tHeaven forbid, you say. I am one who delights in all manifestations of the terpsichorean muse.\n\tSorry? \n\tI like a nice dance. You're forced to. you say. "; else "\n\tOh, hungry, says {the mgr/he}.<.p>[Quick cut to a Viking] <.p>\tAnyway... says the Viking.<.p>[Cut back to the shop] <.p>\tStartled, {the mgr/he} looks about. Who said that? "; } ; // This is a mix-in class for the live ActorStates for mgr. class LiveMgr : object verKiss() { logicalRank(110,'sort of cute'); } doKiss() { "Oddly enough, kissing {the dobj/him} is the last thing you want to do. Even if he is sort of cute."; } doSearch() { "{The mgr/he} isn't likely to let you do that."; } verTake() { illogical('Picking up {the dobj/him} isn\'t going to get you any cheese.'); } ; // note: // The 'wensleydale' is added when that cheese is tried. // The 'bloody dead blood/body/corpse' are added when he's killed. mgr : Person 'mr mr. mister man/owner/shopkeeper/seller/proprietor/manager/salesman/himself' name { return self.isProperName ? rand('Wensleydale','Mr.\ Wensleydale') : rand('shopkeeper','proprietor','man','owner','manager','seller','salesman'); } scopeList = (inherited() + me.allCheeses) // acceptCommand(issuingActor) { return true; } globalParamName = 'mgr' actorHereDesc = '' isHim = true desc { curState.desc(); } dobjFor(Attack) { verify() { logicalRank(120,'target'); } action() { curState.doAttack(); } } dobjFor(Kiss) { verify() { curState.verKiss(); } action() { curState.doKiss(); } } dobjFor(Search) { action() { curState.doSearch(); } } dobjFor(ShootAt) { verify() { } /* Find a suitable iobj (weapon). */ action() { askForIobj(ShootAtWith); } } dobjFor(ShootAtWith) { verify() { } action() { actionDobjAttack(); } } dobjFor(ShoutAt) { action() { curState.doShoutAt(); } } dobjFor(Smell) { action() { curState.doSmell(); } } dobjFor(Take) { verify() { curState.verTake(); } } ; + deadShopkeeper: HermitActorState wasKicked = nil desc { "{The mgr/he} lies dead behind the counter. You smile the smile of a job well done. "; } greetingsFrom(actor) { noResponse(); } obeyCommand(issuingActor, action) { noResponse(); return nil; } doAttack { if (wasKicked) "No, that's enough. Remember, you are still a gentleman. Time to leave, I'd say. "; else { wasKicked = true; "You allow yourself one last kick at the corpse to make sure the bastard is dead. He is. He is quite dead. "; } } doEat { "That peckish you are not. "; } verKiss { logicalRank(80,'ugh'); } doKiss { "Death hasn't made him any cuter, y'know. "; } doSearch { "Oh, leave him be. He obviously doesn't have any cheese secreted on his person. "; } doSmell { "Let's not be morbid. "; } verTake { illogical('Yes, it would be jolly to pick up the dead {mgr/him}, take him on holiday overseas and frighten the children, but unfortunately, you have other things to do. '); } doTouch { "There's no pulse. Perhaps it's time to go. "; } noResponse() { "It's a bit late to talk to the ol' beggar now. He's passed on. {The mgr/he} is no more. He has ceased to be. He's expired and gone to meet his maker. He's a stiff. Bereft of life, he rests in peace. He's rung down the curtain and joined the choir invisible. This is an ex-shopkeeper. "; } ; + scaredShopkeeper: HermitActorState, LiveMgr desc { "{The dobj/he} smugly waits for you to select yet another cheese, blithely ignoring the pistol that you're pointing at him. "; } greetingsFrom(actor) { noResponse(); } obeyCommand(issuingActor, action) { noResponse(); return nil; } doAttack() { "...and shoot the pathetic creature:<.p>\t*** BANG! *** "; if (dancers.isIn(inShop)) "<.p>[the music stops] "; "<.p>The body falls to the floor. You shake your head"; if (!dancers.isIn(inShop)) " as you put away your gun"; ".<.p>\tWhat a senseless waste of human life. "; gun.mainMoveInto(nil); mgr.setCurState(deadShopkeeper); mgr.noun += ['corpse', 'body', 'stiff', 'blood']; mgr.adjective += ['bloody', 'dead']; G_dict.addWord(mgr, ['corpse', 'body', 'stiff', 'blood'], &noun); G_dict.addWord(mgr, ['bloody', 'dead'], &adjective); if (dancers.isIn(inShop)) { music.noiselevel = 0; dancers.moveInto(nil); music.moveInto(nil); "<.p>The dancers beat a hasty retreat out the door as you put away your gun. "; } } doSmell() { "Come, come. Gentlepersons such as yourself do not go about smelling other people."; } noResponse() { "The time for talk is over. Now is the time for action. "; } ; ++ ShowTopic @gun "You let the smiling bastard shopkeeper get a good long look at the business end of your pistol, ... " ; + chattyShopkeeper: ActorState, LiveMgr isInitState = true desc { "{The dobj/he} waits patiently for you to select <><.p>"; nestedAction(Think); } greetingsFrom(actor) { if (!cheese.isVague) cheese.handleBuySpecial(); else "You're already talking with {the mgr/him}. "; } obeyCommand(issuingActor, action) { if (action.ofKind(GiveToAction)) return true; "{The mgr/he} refuses your request."; return nil; } doAttack() { if (me.phase >= 28) "Oh, you are sorely tempted, but unfortunately your genteel nature forbids that course of action until all other options are exhausted. But you will get satisfaction from this miserable shopkeeper, in one way or another. "; else if (me.phase >= 18) "{The mgr/he} is an annoying git, but that's no reason to resort to violence. Not yet, anyway. "; else "That's hardly the gentlemanly thing to do. "; } doShoutAt() { "No no no. A gentleman never raises his at a voice to a servant. This is, after all, a battle of wits. If you yelled at him, the shopkeeper would win, and you would lose."; } doSmell() { "Come, come. Gentlepersons such as yourself do not go about smelling other people."; } ; ++ YesNoTopic "\tIf you say so, sir, he says with an unctuous smile. "; ++ AskTopic @area topicResponse() { "You ask {the mgr/him} about the area. <.p>\tBlimey, you ask a lot of questions. I didn't expect the Spanish Inquisition, he says. "; if (inquisition.hasBeenSeen) "\nA voice calls out,<.p>\tBugger off. We're not doing that again. "; else { inquisition.hasBeenSeen = true; "<.p>Suddenly, four men in black robes leap into the shop! <.p>\tNobody expects the Spanish Inquisition! Our chief weapons are...\ are...\ dammit, we're in the wrong sketch again. <.p>They turn around and march out."; } } ; ++ AskTellTopic @breasts "How strange. I feel compelled to ask you about her breasts. \n\tIt wasn't me, sir. I never even knew she had breasts, he says, disingeniously. "; ++ AskTopic @cat "\tYou have a cat? \n\tI got her from a cat detector van. "; ++ AskTellTopic @cheeseshop "\tIt's not much of a cheeseshop really, is it? \n\tFinest in the district, he claims. "; ++ AskTellTopic @counter "\tNice counter you have here, you remark. \n\tHave you noticed how clean it is? "; ++ AskTopic @dancers "\tWhy are there Greek dancers in a cheeseshop? you ask. \n\tThey seem to be here all the time, ever since we got licensed for public dancing. Adds a bit of local colour to the place, wouldn't you say? he says. "; ++ AskTopic @fudges "\tDo you have any fudges? you ask. \n\tI'm sorry, sir, but this is a cheeseshop. We don't have any fudges here, he says, miffed. "; ++ AskTopic @handbell "\tWhat can you tell me about the small handbell? \n\t

C'est Michelle, my bell,

he says proudly. "; ++ AskTopic @inquisition topicResponse() { "\tHave you sold any cheeses to the...\ Spanish Inquisition? "; if (inquisition.hasBeenSeen) "<.p>Before he can reply, a voice calls out,<.p>\tBugger off. We're not doing that again."; else { inquisition.hasBeenSeen = true; "\n\tThe Spanish Inquisition? I didn't expect you to ask about the Spanish Inquisition! he exclaims. <.p>Suddenly, four men in black robes leap into the shop! <.p>\tNobody expects the Spanish Inquisition! Our chief weapons are...\ are...\ dammit, we're in the wrong sketch again.<.p>They turn around and march out."; } } ; ++ AskTopic @lumberjack "\tI beg your pardon. Did you say 'lumberjack'? you ask {the mgr/him}. <.p>\tI didn't want to work in a cheeseshop. I wanted to be a lumberjack. Leaping from tree to tree as they float down the mighty rivers of British Columbia... <.p>His voice trails off as he realizes that no one's going to oblige him with the appropriate sound cue." ; ++ AskTopic @me "You ask {the mgr/him} about yourself. He just smiles back at you."; ++ AskTopic @mgr "You ask {the mgr/him} about himself. <.p>\tSomeday... I'd like to be... a lumberjack! he exclaims." ; ++ AskTopic @monty "You ask {the mgr/him} about Monty Python. <.p>\tWho? he asks, all innocence." ; ++ AskTopic [music, bouzouki] "<= 1 ? '\tDoesn\'t that music bother you at all? you ask. <.p>\tI rather enjoy it. But I expect some music hater will tell them to shut up, sooner or later, he says. ' : 'You\'re no longer interested in the music, now that it\'s stopped. '>>"; ++ AskTopic @viking "\tWhere did that Viking come from? you ask. <.p>\tEr, Viking, sir? he says, solicitously."; ++ DefaultAskForTopic topicResponse() { // "[TEST DefaultAskForTopic] "; mgrAskTopic.topicResponse(); } ; ++ mgrAskTopic : DefaultAskTopic topicResponse() { if (gTopic.inScopeList.length() > 1) { local lst = gTopic.inScopeList.subset( {o: !o.ofKind(CheeseTopic) || o.asked}); gTopic.likelyList += lst; gTopic.inScopeList -= lst; } local topic = gTopic.getBestMatch(); if (topic == itTopic) topic = me.getPronounAntecedent(PronounIt); if (topic && topic.ofKind(Thing)) { if (topic.ofKind(CheeseTopic)) topic.handleBuy(); else "You ask {the mgr/him} about <>, but he acts like he didn't even hear your question."; } else { "You ask {the mgr/him} about << gTopic.getTopicText() >>, but he acts like he didn't even hear your question."; } } ; area : Topic 'these area/district*parts' ; breasts : Topic 'her breasts' ; cat : Topic 'cat' ; fudges : Topic 'fudge*fudges' ; inquisition : Topic 'spanish inquisition' hasBeenSeen = nil ; lumberjack : Topic 'lumberjack' ; monty : Topic 'monty python python\'s flying circus' ; viking : Topic 'viking' ; class CheeseTopic: Thing '(cheese)' isKnown = true // see topic.t; if not known, we can't ask about it. isMassName = true isProperName = true asked = nil isVague = nil dobjFor(GiveTo) { preCond = (gActor == mgr ? [] : inherited()) verify() { if (gActor != mgr) inherited(); } } handleBuy() { me.setIt(self); if (isVague) { "\tAny <>? you say.\n\tThe owner almost looks apologetic. Er, could you be more specific, sir? he asks, unhelpfully.<.p>"; nestedAction(Think); } else if (asked) { "You've already tried <>. Think of another cheese.<.p>"; nestedAction(Think); } else handleBuySpecial(); } handleBuySpecial() { switch (me.phase) { case 1: me.phase = 2; asked = true; "\tWell, how about a little <>? you ask. \n\tI'm afraid we're fresh out of <>, sir. \n\tOh never mind, you say, unconcerned. "; break; case 2: me.phase = 3; asked = true; "\tHow are you on <>? you ask. \n\tNever at this part of the week, sir. Always get it fresh first thing on Monday.\n\tTish, tish. No matter. "; break; case 3: me.phase = 4; asked = true; "\tWell, four ounces of <>, then, if you please, stout yeoman.\n\tAh, well, it's been on order for two weeks, sir, {the mgr/he} replies. I was expecting it this morning. \n\tYes, it's not my day is it, you say ruefully. "; break; case 4: me.phase = 5; asked = true; "\tEr, <>? you try.\n\tSorry. "; break; case 5: me.phase = 6; asked = true; "\t<>? you ask.\n\tNormally, sir, yes, but today the van broke down. "; break; case 6: me.phase = 7; asked = true; "\tAh. <>? you ask.\n\tSorry. "; break; case 8: me.phase++; asked = true; "\tAny <>? you try.\n\tNo. "; break; case 13: me.phase = 14; asked = true; "\tAny <>? you ask.\n\t....No. "; break; case 15: me.phase = (camembert.askCount == 0) ? 16 : 19; asked = true; "\tAny <>? you try.\n\tNo. "; break; case 16: // duplicates Camembert stage one camembert.askCount++; me.phase = 19; asked = true; me.setIt(camembert); "\tYou recite, <>, << camembert.calcCamembertList >>Camembert? \n\t{The mgr/he} brightens. Ah! We do have some Camembert, sir. \n\tYou do. Excellent, you say.\n\t{The mgr/he} hesitates. It's a bit runny, sir. "; break; case 23: me.phase = 24; asked = true; "\t<>? you ask.\n\tNo, sir. "; break; case 24: // NOTE: phase 26 (identical to phase 7) is called directly // after phase 24. Phase 25 is Wensleydale. me.phase = 27; asked = true; "\tYou do have some cheese, do you? you inquire. \n\tCertainly, sir. It's a cheese shop, sir. We've got... \n\tNo, no, no, don't tell me. I'm keen to guess. \n\tFair enough. \n\t<>? you ask.\n\tNo. "; break; case 30: me.phase = 31; asked = true; "\t<>? you ask.\n\tNot today, sir, no. "; break; case 31: // force asking of Cheddar instead of cheese chosen. cheddar.handleBuySpecial(); break; case 32: // Try to get the player to ask for "most popular cheese" // Let him be stuck for ten turns, then go on as if he asked anyway. if (popular.number < 10) { asked = true; popular.number++; "\tAny <>? you ask.\n\tNo. Then {the mgr/he} "; say(rand([ 'prompts, Don\'t you want to ask me what the most popular cheese is? ', 'says, That\'s not popular around these parts either. ', 'remarks, Is that cheese popular elsewhere? ' ])); } if (popular.number >= 10) { "<.p>You grimace. The shopkeeper must really want you to ask what's popular.<.p>"; popular.handleBuySpecial(); } break; case 33: // If player tried a cheese other than "Ilchester", prompt him!! if (self != me.ilchesterMimic) "Good god! Stop the insanity! Buy << me.ilchesterMimic.name >>! "; else { me.phase = 34; asked = true; "\tOK, I'm game. Have you got any << self.name >>, he asked, expecting the answer no?\n\tI'll have a look, sir, ... nnnnnnooooooooo. \n\tIt's not much of a cheese shop really, is it? you observe. \n\tFinest in the district, sir, {the mgr/he} claims. \n\tAnd what leads you to that conclusion? you ask. \n\tWell, {the mgr/he} sputters, it's so clean. \n\tWell, you say, it's certainly uncontaminated by cheese. "; } break; case 34: me.phase = 35; asked = true; calcLimburger(); "\t<>?, you ask, without any real hope. \n\tSorry, says {the mgr/he}. Then he points out, You haven't asked me about << me.limburgerMimic.name >>, sir. \n\tYou hestitate. Is it worth it? \n\tCould be, he says temptingly. "; break; case 35: // If Player tried a cheese other than "Limburger", prompt him!! if (self != me.limburgerMimic) "But the shopkeeper might have << me.limburgerMimic.name >>! Don't drag this out any longer! "; else { me.phase = 36; asked = true; "\tYou ask, Have you got any << self.name >>?\n\tNo. \n\tNo, that figures. It was pretty predictable really. It was an act of pure optimism to pose the question in the first place. Tell me something, do you have any cheese at all?\n\tYes, sir, says {the mgr/he}. "; } break; case 36: // Prompt the player to ASK FOR ANY CHEESE "After all you've been through, do you really believe there's any cheese at all here? Ask {the mgr/he} for any cheese. "; break; default: // case 7, 9, 10, 11, 12, 14, 19, 20, 21, 22, 27, 28, 29: me.phase++; asked = true; "\t<>? you ask.\n\tNo. "; break; } } ; function calcIlchester() { if (!ilchester.asked) me.ilchesterMimic = ilchester; else { for (local x = firstObj(CheeseTopic); x; x = nextObj(x, CheeseTopic)) { if (!x.asked && !x.isVague && x not in (wensleydale, cheddar, camembert, cheese, popular, anyCheese, limburger)) { me.ilchesterMimic = x; break; } } } } function calcLimburger() { if (!limburger.asked) me.limburgerMimic = limburger; else { for (local x = firstObj(CheeseTopic); x; x = nextObj(x, CheeseTopic)) { if (!x.asked && !x.isVague && x not in (wensleydale, cheddar, camembert, cheese, popular, anyCheese, ilchester)) { me.limburgerMimic = x; break; } } } } redLeicester : CheeseTopic 'red leicester -' 'Red Leicester' ; tilsit : CheeseTopic 'tilsit -' 'Tilsit' ; caerphilly : CheeseTopic 'caerphilly -' 'Caerphilly' ; belPaese : CheeseTopic 'bel paese/pease/bel-paese/bel-pease' 'Bel Paese' ; redWindsor : CheeseTopic 'red windsor -' 'Red Windsor' ; stilton : CheeseTopic 'stilton -' 'Stilton' ; gruyere : CheeseTopic 'gruyere -' 'Gruyère' ; emmental : CheeseTopic '(swiss) emmental -' 'Emmental' ; njarls : CheeseTopic 'norwegian jarlsberger jarlsburg -' 'Norwegian Jarlsberger' ; liptauer : CheeseTopic 'liptauer -' 'Liptauer' ; lancashire : CheeseTopic 'lancashire -' 'Lancashire' ; whiteStilton : CheeseTopic 'white (stilton) -' 'White Stilton' ; danishBlue : CheeseTopic 'danish blue -' 'Danish Blue' ; dgloucester : CheeseTopic 'dg double gloucester -' 'Double Gloucester' ; cheshire : CheeseTopic 'cheshire -' 'Cheshire' ; dorset : CheeseTopic 'dorset blue vinney dbv -' 'Dorset Blue Vinney' ; brie : CheeseTopic 'brie -' name = "Brie" ; rocquefort : CheeseTopic 'rocquefort roquefort -' 'Rocquefort' ; pont : CheeseTopic 'pont-l\'eveque pont l\'eveque eveque - ' 'Pont-l\'Évêque' ; portSalut : CheeseTopic 'port-salut port salut -' 'Port Salut' ; savoyard : CheeseTopic 'savoyard -' 'Savoyard' ; stPaulin : CheeseTopic 'st saint paulin saint-paulin st-paulin st.-paulin -' 'Saint-Paulin'; carre : CheeseTopic 'carre-de-l\'est carre de l\'est est de-l\'est -' 'Carre-de-L\'Est' ; boursin : CheeseTopic 'boursin -' 'Boursin' ; wensleydale : CheeseTopic 'wensleydale -' 'Wensleydale' handleBuySpecial() { asked = true; mgr.isProperName = true; mgr.noun += ['wensleydale']; G_dict.addWord(mgr, ['wensleydale'], &noun); "\tWensleydale? you ask.\n\tYes, sir?<.p>You smile. <.p>\tSplendid. Well, I'll have some of that then, please. \n\tOh, I'm sorry, sir. I thought you were referring to me, Mr.\ Wensleydale.<.p>You stop smiling. "; } ; bresse : CheeseTopic 'bresse-bleue bresse bleue -' 'Bresse-Bleue'; perle : CheeseTopic 'perle de champagne -' 'Perle de Champagne' ; camembert : CheeseTopic 'cam camembert -' 'Camembert' askCount = 0 // how many times was Camembert asked? calcCamembertList() { local validCheeses = me.allCheeses.subset({ o: !o.asked && !o.isVague && o not in (wensleydale, cheddar, camembert, ilchester, limburger, anyCheese, popular, cheese) }); for (local i = 0; i < 9; i++) { local o = rand(validCheeses); "<>, "; o.asked = true; validCheeses -= o; } } handleBuySpecial() { if (me.phase < 4) { "You're about to ask for camembert, but then reconsider. You've hardly asked for any cheeses at all. Might there not be more exotic cheeses? You can always ask about camembert later, if the shop doesn't have your first few choices.<.p>"; nestedAction(Think); return; } switch (askCount) { case 0: // phase 16 askCount++; me.phase = 19; me.setIt(self); "\tYou recite, << calcCamembertList >>Camembert? \n\t{The mgr/he} brightens. Ah! We do have some Camembert, sir. \n\tYou do. Excellent, you say.\n\t{The mgr/he} hesitates. It's a bit runny, sir. "; break; case 1: // phase 17 askCount++; "\tOh, I like it runny, you say with considerable relish. \n\tWell, as a matter of fact, it's very runny, sir, {the mgr/he} cautions.\n\tNo matter, no matter, you reply. Hand over the fromage de la Belle France qui s'appelle Camembert, s'il vous plaît. \n\tI think it's runnier than you like it, sir, {the mgr/he} warns. "; break; case 2: // phase 18 askCount++; asked = true; "\tI don't care how fucking runny it is. Hand it over with all speed, you demand.\n\tYes, sir.<.p>{The mgr/he} bends down below the counter and reappears.<.p>\tOh..., he says.\n\tWhat? The cat's eaten it. Has he? She, sir. "; break; } } ; gouda : CheeseTopic 'dutch gouda -' 'Gouda'; edam : CheeseTopic 'dutch edam -' 'Edam'; caithness : CheeseTopic 'caithness -' 'Caithness'; smoked : CheeseTopic 'smoked austrian -' 'Smoked Austrian'; sage : CheeseTopic 'sage derby -' 'Sage Derby'; gorgonzola : CheeseTopic 'gorgonzola -' 'Gorgonzola'; parmesan : CheeseTopic 'parmasan parmesan -' 'Parmesan'; mozza : CheeseTopic 'mozza mozzarella -' 'Mozzarella'; pippo : CheeseTopic 'pippo creme -' 'Pippo Creme'; danishFimboe : CheeseTopic 'danish fimboe -' 'Danish Fimboe'; czech : CheeseTopic 'csmc czech czechoslovakian sheep sheep\'s milk -' 'Czechoslovakian Sheep\'s Milk Cheese'; venez : CheeseTopic 'venez vbc venezuelan beaver -' 'Venezuelan Beaver Cheese'; cheddar : CheeseTopic 'cheddar american canadian -' 'Cheddar' handleBuySpecial() { if (me.phase < 20) { "Not yet! Asking for cheddar this early would be an admission of defeat. Surely a cheeseshop has more than just cheddar! Consider all the cheeses that a cheeseshop might have!<.p>"; nestedAction(Think); } else { me.phase = 32; cheddar.asked = true; "You decide to cut to the chase.<.p>\tWell, let's keep it simple. How about Cheddar?\n\tWell, I'm afraid we don't get much call for it around these parts.\n\tYou're flabbergasted. No call for it? It's the single most popular cheese in the world! \n\tNot round these parts, sir, says {the mgr/he} with a straight face. "; } } ; feta : CheeseTopic 'feta -' 'Feta'; provolone : CheeseTopic 'provolone -' 'Provolone'; raclette : CheeseTopic 'raclette -' 'Raclette'; romano : CheeseTopic 'romano -' 'Romano'; bleu : CheeseTopic 'blue bleu -' 'Bleu'; finlandia : CheeseTopic 'finlandia (swiss) -' 'Finlandia Swiss'; cottage : CheeseTopic 'cottage -' 'Cottage Cheese'; swinzie : CheeseTopic 'swinzie -' 'Swinzie'; havarti : CheeseTopic 'cream havarti -' 'Havarti'; allerdale : CheeseTopic 'allerdale -' 'Allerdale'; asiago : CheeseTopic 'asiago -' 'Asiago'; appenzeller : CheeseTopic 'appenzeller -' 'Appenzeller'; bath : CheeseTopic 'bath -' 'Bath Cheese'; baylough : CheeseTopic 'baylough' name = "Baylough"; bishop : CheeseTopic 'bishop kennedy bishop-kennedy -' 'Bishop Kennedy'; blueCastello : CheeseTopic 'blue castello -' 'Blue Castello'; blueShropshire : CheeseTopic 'blue shropshire -' 'Blue Shropshire'; bonchester : CheeseTopic 'bonchester -' 'Bonchester'; bonnet : CheeseTopic 'bonnet -' 'Bonnet'; boursault : CheeseTopic 'boursault -' 'Boursault'; brodick : CheeseTopic 'brodick -' 'Brodick'; brodickBlue : CheeseTopic '(brodick) blue -' 'Brodick Blue'; cabrales : CheeseTopic 'cabrales -' 'Cabrales'; caboc : CheeseTopic 'caboc -' 'Caboc'; cairnsmore : CheeseTopic 'cairnsmore -' 'Cairnsmore'; calahora : CheeseTopic 'calahora -' 'Calahora'; celtic : CheeseTopic 'celtic promise -' 'Celtic Promise'; cerney : CheeseTopic 'cerney -' 'Cerney'; colby : CheeseTopic 'colby -' 'Colby'; comte : CheeseTopic 'comte -' 'Comte'; coolea : CheeseTopic 'coolea -' 'Coolea'; coulommiers : CheeseTopic 'coulommiers -' 'Coulommiers'; crottin : CheeseTopic 'crottin du chavignol -' 'Crottin du Chavignol'; crowdie : CheeseTopic 'crowdie -' 'Crowdie'; devon : CheeseTopic 'devon cream -' 'Devon Cream'; dolcelate : CheeseTopic 'dolcelate -' 'Dolcelate'; dworcester : CheeseTopic 'double dw worcester worchester -' 'Double Worcester'; dunburra : CheeseTopic 'dunburra -' 'Dunburra'; dunlop : CheeseTopic 'dunlop -' 'Dunlop'; dunsyre : CheeseTopic 'dunsyre blue -' 'Dunsyre Blue'; dryJack : CheeseTopic 'dry jack -' 'Dry Jack'; swiss : CheeseTopic 'swiss -' 'Swiss'; fontal : CheeseTopic 'fontal -' 'Fontal'; fontina : CheeseTopic 'fontina -' 'Fontina'; aosta : CheeseTopic 'fontina val d\'aosta aosta -' 'Fontina Val d\'Aosta'; freshJack : CheeseTopic 'fresh jack -' 'Fresh Jack'; gjetost : CheeseTopic 'gjetost -' 'Gjetost'; grana : CheeseTopic 'grana padano -' 'Grana Padano'; gourmandise : CheeseTopic 'gourmandise -' 'Gourmandise'; gubbeen : CheeseTopic 'gubbeen -' 'Gubbeen'; halloumi : CheeseTopic 'halloumi -' 'Halloumi'; howgate : CheeseTopic 'howgate -' 'Howgate'; huntsman : CheeseTopic 'huntsman -' 'Huntsman'; ilchester : CheeseTopic 'ilchester -' 'Ilchester'; // TODO calcval ilchester; innesButton : CheeseTopic 'innes button -' 'Innes Button'; isle : CheeseTopic 'isle of mull -' 'Isle of Mull'; iverlock : CheeseTopic 'iverlock -' 'Iverlock'; jermi : CheeseTopic 'jermi torte -' 'Jermi Torte'; kasseri : CheeseTopic 'kasseri -' 'Kasseri'; kefalotyri : CheeseTopic 'kefalotyri -' 'Kefalotyri'; kelsae : CheeseTopic 'kelsae kelsea -' 'Kelsae'; knockalara : CheeseTopic 'knockalara -' 'Knockalara'; lanarkBlue : CheeseTopic 'lanark blue -' 'Lanark Blue'; lappi : CheeseTopic 'lappi -' 'Lappi'; leyden : CheeseTopic 'leyden -' 'Leyden'; limburger : CheeseTopic 'limburger limberger -' 'Limburger'; // TODO calcval limburger; lochArthur : CheeseTopic 'loch arthur -' 'Loch Arthur'; maasdam : CheeseTopic 'maasdam -' 'Maasdam'; malvern : CheeseTopic 'malvern -' 'Malvern'; manchego : CheeseTopic 'manchego -' 'Manchego'; mascarpone : CheeseTopic 'mascarpone -' 'Mascarpone'; mimolette : CheeseTopic 'mimolette -' 'Mimolette'; mizithra : CheeseTopic 'mizithra -' 'Mizithra'; monterey : CheeseTopic 'pepper monteray monterey jack -' 'Monterey Jack'; morbier : CheeseTopic 'morbier -' 'Morbier'; munster : CheeseTopic 'munster muenster -' 'Munster'; orla : CheeseTopic 'orla -' 'Orla'; pantYsGawn : CheeseTopic 'pant ys gawn -' 'Pant ys Gawn'; pecorino : CheeseTopic 'pecorino (romano) -' 'Pecorino Romano'; pentland : CheeseTopic 'pentland -' 'Pentland'; petitBasque : CheeseTopic 'petit basque -' 'Petit Basque'; petitMorin : CheeseTopic 'petit morin -' 'Petit Morin'; reggiano : CheeseTopic 'parmigiano reggiano -' 'Parmigiano Reggiano'; pouligny : CheeseTopic 'pouligny-saint-pierre saint-pierre st-pierre pouligny saint st pierre -' 'Pouligny-Saint-Pierre'; quesoVare : CheeseTopic 'queso vare -' 'Queso Vare'; reblochon : CheeseTopic 'reblochon -' 'Reblochon'; reggianito : CheeseTopic 'reggianito -' 'Reggianito'; ricotta : CheeseTopic 'ricotta -' 'Ricotta'; ricottaSalata : CheeseTopic '(ricotta) salata -' 'Ricotta Salata'; romany : CheeseTopic 'romany -' 'Romany'; saga : CheeseTopic 'saga -' 'Saga'; salers : CheeseTopic 'salers -' 'Salers'; sardo : CheeseTopic 'sardo -' 'Sardo'; serraDaEstrela : CheeseTopic 'serra da estrela -' 'Serra da Estrela'; st_agur : CheeseTopic 'st saint agur saint-agur st-agur -' 'Saint-Agur'; stAndre : CheeseTopic 'st saint andre saint-andre st-andre -' 'Saint-Andre'; stAndrews : CheeseTopic 'st saint andrews saint-andrews st-andrews -' 'Saint-Andrews'; stMarcellin : CheeseTopic 'st saint marcellin saint-marcellin st-marcellin -' 'Saint-Marcellin'; stNectaire : CheeseTopic 'st saint nectaire saint-nectaire st-nectaire -' 'Saint-Nectaire'; sapsago : CheeseTopic 'sapsago -' 'Sapsago'; staffordshire : CheeseTopic 'garlic staffordshire -' 'Staffordshire'; stichill : CheeseTopic 'stichill -' 'Stichill'; stinking : CheeseTopic 'stinking bishop -' 'Stinking Bishop'; strath : CheeseTopic 'strathkinness -' 'Strathkinness'; sussex : CheeseTopic 'sussex slipcote -' 'Sussex Slipcote'; taleggio : CheeseTopic 'taleggio -' 'Taleggio'; teviotdale : CheeseTopic 'teviotdale -' 'Teviotdale'; tomme : CheeseTopic 'tomme de savoie -' 'Tomme de Savoie'; trouDuCru : CheeseTopic 'trou du cru -' 'Trou du Cru'; turunmaa : CheeseTopic 'turunmaa -' 'Turunmaa'; vieux : CheeseTopic 'vieux corse -' 'Vieux Corse'; yarg : CheeseTopic 'yarg -' 'Yarg'; yorkshire : CheeseTopic 'yorkshire blue -' 'Yorkshire Blue'; zamorano : CheeseTopic 'zamorano -' 'Zamorano'; buffalo : CheeseTopic 'buffalo -' 'Buffalo Cheese'; blueStilton : CheeseTopic 'blue (stilton) -' 'Blue Stilton'; somersetBrie : CheeseTopic 'somerset (brie) -' 'Somerset Brie'; charnwood : CheeseTopic 'charnwood smoked (cheddar) -' 'Charnwood Smoked Cheddar'; chevre : CheeseTopic 'chevre -' 'chevre' isVague = true; goat : CheeseTopic 'goat -' 'goat cheese' isVague = true; cream : CheeseTopic 'cream -' 'cream cheese' isVague = true; anyCheese : CheeseTopic 'any cheese at all' 'any cheese at all' handleBuySpecial() { if (me.phase != 36) { "As a cheese connoisseur, it is beneath you to ask directly for any cheese at all. It is for you to decide what cheese you want, not a shopkeeper's. Only in the most extreme circumstances, such as a cheeseshop with no cheese at all, would you consider asking such an audacious question.<.p>"; nestedAction(Think); } else { gun.mainMoveInto(me); me.phase = 37; mgr.setCurState(scaredShopkeeper); "\tYou calmly tell {the mgr/him}, Now I'm going to ask you that question once more, and if you say no I'm going to shoot you through the head. Now, do you have any cheese at all?\n\tNo. <.p>You draw a gun, ... "; } } ; popular : CheeseTopic 'most popular -' 'most popular cheese' number = 0 /* number of turns wasted not asking for it */ handleBuySpecial() { if (me.phase != 32) { "Popular cheese? What gave you that notion? The shopkeeper hasn't mentioned anything like that yet.<.p>"; nestedAction(Think); } else { me.phase = 33; popular.asked = true; calcIlchester(); "<.p>\tAnd pray, what is the most popular cheese round these parts? \n\t<< me.ilchesterMimic.name >>, sir, says {the mgr/he} proudly. \n\tI see, you say evenly. \n\tYes, sir. It's quite staggeringly popular in the manor. \n\tIs it?\n\tYes sir, repeats {the mgr/he}. It's our number-one seller. \n\tIs it? you ask again.\n\tYes, sir. \n\t<< me.ilchesterMimic.name >>, eh? you ask, just to be quite sure. \n\tRight, {the mgr/he} confirms. "; } } ; DefineTopicAction(Buy) execAction() { if (me.isIn(outShop)) "There's nothing for sale here outside the shop. Try going inside. "; else { if (gTopic.inScopeList.length() > 1) { local lst = gTopic.inScopeList.subset( {o: !o.ofKind(CheeseTopic) || o.asked}); gTopic.likelyList += lst; gTopic.inScopeList -= lst; } local obj = gTopic.getBestMatch(); if (obj == itTopic) obj = me.getPronounAntecedent(PronounIt); if (obj && obj.ofKind(CheeseTopic)) { if (!mgr.isIn(inShop)) "You don't see the shopkeeper here. Perhaps he can be summoned, somehow. "; else obj.handleBuy(); } else if (obj == mgr) "He's not for sale."; else if (obj == dancers) "They're not for sale."; else if (obj == me) "You're not for sale."; else "That's not for sale. "; } } ; modify InventoryAction execAction() { "<' >> You are impeccably dressed in a nice business suit, and you're carrying the things you usually carry. To wit: a wallet (with enough money in it to buy some delicious cheese), your keys (for a house that doesn't appear in this game), a pen, some headache pills, a hanky,... <> None of which you can or need to refer to in this game. <> <.p><>You also have a craving for cheese. <>"; } ; DefineIAction(Dance) execAction() { "You dance about the room, in an apparent audition for the Ministry of Silly Dances. "; } ; DefineTAction(Ring); DefineIAction(ShootNil) execAction() { askForDobj(ShootAt); } ; DefineTAction(Shoot); DefineTAction(ShootAt); DefineTAction(ShootWith); DefineTIAction(ShootAtWith); DefineTAction(ShoutAt); DefineIAction(ShutUp) execAction() { if (gActor == dancers) dancers.doShoutedAt(); else "Try telling someone else that. "; }; DefineIAction(Sing) execAction() { "You haven't sang in public since that incident in Liverpool, and you're not about to start now. "; } ; DefineIAction(Think) execAction() { local validCheeses = me.allCheeses.subset({ o: !o.asked && !o.isVague && o != cheese }); "(hmmm... what about "; for (local i = 0; i < 9; i++) { local o = rand(validCheeses); "<>, "; validCheeses -= o; } "...?) "; } ; DefineIAction(Xyzzy) execAction() { "A hollow voice says, Xyzzy? Tinny, tinny sort of word. <.p>Then a sixteen-ton weight drops on your head. "; endGame(youLost,'You have died','Ouch. How depressing. '); } ; VerbRule(Dance) 'dance' : DanceAction verbPhrase = 'dance/dancing' ; VerbRule(Buy) ('buy' | 'purchase') singleTopic : BuyAction verbPhrase = 'buy/buying (what)' ; VerbRule(Ring) 'ring' singleDobj : RingAction verbPhrase = 'ring/ringing (what)' ; /* SHOOT */ VerbRule(ShootNil) 'shoot' | 'fire' : ShootNilAction verbPhrase = 'shoot/shooting'; /* SHOOT GUN or SHOOT MAN */ VerbRule(Shoot) 'shoot' singleDobj : ShootAction verbPhrase = 'shoot/shooting (what)' ; /* SHOOT AT MAN */ VerbRule(ShootAt) ('shoot' | 'fire') 'at' singleDobj : ShootAtAction verbPhrase = 'shoot/shooting at (what)' ; // construct() { // /* These two lines makes the parser ask for an object. */ // iobjMatch = new EmptyNounPhraseProd(); // iobjMatch.responseProd = withSingleNoun; // } /* SHOOT WITH GUN. */ VerbRule(ShootWith) (('shoot' | 'fire') 'with' | 'fire') singleDobj : ShootWithAction verbPhrase = 'fire/firing (what)' ; /* SHOOT MAN (dobj) WITH GUN (iobj) */ VerbRule(ShootAtWith) ('shoot' | 'fire') ('at'|) singleDobj 'with' singleIobj : ShootAtWithAction verbPhrase = 'shoot/shooting at (what) with (what)' ; /* SHOOT GUN (iobj) AT MAN (dobj) */ VerbRule(ShootWithAt) ('shoot' | 'fire') ('with'|) singleIobj 'at' singleDobj : ShootAtWithAction verbPhrase = 'shoot/shooting at (what) with (what)' ; VerbRule(ShoutAt) ('shout' | 'yell') 'at' singleDobj: ShoutAtAction verbPhrase = 'shout/shouting at (what)' ; VerbRule(ShutUp) 'be' 'quiet' | 'shut' 'up' | 'shh' | 'shush' | 'hush' | 'quiet' | ('stop'|'halt'|'end'|'quiet'|'shut') ('the'|'your'|'that'|) ('bloody'|) ('goddamn'|'god' 'damn'|'damn'|) ('fuck'|'fucking'|) ('dancing'|'music'|'racket'|'noise') ('up'|) : ShutUpAction verbPhrase = 'shut/shutting up' ; VerbRule(Sing) 'sing' : SingAction verbPhrase = 'sing/singing' ; VerbRule(Think) 'think' : ThinkAction verbPhrase = 'think/thinking' ; VerbRule(Xyzzy) 'xyzzy' : XyzzyAction verbPhrase = 'say/saying XYZZY' ; modify Thing dobjFor(Ring) { verify() { illogical('{You/he} do{es}n\'t know how to ring {that dobj/him}. '); } } /* For most Things, SHOOT X means SHOOT AT X. */ dobjFor(Shoot) asDobjFor(ShootAt) dobjFor(ShootAt) { verify() { illogical('{The dobj/him} {is}n\'t a suitable target. '); } } dobjFor(ShootWith) { preCond = [objHeld] verify() { illogical('{You/he} can\'t shoot anything with {the dobj/him}. You want to use a gun. '); } } dobjFor(ShootAtWith) { verify() { illogical('{The dobj/him} {is}n\'t a suitable target. '); } } iobjFor(ShootAtWith) { preCond = [objHeld] verify() { illogical('{You/he} can\'t shoot anything with {the iobj/him}. You want to use a gun. '); } } dobjFor(ShoutAt) { verify() { if (self.ofKind(Person)) logicalRank(100,'human'); else illogical('Maddingly, {the dobj/he} do{es}n\'t respond to your shouting. '); } } handleBuy = "You were looking for cheese, not <>. " ; //modify libScore // showScore() { "There is no score in this game. "; } //; /* * A dummy Topic to represent the concept of "it". */ itTopic: Topic 'it'; /* * Define the player character. The name of this object is not * important, but note that it has to match up with the name we use in * the main() routine to initialize the game, below. * * Note that we aren't required to define any vocabulary or description * for this object, because the class Actor, defined in the library, * automatically provides the appropriate definitions for an Actor when * the Actor is serving as the player character. Note also that we * don't have to do anything special in this object definition to make * the Actor the player character; any Actor can serve as the player * character, and we'll establish this one as the PC in main(), below. */ me : Person 'me/myself/mousebender' 'Mr. Mousebender' @outShop pcDesc = "You, Mr.\ Mousebender, are an English gentleman, in search of cheesy comestibles. In other words, you wish to buy some cheese." didInv = nil /* have you done 'inventory' yet? */ phase = 1 /* where we are in the conversation */ ilchesterMimic = nil /* which cheese plays Ilchester's role? */ limburgerMimic = nil /* which cheese plays Limburger's role? */ allCheeses = [] /* init'd in main */ dobjFor(ShoutAt) { action() { "You are about to yell imprecations at yourself, when you remember your promise to Greta that you wouldn't do that to yourself. So you don't."; } } ; // actorAction() { // if (self.isIn(inShop) && dancers.isIn(inShop)) // extraReport('Ding dang blim blam!\b'); // } + misc : Decoration 'business suit/wallet/money/cash/key/pen/hanky/hankerchief/craving/headache/miscellany*keys pills' 'your possessions' "You don't need to refer to that in this game. " aName = 'your possessions' theName = 'your possessions' isPluralName = true checkMoveViaPath(obj, dest, op) { if (obj == self && dest != gPlayerChar) return new CheckStatusFailure('You don\'t need to refer to that in this game. '); return checkStatusSuccess; } ; gun : Thing 'six gun/pistol/weapon/shooter/six-shooter' 'gun' "<>" hasBeenExamined = nil checkMoveViaPath(obj, dest, op) { if (obj == self && dest != gPlayerChar) return new CheckStatusFailure('On second thought, you decide to keep the gun. '); return checkStatusSuccess; } /* For a gun, Shoot means Shoot With. */ dobjFor(Shoot) asDobjFor(ShootWith) dobjFor(ShootWith) { verify() { } /* Find a suitable dobj (target), making me iobj. */ action() { askForDobj(ShootAtWith); } } iobjFor(ShootAtWith) { verify() { } /* We let the dobj (target) handle the shooting. */ } ; /* before [; Drop, Give, Insert, PutOn, Transfer, ThrowAt: " On second thought, you decide to keep the gun."; ], has shootable; */ /* * Main entrypoint. After the library finishes initializing, it calls * this routine. This function orchestrates the entire execution of the * game; when this function returns, the program terminates. * * 'args' contains a list of strings giving the command-line arguments * that the player used to start the game from the operating system * command shell. At a minimum, this will contain one element giving * the name of the image (.t3) file being executed. * * Our implementation here is simple: we display an introductory * message, then we call runGame(), a library routine that does all of * the work involved in running the game. The runGame() function * doesn't return until the game ends (for example, when the player * types QUIT). */ main(args) { /* simply invoke our common "main" routine with no saved game file */ mainCommon(args, nil); } /* * Main *restore* entrypoint. This is called instead of main() when a * player launches the interpreter using a saved-game file. For example, * on a command-line system, this is done by running a command such as * "t3run -r save1.t3v". On a GUI system, this is usually invoked by * double-clicking on a saved-game file from the desktop. * * When we launch directly from a saved-game file, we'll simply try to * restore the saved game, and run the normal command loop. */ mainRestore(args, restoreFile) { /* invoke our common "main" routine with the saved game file */ mainCommon(args, restoreFile); } /* * Common main entrypoint. This has all of our main game handling, for * both the normal case where we're launching a new session with the * game, and for the "restore" case where we're launching directly from a * saved-game file. */ mainCommon(args, restoreFile) { /* set the interpreter window title (if applicable on this platform) */ "<<versionInfo.name>>"; /* check to see if we're restoring or starting a brand new session */ if (restoreFile == nil) { /* starting a new session - show our introductory message */ "Cheeseshop\n An interactive re-creation of the famous Cheeseshop sketch by Monty Python's Flying Circus.\n Program code by David Welbourn (dswxyz@look.ca).\n (Type ABOUT if you wish to learn a little more about this game.)\b"; /* set the initial player character to the "me" object */ gPlayerChar = me; /* kludgy to do it here, but: */ cheese.weakTokens = nil; /* Turn off scoring. */ libGlobal.scoreObj = nil; /* Build me.allCheeses */ me.allCheeses = []; for (local o = firstObj(CheeseTopic); o; o = nextObj(o, CheeseTopic)) me.allCheeses += o; } else { /* restoring a saved game - mention that we're restoring the file */ "Restoring saved game...\n"; /* try restoring the saved position */ local succ = RestoreAction.startupRestore(restoreFile); /* show a blank line after the restore result message */ "\b"; /* if the restore failed, abort the session */ if (!succ) return; } /* * Run the game. Only show the room description if we're starting a * new session, since we'll already have shown the description if we * restored a game. */ runGame(restoreFile == nil); /* the game is now over - show our farewell message */ "<.p>Thanks for playing!\b"; }