#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
#include "AHA.h"

/* OldHell.t */

class MazeRoom : Room 'Labyrinth' 'the labyrinth'
    "You are in a <<epithet>> labyrinth, with confusing passages leading off in
    all directions -- so confusing that you can't even be sure which direction
    is which, and you're forced to label them arbitrarily. Between two of the
    exits is fixed a large sign. <<extraDesc>>"
    epithet = ''
    extraDesc = nil
    nextRoom = nil
    north = nextRoom
    northeast = nextRoom
    east = nextRoom
    southeast = nextRoom
    south = nextRoom
    southwest = nextRoom
    west = nextRoom
    northwest = nextRoom
    thinkHere = "You think that one direction looks as good as any other from
        here. "
    roomAfterAction()
    {
        if(gActionIs(Yell))
            "The reverberations of your voice echo mockingly from one exit to
            the next. ";
    }
    roomBeforeAction()
    {
        if(gActionIs(GoBack))
        {
            "You head back down what you\'re fairly convinced was the way you
            came, but so confusing is the labyrinth that you <<self==maze1 ?
              'land up somewhere else' : 'can\'t be absolutely sure'>>. ";
            replaceAction(North);
        }
    }
    lookDirToRoomPart(dirn) { return dirn is in (upDirection, downDirection); }
    defaultLook(dir)
    {
        "You're not really sure which direction is which, but there are
        confusing passages leading off from here whichever way you look. ";
    }
;

maze1: MazeRoom 
    epithet = 'diabolical'
    nextRoom = maze2
    
    vocabWords = 'maze'
;

class AgrathSign: CustomFixture
    cannotTakeMsg = 'It won\'t budge. '
    nothingBehindMsg = 'You can\'t see what\'s behind it, but the more urgent
        question is surely <i>who\'s</i> behind it. '
    shouldNotBreakMsg = 'It\'s harder than diamond. '
    uselessToAttackMsg = (shouldNotBreakMsg) 
;

+ AgrathSign 'large sign' 'large sign'
    "It reads:\n
    AGRATH'S LABYRINTH.\n
    Abandon hope all ye who enter here\n
    For now you never shall avoid my lair.<.reveal agrath>" 
;

maze2: MazeRoom 
    epithet = 'devilish'
    nextRoom = maze3
;

+ AgrathSign 'large sign' 'large sign'
    "It reads:\n
    AGRATH'S LABYRINTH.\n
    From this labyrinth, I guarantee,\n
    There is no way that you can flee,\n
    East or West, or South or North,\n
    Whichever way you hurry forth,\n
    Take a minute, or take an hour,\n
    You are completely in my power.\n
    Be you early, be you late,\n
    I alone decide your fate.\n
    -- <i>Agrath (Princess of Demons)</i>.<.reveal agrath>"
;

maze3: MazeRoom 
    epithet = 'fiendish'
    nextRoom = maze4
;

+ AgrathSign 'large sign' 'large sign'
    "It reads:\n
    AGRATH'S LABYRINTH.\n   
    Try all you wish, my labyrinth will take\n 
    you where <i>I</i> desire to make\n
    you come. You cannot escape your destiny;\n
    Once in this place, all men come to me!\n
    -- <i>Agrath (Queen of Hell)</i><.reveal agrath>"
;


maze4: MazeRoom 
    epithet = 'devious'
    nextRoom = lair
    roomBeforeAction()
    {
        if(gActionIs(Jump))
        {
            "For some reason you find yourself unable to; it must be
            something to do with the atmosphere of the place. ";
            exit;
        }
        inherited;
    }
;

+ AgrathSign 'large sign' 'large sign'
    "It reads:\n
    AGRATH'S WAGER.\n
    If your next step leads not into my lair,\n
    Then free you'll be; I shall play fair\n
    And let you go if you can find from here\n
    Some path that leads not straight unto my lair.\b   
    But if into my lair you come\n      
    then I with you will have my fun:\n
    Torment and temptation, endless once begun\n
    For my plaything you then will have become!\b
    So choose you path with utmost care,\n
    Then meet your doom within my lair!\b   
    -- <i>Agrath (Temptress-and-Tormenter-in-Chief)</i><.reveal agrath>"
    epithet = 'cunning'
    nextRoom = lair
    
;

MultiLoc, ThroughPassage 'confusing exit passage*passages*exits' 'passages'
    "Passages lead off to north, south, east and west, as well as the diagonal
    directions in between. They all look pretty much alike. "
    isPlural = true
    locationList = [maze1, maze2, maze3, maze4]
    dobjFor(TravelVia)
    {
        action()
        {
            "In desperation, you choose a passage at random and set off down
            it. ";
            replaceAction(TravelVia, gPlayerChar.getOutermostRoom.nextRoom);
        }
    }
;

lairWall : RoomPart 'continuous circular smooth wall*walls' 'wall'
    "This room has a single wall, about ten feet high, running all the way
    round its circumference, painted in abstract green and orange patterns. "
;

+ Component 'abstract green orange pattern*patterns' 'patterns'
    "You can't quite make them out: they're the sort of patterns that looks as
    if they might make sense when you glance at them out of the corner of your
    eye, but then dissolve into mind-numbing meaninglessness when you try to
    stare at them directly. "
    isPlural = true
;

lairCeiling : RoomPart 'large domed green ceiling/roof/dome*domes' 
    'domed ceiling'
    "The ceiling is a large green dome, about twenty feet across. "
;

lair: Room 'Domed chamber' 'the domed chamber'
    "<<mainDesc>> <<lairDoor.isOpen ? 'There\'s an opening through the wall to
        the north' : 'So far as you can tell, there\'s no way out'>>. "
    mainDesc = "About twenty feet in diameter, this chamber is perfectly round,
        with a continuous circular wall and a domed ceiling. "  
    roomFirstDesc = "<<mainDesc>>\b As you walk in, the entrance closes up
        behind you. " 
    roomParts = [defaultFloor, lairWall, lairCeiling]
    enteringRoom(traveler)
    {
        if(traveler == gPlayerChar)
        {      
            new Fuse(agrath, &appear, 1);
        }
    }
    north = lairDoor
    thinkHere()
    {
        if(lairDoor.isOpen)
            "You suspect it may be time to leave. ";
        else if(gPlayerChar.canSee(agrath))
            replaceAction(ThinkAbout, agrath);
        else
            "You have a nasty feeling that this is a place you'd rather have
            avoided finding. ";
    }
    defaultLook(dir)
    {
        "You see a section of the circular wall. ";
    }
    northLook
    {
        if(lairDoor.isOpen)
            "You see an opening to the north. ";
        else
            defaultLook(northDirection);
    }
;

+ lairDoor : HiddenDoor 'exit/opening' 'opening'
    "The opening to the north is easily large enough to walk through. "
    openTo(dest)
    {
        destination = dest;
        makeOpen(true);
        "An opening duly appears in the wall to the north. ";
    }
    makeOpen(stat)
    {
        inherited(stat);
        if(!stat)
            "The opening to the north closes again. ";
    }
;

wealthRoom : Room 'Treasure Room'
    "This long, narrow room stretches to the north as far as you can see. Both
    sides are lined with benches, each bench being piled high with gold coins,
    while under the benches gems and bank-notes bulge out of large wooden
    crates. "
    enterRoom(traveler)
    {
        "<.p>As you step into the room, you pause to estimate how much wealth
        is stacked up here. You give up when your estimate reaches twice the
        GDP of the entire world, but before you can even begin to form a plan
        of what you could actually do with such wealth, Agrath strides up you
        with a fiendish grin on her face.\b
        <q>Behold your riches!</q> she declares, indicating the cash-laden
        benches with a sweep of her hand, <q>Behold your wealth! More than you
        ever dreamt of! But I can't bear the thought of your being the richest
        man without your knowing just how rich you are, so you really
        <i>must</i> count it all. Once you've carried out that little task we
        can discuss what happens next -- but I expect you to get it right; I
        just can't <i>abide</i> sloppiness over that kind of thing! Well, so
        long for now -- and happy counting!</q>\b
        So saying, the demoness turns on her heel and minces out of the room,
        slamming the door behind her. A quick check reveals that the door is
        well and truly locked.\b
        Since there seems to be nothing else for it, you start counting the
        cash.\b";
        inputManager.pauseForMore(nil);
        "A year later, you have moved so far down the benches that you have lost
        sight of the door; but you are still counting the cash, and the benches
        still stretch to the north as far as you can see.\b";
        inputManager.pauseForMore(nil);
        "A century later, you have almost forgotten that there was a door, or a
        demoness, or anything else except benches full of gold coins; but you
        are still counting your wealth.\b";
        inputManager.pauseForMore(nil);
        "A millenium later, you have forgotten everything except the need to
        count, and still there is no end in sight to your counting. Indeed,
        there will be no end to your counting: you will be counting these coins
        for all eternity.\b";
        finishGameMsg('YOU HAVE TURNED INTO AN ADDING MACHINE',
                      [finishOptionUndo, finishOptionFullScore]);       
    }
;

fameRoom : OutdoorRoom 'Crowded Room'
    "Whatever this place is, it's crowded with people who seem to think they
    know you, all of them jostling one another to take your photograph or ask
    you for an interview or request your autograph, or simply to touch you or
    gawp at you or get you to notice them. You are on some kind of raised
    platform, which makes you a bit more visible to the sea of faces you can
    see in all directions, but that doesn't prevent the people nearest to you
    from climbing up to press against you. "
    enterRoom(traveler)
    {  
        "<.p>Agrath elbows her way through the crowd to stand by your side, and
        then cries out in a stentorian roar, <q>Order! <i>Order</i>! For
        goodness's sake give the man a chance! What the hell do you think
        you're all doing behaving like this?</q> She turns to give you an
        apologetic smile, then turns back to the crowd, <q>Right!</q> she says,
        <q>Which of you want an autograph?</q>\b
        At once more hands go up than you know how to count.\b
        <q>Okay then!</q> the demoness declares, <q>Form an orderly queue and
        come up for your autographs <i>one at a time</i>.</q>\b
        At once the crowd obey her, and some sort of orderly queue miraculously
        appears through the throng.\b Agrath turns to you with an evil grin,
        <q>Well, you'd better get signing then!</q> she tells you, <q>Enjoy
        your fame!</q> Before you can respond, she disappears into the crowd.\b
        Already the first man in the queue is pushing his pen and autograph
        book into your hand.\b";  
        inputManager.pauseForMore(nil);
        "A month, a year, a decade, and several million signatures later, you
        are still at it, your hand, wrist and arm miraculously preserved from
        repetitive strain injury by Agrath's devilish magic.\b";
        inputManager.pauseForMore(nil);
        "A century passes, and a millenium. A million, billion or trillion
        years go by. Out in the real world the sun goes nova, the stars burn
        cold, the universe dies a heat death, hell freezes over, and still
        these hateful little people come demanding your autograph for their
        neat little books.\b
        By then, you fully appreciate the price of fame.\b";
        finishGameMsg('YOU ARE TRAPPED BY ETERNAL FAME',
                      [finishOptionUndo, finishOptionFullScore]);
    }
;

library: Room 'Library' 'the library'
    "Rows and rows of bookshelves, crammed with books and periodicals in every
    language you've ever heard of (and several you haven't) stretch in every
    direction as far as the eye can see (and quite probably a good deal
    further). In the middle of all this, roughly where you're <<gPostureName>>,
    is a large desk with a pair of computer terminals and a microfiche
    reader. "
    enterRoom(traveler)
    {
        "Agrath follows you in, and looks around with an expression of evident
        satisfaction. <q>This will do nicely, I think,</q> she remarks. Then
        she turns to you and indicates the library with a sweep of her hand,
        <q>In this room is all the knowledge known to humankind throughout all
        the ages, past, present and future. If that's not enough for you I can
        lay on all the knowledge of all the non-human races in the universe as
        well -- but human knowledge will be enough to be getting on with. Of
        course it\'s in a couple of hundred different languages or so, but
        there are plenty of dictionaries and grammars around, so you should be
        able to learn them all in time. So here's the deal. You want knowledge
        -- you acquire it. It's all there, you've just got to study a bit. Your
        task is simply to master it -- all of it. Once you've done that, you
        can call me back and I'll set you a little examination. Oh, I should
        mention that I simply cannot tolerate sloppiness in scholars, so for
        every wrong  answer you give I'll chop a little piece off you -- a
        finger or a foot maybe, that sort of thing -- and I'll do it slowly and
        painfully. So if I were you I shouldn't call me back until you're quite
        sure you're ready. But don't worry, there's no time limit -- you can
        spend all eternity on it if you like. Should you ever feel you're ready
        to sit the exam, just send me an email on one of those -- </q> she
        points to the computer terminals <q> -- you can reach me on
        agrath@inferno.org. Right, so long till then!</q>\b So saying, the
        demoness turns on her heel and vanishes in an impressive puff of purple
        smoke, leaving you all alone in the library.<.p>";
        inputManager.pauseForMore(true);
        "A century later, you are still working through the English-language
        material in your own discipline of New Testament studies, for which
        there seems to be almost an infinity of future scholarship available on
        the infernal internet.<.p>";
        inputManager.pauseForMore(true);
        "A millenium later, you try to cram your brain with a thirteenth
        foreign language, just for a change, but you know that you are starting
        to forget twice as much as you learn.<.p>";
        inputManager.pauseForMore(true);
        "Some time during the next million years, the information overload
        proves too much even for ghostly synapses, and you suffer a total
        breakdown, a complete psychic scrambling, perhaps even the mental
        equilavent of a hard-disk crash. Your last ever coherent thought is a
        quotation from Acts 26.24: <q>Your great learning is driving you
        mad!</q>. 
        <.p>And so it does.<.p>";
        finishGameMsg('YOU HAVE TOTALLY LOST YOUR MIND', 
                      [finishOptionUndo, finishOptionFullScore] );
        
    }
;

feastRoom : Room 'Restaurant' 'the restaurant'
    "As restaurants go, this is the one of the most intimate you have ever
    seen: it has a single table with a single chair at it, with a single place
    setting laid. The decor is not entirely to your taste -- it's all on the
    theme of food, and though the scenes of bumper harvests are okay, the Roman
    orgies and the graphic depictions of the slaughter and butchering of beef
    cattle are rather too gaudy and gory. "
    enterRoom(traveler)
    {
        "Agrath follows you in and seats you at the table with all the grace
        and finesse of an expert waitress. ";
        nestedActorAction(traveler, SitOn, restaurantChair);
        "Then, as if from nowhere she produces a bowl of cold soup, placing it
        in front of you with a snappy <q>Bon app&eacute;tit!</q>. It turns out
        to be a absolutely amazing gazpacho -- the best you've ever tasted.\b
        She continues to ply you with course after course, all tasting
        delicious, all beautifully presented. The gazpacho is followed by some
        superb breaded mushrooms in garlic. Then comes a divine Beef
        Wellington. This is followed by a cr&ecirc;pe suzette to die for. Then
        the demon waitress puts a huge helping of what might well be the best
        of all possible cheesecakes in front of you, but, since you are now
        beginning to feel more than a little bloated, you hesitate to tuck into
        it.\b
        <q>Eat up -- or I shall think you don't like my cooking, and that would
        mortally offend me,</q> Agrath warns you, <q>and believe me, offending
        me is something you really don't want to do!</q>\b Well, you just about
        manage to force the cheescake down, but when she then puts a huge hunk
        of Blue Stilton (complete with a choice of bread rolls or crackers) in
        front of you, you simply can't make yourself eat any more.\b <q>Too
        full?</q> Agrath wonders, <q>Don't worry - I've got just the answer to
        that little problem!</q><.p>";
        inputManager.pauseForMore(nil);
        "Agrath suddenly whips out a feather, forces it into your mouth, and
        tickles your throat with it. You immediately throw up.\b
        <q>There,</q> she says sweetly, <q>that should leave a bit more room.
        So eat up!</q>\b
        Of course it doesn't stop there. Oh no. The same routine goes on for
        day after day. Agrath puts course after course of admittedly excellent
        food in front of you, and whenever you're a bit too slow off the mark
        eating it up, out comes the feather.\b
        Pretty soon your throat feels raw, your stomach feels like bloated
        lead, and you have run out of superlatives to describe just how sick
        you feel. And you've long since realized that the choice Agrath offered
        between torment and temptation was no real choice at all -- she's
        simply tricked you into naming what form your torment will take.\b
        Day after day the food keeps coming, and Agrath makes quite sure you
        eat it. Eventually it becomes apparent that you've got an even worse
        problem than being perpetually stuffed with food...<.p>";
        inputManager.pauseForMore(nil);
        "... The problem is that although Agrath keeps wielding her diabolical
        feather, she never cleans up the resulting mess, and though that
        doesn't seem to bother her at all, it soon starts bothering you. After
        a decade or so, the room starts filling up. Eventually Agrath takes to
        walking upside down on the ceiling, and serving you from that position
        -- no doubt an easy enough trick for a princess of demons to perform,
        but not one that helps you all that much. Month by month, year by year,
        the tide of vomit slowly rises -- to your knees, your waist, your
        chest, and eventually your neck. By that time, of course, you're no
        longer able to feed yourself very easily, so Agrath obligingly takes
        over the job for you, spooning the food (you no longer know or care
        what food) directly into your mouth, and exchanging spoon for feather
        whenever your swallowing becomes too slow.\b
        For the millionth time you beg her to stop, and for the millionth time
        she sternly refuses:\b <q>Oh no! You asked for food, and food you shall
        have!</q><.p>";
        inputManager.pauseForMore(nil);
        "Why indigestion, stomach-rupture, obesity, or heart-failure don't kill
        you, you never work out (unless it's because you're already dead), but
        finally, of course, the day comes when the tide of vomit rises just a
        bit too far.<.p>";
        finishGameMsg('YOU HAVE DROWNED IN YOUR OWN VOMIT',
                      [finishOptionUndo, finishOptionFullScore]); 
        
    }
;  

+ restaurantChair: Chair, CustomImmovable 'customer chair' 'chair'
    
;

boozeRoom: Room 'Huge Bar'
    "You find yourself in a huge bar, with a counter stretching off into the
    far distance, barrels lining the wall, and shelves full of bottle and
    glasses. Every kind of strong drink you can imagine is here, from beer and
    wine through gin, whisky, and vodka to liqueurs, brandies, schnapps,
    vermouths and anything else you can think of, in addition to many others
    that never occurred to you. "
    enterRoom(traveler)
    {
        "Agrath follows you in, and indicates it all with a sweep of her hand,
        <q>Here you are, drink all you want!</q> she tells you, <q>There's just
        one thing, I never do temptations by halves, and I can't abide
        ingratitude, so I expect you to drink the lot before I'll even consider
        letting you out of here!</q>\b
        So saying, she turns on her heel and vanishishes in an impressive cloud
        of purple smoke.<.p>";
        inputManager.pauseForMore(nil);
        "You pour yourself a large beer, and then another, and then start
        sampling some of the wines. To begin with you take some interest in the
        quality, and note that the majority of the stuff here is pretty good.
        Soon, however, you become far too drunk too care.\b
        How much time passes in your alcoholic haze you have no idea, but after
        a while you become far too inebriated to have any idea what you're
        doing. By then your brain is probably as pickled as your liver.\b
        One day, you stagger drunkenly over to a barrel, trip and fall in head
        first. You never emerge.\b";
        finishGameMsg('YOU HAVE DROWNED IN A CASK OF MALMSEY', [finishOptionFullScore,
            finishOptionUndo]);     
    }
;


powerRoom : Room 'High Mountain' 
    "You find yourself on the top of a very high mountain, overlooking fields,
    farms, and forests, villages, towns and cities -- more than you can number
    -- spread out in every direction as far as the eye can see.\b
    Agrath comes to stand behind you, indicating these lands with a grand sweep
    of her hand, <q>All these kingdoms, and all the glory of them, are yours to
    rule forever. I grant you absolute power as absolute King, Emperor and
    Monarch of all you survey. All those who dwell here will obey your every
    command, and all will look to you for instruction. I tell you no Emperor of
    Rome, no mediaeval monarch, no dictator, president or prime minister has
    ever enjoyed such absolute power. Now let your reign begin!</q>\b  
    So saying, Agrath vanishes in a puff of purple smoke, leaving you alone on
    the mountain top -- but not for long. Soon a steady stream of people come
    seeking your orders: generals and admirals, city councillors and
    businessmen, tax-collectors and customs officials, writers and teachers,
    plumbers and decorators, sewage workers and refuse collectors, all wanting
    your orders, all coming with problems requiring your decision.\b"
    enterRoom(traveler)
    {
        inputManager.pauseForMore(nil);
        "As the days pass, the stream becomes a flood. Of course you try to
        delegate, and of course your subjects obey you in accepting the
        authority you delegate to them, but it doesn't seem to help, for there
        are always any number of problems that contrive to fall outside the
        scope of their delegated powers. The gardener of the public park in
        Williamsville wants to know whether to plant pink, white or red roses;
        the headmaster of the Fisher Academy needs to know the precise
        proportion of lesson time to be devoted to nouns, verbs and adjectives
        in Spanish lessons; the editor of the Royal Gazette needs to know if he
        can accept advertising from former prostitutes wishing to peddle
        ladies' underwear, and so it goes on, unremittingly, hour by hour, day
        by day, week by week, year by year. There is never any rest for you,
        only a stack of decisions to make and orders to give that grows ever
        faster than your ability to deal with them. ";
        inputManager.pauseForMore(nil);
        "If only your petitioners would go away, you might have time to devise
        an administrative structure that would remove most of these burdens
        from you, but somehow even your most loyal advisers contrive to prevent
        this happening: <q>Oh no, sire, this matter is urgent and must be dealt
        with straight away,</q> <q>Oh no, sire, that is a power Your Majesty
        must retain to himself.</q>\b
        Finally, after what feels like centuries of ever mounting stress, your
        decisions become totally eccentric, resulting in mounting chaos in your
        dominions. After a few more centuries of growing panic, your orders
        become completely random, and among the random orders you issue is one
        to have yourself assassinated. Your subjects obey with alacrity. ";
        finishGameMsg('YOU HAVE BEEN ASSASSINATED', [finishOptionFullScore,
            finishOptionUndo]);
    }
    
;

//==============================================================================

fireLedgeFloor : Floor 'fairly level rocky ground/floor' 'ground'
    "The ground here is fairly level, if a bit rocky. One thing you do notice
    on closer inspection is a small round hole, just above the spot where
    <<singleRope.theName>> starts its journey across the ravine. "
;

fireLedge : OutdoorRoom 'Fire Ledge' 'the fire ledge'
    "Immediately to the north is a deep ravine, filled with fire, from the
    bottom of which come sounds like the screams of the damned. The ledge on
    which you're <<gPostureName>> continues a short way to the west, but
    otherwise the only open path seems to be on the far side of the ravine, and
    the only way across the ravine would seem to be via <<singleRope.theName>>
    stretched across it. Behind you to the south is a large dome, which may or
    may not be the outside of Agrath's lair; even if it is, there seems to be
    no way back into it. "
    north = singleRope
    west : TravelMessage { -> crudeCave
        "You walk along the ledge for some way, with the ravine ever to your
        right, until the ledge comes to an end outside the mouth of a crude
        cave, which you enter. "
    }
    south: NoTravelMessage { "That way is blocked by the large dome. " }
    vocabWords = 'ledge'
    enterRoom(traveler)
    {
        achievement.addToScoreOnce(1);
    }
    achievement : Achievement { "escaping from Agrath's lair" }
    dobjFor(Follow) remapTo(West)
    roomParts = [fireLedgeFloor, defaultSky]
    thinkHere()
    {
        if(singleRope.passable)
            "You think that you may as well walk the plank. ";
        else if(crudeCave.seen)
            "It occurs to you that you probably need to find a way across the
            ravine. ";
        else
            "At first sight there doesn't seem to be much of interest here, so
            you wonder if it would be a good idea to start exploring. ";
    }
    southLook = "Directly to the south is a large dome. "
    northLook = "To the north, <<singleRope.aName>> stretches across the deep
        ravine. "
    westLook = "The ledge continues some way to the west. "
    defaultLook(dir)
    {
        "You see nothing of interest to the <<dir.name>>. ";
    }
    roomBeforeAction
    {
        if(gActionIs(JumpOffI))
            replaceAction(Enter, ravine);
    }
    throwDests = [[northDirection, ravine], [northeastDirection, ravine],
        [northwestDirection, ravine]]
;

+ Distant 'only open most obvious path/ways*paths' 'only open path'
    "It looks like there could be several ways you might be able to go once
    you've crossed the ravine, but from this side the most obvious path on the
    far side leads directly away from the ravine. "
;

+ Fixture 'agrath\'s large smooth unyielding frictionless surface/dome/lair*domes' 
    'large dome'
    "It simply sits there, blocking your way south. It's too smooth to climb,
    there\'s nothing you could get a purchase on. There's also no way to open
    it or get inside it. The dome is easily large enough to be the outside of
    Agrath's lair, but there's no sign of the labyrinth you thought surrounded
    the lair. "
    cannotClimbMsg = 'The surface of the dome is too smooth -- there is nothing
        you could get a purchase on. '
    cannotOpenMsg = 'The surface of the dome looks seamless; you can find no
        hint of an opening anywhere. '
    shouldNotBreakMsg = 'Whatever the dome\'s made of, it\'s jolly tough; you
        can\'t even scratch it, let alone dent it. '
    uselessToAttackMsg = (shouldNotBreakMsg)
    cannotEnterMsg = 'If there is a way in, you can\'t find it. '
    feelDesc = "The surface of the dome feels hard and smooth, unyielding but
        frictionless. "
    lookInDesc = "The dome is opaque; you can't see inside. "
    nothingBehindMsg = cannotSeeBehindMsg
;

+ singleRope : Passage 'sturdy narrow rope' 'rope'
    "The <<name>> looks sturdy enough as <<name>>s go, but also perilously
    narrow. About the only thing that can be said for it is that it spans the
    ravine. It's not immediately obvious how it's fixed in place, however,
    since it seems to run from a point just below the lip of the ledge on your
    side of the ravine to a similar point on the far side. "
    canTravelerPass(traveler)
    {
        return passable;
    }
    explainTravelBarrier(traveler)
    {
        "The very thought of stepping out onto that narrow rope across that
        fiery ravine sends shivers of terror down your spine and churns your
        stomach into adrenalin soup. You simply cannot bring yourself to
        attempt it. ";
    }
    noteTraversal(traveler)
    {
        "The narrow plank looks anything but safe to you, but since it provides
        the only means of crossing the ravine you\'re likely to get, you force
        yourself to step onto it, your heart leaping into your mouth as you
        look down at the fierce flames in the ravine below. Doing your best to
        follow the oft-given advice not to look down, you manage to edge your
        way unsteadily along the plank, and finally arrive safe at the other
        side. ";
    }
    nothingThroughPassageMsg = '{The dobj/he} may be relatively narrow, but
        it\'s not transparent. '
    dobjFor(Cross) asDobjFor(TravelVia)
    dobjFor(WalkOn) asDobjFor(TravelVia)
    dobjFor(Pull)
    {
        verify() { 
            if(passable)
                illogicalNow('{You/he} can\'t pull {the dobj/him} anywhere --
                    it\'s firmly lodged in place. ');
        }
        action() {
            "You pull the rope fully taut, but then you meet too much
            resistance, and you find you cannot pull it any further. But you do
            detect a hint of movement on the other side, as if the rope might
            be meant to move. ";     
        }
    }
    retract()
    {
        if(passable)
            "{You/he} find{s} {it actor/he} can't turn <<windlass.theName>> any
            further. ";
        else
        {
            name = 'narrow wooden plank';
            passable = true;
            cmdDict.removeWord(self, 'rope', &noun);
            initializeVocabWith('wooden plank');
            "\^<<windlass.theName>> proves stiff to turn, but as {you/he}
            turn{s} it the rope slowly retracts into {your/his} side of the
            ravine, pulling a wooden plank with it, until the rope is fully
            retracted and the plank spans the ravine. ";
        }
    }
    dobjFor(Move) asDobjFor(Pull)
    passable = nil
    futileToKnockOnMsg = (passable ? inherited : 'That achieves nothing. ')
    cannotMoveMsg = 'That looks unlikely to achieve anything. '   
;

+ Fixture 'lip/ledge' 'lip of the ledge'
    "There's <<holeDesc>>"
    holeDesc = "a small round hole, just 
        above the point where <<singleRope.theName>> crosses the ravine. "
    initDesc = "Looking more closely at the lip of the ledge you spy
        <<holeDesc>>"
    isInInitState = (!described)
;

+ fireLedgeHole: SingleContainer, RestrictedContainer, Fixture 
    'small round hole' 'small round hole'
    "The small round hole in the ground looks about a couple of centimetres in
    diameter. "
    validContents = [windlass, pen, steelRod]
;

MultiLoc, SimpleNoise 'distant tormented screams/damned/souls' 'screams'
    "The screams -- if that's what they are -- are enough to curdle your blood.
    They sound like souls in perpetual torment, although the sound is terribly
    remote. You can't exactly see their source, but they seem to be coming from
    the bottom of the deep ravine. "
    isPlural = true
    locationList = [fireLedge, farSideRavine]
;

MultiLoc, SimpleOdor 'constant burning' 'constant burning'
    "You smell constant burning -- burning and burning heat. "
    locationList = [fireLedge, farSideRavine]
;


ravine: MultiLoc, Fixture 'deep fiery dreadful (bottom)/ravine' 'deep ravine'
    "The ravine is deeper than you can judge, though less than a hundred feet
    down are the tops of great raging flames. It is about thirty feet wide --
    clearly too wide to jump across -- although <<singleRope.aName>> is slung
    from one side to the other. "
    locationList = [fireLedge, farSideRavine]
    dobjFor(Cross) remapTo(Cross, bridge)
    bridge = (gPlayerChar.isIn(fireLedge) ? singleRope : ravinePlank)
    cannotEnterMsg = 'The screams sounding from the bottom of the ravine
        convince you that this is one ravine you don\'t want to fall down --
        for that matter, so do the flames. '
    dobjFor(JumpDown) asDobjFor(Enter)
    iobjFor(ThrowInto)
    {
        verify() { }
        action()
        {
            "You toss {the dobj/him} over the edge, and {it dobj/he} fall{s}
            rapidly to the hungry flames below. ";
        }
    }
    nothingBehindMsg = 'Behind the ravine is its far side. '
    cannotJumpOverMsg = 'The ravine is far too wide to jump across. '
;

MultiLoc, Distant 'great raging fierce hungry (tops)/(top)/fire/flames' 
    'raging fire'
    "The raging fire fills the ravine. "
    locationList = [fireLedge, farSideRavine]
    iobjFor(ThrowInto) remapTo(ThrowInto, DirectObject, ravine)
;

ccSouthWall: RoomPart 'surprisingly smooth south (s) wall*walls' 'south wall'
    "The south wall of the cave is surprisingly smooth. A closer inspection
    reveals a small round hole in it, at about chest height. <<ccDoor.isOpen ?
      'Next to the hole is a large square opening. ' : ''>><.reveal cave-hole>"
;

crudeCave : Room 'Crude Cramped Cave' 'the crude cramped cave'
    "As caves go, this is not an impressive one. It's just about high enough to
    stand in, and just about large enough to take a couple of paces in any
    direction from its centre. The only feature that strikes you as at all
    notable is that the south wall looks surprisingly smooth. "
    east : TravelMessage { -> fireLedge
        "You emerge from the cave and walk back along the ledge till you reach the
        point where the rope spans the ravine. "
    }
    out asExit(east)
    south = ccDoor
    down : NoTravelMessage { "The ground is far too solid here for you to
        burrow through. " }
    roomParts = [defaultFloor, defaultCeiling, ccSouthWall, defaultNorthWall, 
        defaultWestWall]
    thinkHere()
    {
        if(deadEndPassage2.seen)
            "There doesn't seem to be much else of interest here, so far as you
            can tell. ";
        else if(ccDoor.isOpen)
            "You wonder what's on the other side of that large square opening
            in the south wall. ";
        else if(gRevealed('cave-hole'))
            "You wonder about that hole in the south wall. ";
        else
            "You wonder if it might be worth giving this cave a closer
            inspection. ";
    }
    eastLook = "To the east is the exit from the cave. "
    outLook = (eastLook)
    roomBeforeAction()
    {
        if(gActionIs(Jump))
        {
            "You'd obviously crack your head on the ceiling if you tried
            that. ";
            exit;
        }
    }
;

+ Unthing '(e) east wall*walls' 'east wall'
    'The cave has no east wall -- that way lies the exit. '
;

+ ExitPortal ->(location.east) 'large rectangular exit' 'exit'
    "The large rectangular exit lies to the east. "  
    nothingBehindMsg = &cannotLookBehindMsg
;

+ ccHole : RestrictedContainer, Fixture 'small round hole' 'small round hole'
    "It's at about chest height in the south wall of the cave, and looks about
    three-quarters of an inch in diameter. "
    validContents = [windlass]
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    nothingBehindMsg = &cannotLookBehindMsg
;

+ ccDoor: TravelWithMessage, HiddenDoor 'large square opening' 
    'large square opening'
    "The opening in the south wall is easily large enough to walk through. "
    openOrClose() {  makeOpen(!isOpen);  }
    makeOpen(stat)
    {
        inherited(stat);
        "As {you/he} turn{s} <<windlass.theName>>, <<stat ? 'a panel slowly
            sides to one side, revealing an opening in the south wall' : 'the
                panel slowly slides back into place, concealing the former
                opening'>>. ";
        ccPanel.makePresent();
    }
    destination = junction2
    travelDesc = "You walk a brief distance up a short passage until you
        reach a junction. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    nothingBehindMsg = &cannotLookBehindMsg
;

+ ccPanel: PresentLater, CustomFixture 'smooth panel' 'panel'
    "The panel <<ccDoor.isOpen ? 'has slid aside to reveal an opening' : 'has
        closed, seemingly forming a seemless part of the smooth cave wall'>>. "
    cannotTakeMsg = 'It seems to be securely fixed in place. '
    onlyWithCrankMsg = 'It seems that can only be done with the crank. '
    cannotOpenMsg = (ccDoor.isOpen ? 'It\'s already open. ' : onlyWithCrankMsg)
    cannotCloseMsg = (ccDoor.isOpen ? onlyWithCrankMsg : 'It\'s already closed. ')
;

+ windlass: Thing 'bent discarded crude metal crank 
    length/windlass/tubing/socket/handle/tube' 
    'length of bent metal tubing'
    "The length of bent metal tubing looks like a crank of some kind, with one
    end forming a crude handle, and the other ending in some kind of socket.
    The socket is somewhere between half an inch and an inch in diameter.
    <<rename()>>"   
    initSpecialDesc = "A discarded length of bent metal tubing lies on the floor    
        near the back of the cave. "
    rename() { name = 'crank handle'; }   
    
    dobjFor(Turn)
    {
        verify() {
            if(location not in (ccHole, fireLedgeHole))
                nonObvious;
        }
        action()
        {
            if(isIn(ccHole))
                ccDoor.openOrClose();
            else if(isIn(fireLedgeHole))
                singleRope.retract();
            else
                "\^<<gVerbName>>ing <<theName>> achieves nothing. ";
        }
    }
    dobjFor(Push) asDobjFor(Turn)
    dobjFor(Pull) asDobjFor(Turn)
    iobjFor(AttackWith)
    {
        verify() { }
    }
    weight = 3
    bulk = 2
;

//==============================================================================

junction2: Room 'Passage Junction'
    "There's just about enough headroom for you to stand upright at this
    junction, where the short narrow passage from the north meets a much longer
    one running east to west. At the end of the northern passage you can see
    the opening back into the crude cave, but the other two passages look
    pretty gloomy and you can't see where they lead from here. "
    north : TravelMessage { ->crudeCave
        "You walk a few yards down the short narrow passage until
        you pass through an opening back into the cave. "
    }
    west = deadEndPassage2
    east: TravelMessage { -> deadEndCave
        "You walk for several hundred yards down a long, straight,
        narrow passage until it comes to an end in a <<place()>>. "
        place()
        {  
            if(deadEndCave.wouldBeLitFor(gPlayerChar) 
               || (crystal.isIn(gPlayerChar) && gPlayerChar.canSee(crystal)))
                
                "small round cave";
            else
                "dark place";
        }
    }  
    roomParts = [defaultFloor, defaultCeiling, defaultSouthWall]
    northLook = "A short passage runs off to the north. "
    westLook = "A dimly-lit passage leads westwards
        <<glimmer(deadEndPassage2)>>."
    eastLook = "A gloomy passage leads eastwards <<glimmer(deadEndCave)>>. "
    glimmer(dest)
    {
        if(dest.wouldBeLitFor(gPlayerChar))
            "towards a distant glimmer of light";
        else
            "into total darkness";
    }
    roomBeforeAction()
    {
        if(gActionIs(Jump))
        {
            "There's not enough headroom to jump here. ";
            exit;
        }
    }
;

+ EntryPortal ->(junction2.north) 'opening' 'opening'
    "The opening back into the crude cave lies a few yards down the
    passage to the north. "
;

//==============================================================================
deadEndCave: DarkRoom 'Small Round Cave'
    "The walls of this small cave press in on you claustrophobically. The only
    way out appears to be the passage running west. On the north wall is a
    crude painting. " 
    roomFirstDesc = "Your first impression of this cave is of tight walls
        pressing in on you; glancing round you notice that one of them, that to
        the north, has a crude painting daubed on it. "
    roomDarkDesc = "It is totally dark here; you can make out nothing but the
        dim outline of the passage leading back to the west. "
    west = junction2
    westLook = "An ill-lit passage leads off to the west from here. "
    westLookDark = "You see a faint light from the passage to the west. "  
    northLook = "You see a crude painting on the north wall. "   
    out asExit(west)
    thinkHere()
    {
        if(gPlayerChar.canSee(cavePainting))
            "The most interesting thing here, such as it is, would seem
            to be the painting on the north wall. ";
        else
            "You think it's too dark to do much here. ";
    } 
    
;

+ cavePainting: RoomPartItem, Fixture 'crude daubed painting' 'painting'
    "The crude painting depicts an open-mouthed angel standing outside a cave,
    perhaps meant to be a tomb, pointing at the round stone
    covering its entrance. "
    initNominalRoomPartLocation = defaultNorthWall
    initSpecialDesc = "A crude painting has been daubed on the north wall. "
    nothingBehindMsg = &cannotLookBehindMsg
;

++ Component 'open-mouthed angel' 'angel'
    "He's depicted in a very generic way, with just a pair of wings to denote
    his angelic status. His mouth is open and one hand is pointing to the round
    stone covering the cave entrance. "
    nothingBehindMsg = &cannotLookBehindMsg
;

+++ Component 'outline pair/wings/shapes' 'wings'
    "They're little more than outline shapes. "
    owner = (location)
    isPlural = true
    nothingBehindMsg = &cannotLookBehindMsg
;

+++ Component 'open (angel) angel\'s mouth*mouths' 'angel\'s mouth'
    "The angel's mouth is open, as if he's in the act of speaking. "
    nothingBehindMsg = &cannotLookBehindMsg
;

+++ Component '(angel) angel\'s hand' 'angel\'s hand'
    "The angel\'s hand is depicted pointing to the entrance of the cave. "
    nothingBehindMsg = &cannotLookBehindMsg
;


++ Component 'cave tomb entrance/(mouth)' 'cave entrance'
    "The entrance to the cave is depicted covered with a large round stone. "
    nothingBehindMsg = &cannotLookBehindMsg
;

++ Component 'large round stone' 'large round stone'
    "The large round stone is shown covering the entrance of the cave. "
    nothingBehindMsg = &cannotLookBehindMsg
;

++ Component 'cave/tomb' 'cave'
    "Not much of it is shown, apart from the large round stone covering its
    entrance. "
    nothingBehindMsg = &cannotLookBehindMsg
;

+ EntryPortal -> junction2 'dim ill-lit outline/tunnel/passage' 'passage'
    "The ill-lit passage leads off to the west. "
    brightness = 1
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    nothingBehindMsg = &cannotLookBehindMsg
;

//==============================================================================
blankWall : RoomPart 'blank solid rock (w) west wall' 'west wall'
    "It seems to be a wall of solid rock, with no conceivable way through. A
    closer inspection reveals that a picture of a scarlet fish has been painted
    on it. "
;

deadEndPassage2 : DarkRoom 'Long Narrow Passage' 'the long narrow passage'
    "The passage from the east stoops and narrows until it comes to an end at a
    solid rock wall.  "
    roomDarkDesc = "There's no longer enough light to see anything here apart
        from the faint light from the passage leading back to the east. "
    roomDarkName = 'Dark Dead End'
    east = junction2 
    out asExit(east)
    roomParts = [defaultFloor, defaultCeiling, blankWall,
        defaultSouthWall, defaultNorthWall] 
    thinkHere()
    {
        if(!gPlayerChar.canSee(redHerring))
            "You think you could do with some more light here. ";
        else if(redHerring.described)
        {
            if(cavePainting.seen)
                "You suspect that this branch of the passage may be
                something of a red herring. ";
            else
                "You suspect that the entire passage is a red herring. ";
        }
        else
            "The only thing of any conceivable interest here would seem to be
            the painting on the west wall. ";
    }
    eastLook = "A dimly-lit passage leads off to the east. "
    eastLookDark = "You see a faint light from the east. "  
    roomBeforeAction()
    {
        if(gActionIs(Jump))
        {
            "There's not enough headroom to jump here. ";
            exit;
        }
    }
;

+ EntryPortal ->junction2 
    vocabWords = 'faint east passage passage/light/east' 
    name = (isLit ? 'passage east' : 'faint light')
    desc 
    {
        if(isLit)
            "The passage continues back to the east. ";
        else
            "You can't make out much, but you assume it's the light seeping
            down the passage from the east. ";
    }    
    brightness = 1
;


+ redHerring: Decoration 'scarlet red painting/picture/fish/herring' 
    'scarlet fish'
    "You're not that hot on identifying exotic species of fish, but you suspect
    that this one could well be a red herring. "
    nothingBehindMsg = &cannotLookBehindMsg
;

+ crystal: LightSource 'large white dodecahedral dodecahedric glowing pulsating
    crystal/dodecahedron/glow'  'large white crystal'
    "It's some regular shape, such as a dodecahedron. A closer inspection
    reveals a pulsating glow within. "
    useSpecialDesc = (isInInitState || isDirectlyIn(getOutermostRoom))
    specialDesc = "A large white crystal lies on the ground. "
    initSpecialDesc = "A large white crystal is embedded in the north wall. "
    isInInitState = true
    initNominalRoomPartLocation = defaultNorthWall
    dobjFor(AttackWith)
    {
        verify() 
        {
            if(!isInInitState)
                inherited;
        }
        action() { dislodgeWith(gIobj); }    
    }
    
    dislodgeWith(obj)
    {
        gMessageParams(obj);
        if(++blows > 1)
        {
            "{The obj/he} strike{s} the crystal a second time, dislodging it
            so that it falls onto the floor. ";
            isInInitState = nil;
        }
        else
            "{The obj/he} strike{s} the crystal; it seems to move a fraction,
            but remains embedded in the wall. ";
    }
    
    dobjFor(Attack)
    {
        verify()
        {
            if(isInInitState)
                illogical(hitNoEffectMsg);
            else
                inherited;
        }
    }
    dobjFor(Take)
    {
        check()
        {
            if(isInInitState)
                failCheck('It\'s firmly embedded in the wall and won\'t budge.
                    <.reveal crystal-stuck> ');
            else
                inherited;
        }
    }
    dobjFor(Push) maybeRemapTo(isInInitState, Take, self)
    dobjFor(Move) maybeRemapTo(isInInitState, Take, self)
    dobjFor(Pull) maybeRemapTo(isInInitState, Take, self)
    dobjFor(Break) maybeRemapTo(isInInitState, Attack, self)
    blows = 0
    
    throwTargetHitWith(projectile, path)
    {    
        if(isInInitState && projectile.weight > 1)
        {
            dislodgeWith(projectile);
            "Meanwhile, <<projectile.theName>><<isInInitState ? '' : ' also'>> 
            falls onto the floor. ";
            projectile.moveInto(location);
        }
        else
            inherited(projectile, path);
    }
    hitNoEffectMsg = ((gVerbName == 'kick' ? 'Kicking {the dobj/him}'
                       : 'Hitting {the dobj/him} with your bare hands ') + '
                           proves painful and ineffective. ')
;

//==============================================================================
fsrGround : Floor 'rough broken rocky ground/floor' 'ground'
    "The ground here is mostly broken rock, not exactly impassible, but rather
    hard going apart from the smoother tracks to north, east and west. " 
;

farSideRavine : OutdoorRoom 'Far Side of Ravine' 'the far side of the ravine'
    "Although you can see neither ceiling nor walls, you have the impression of
    being in some vast cavern. Immediately to the
    south a narrow plank runs across a wide ravine, the edge of which runs
    east and west from here. What looks like the most promising track, however,
    leads off to the north. "
    east: FakeConnector { "You set off a short way to the east, but finding
        nothing of interest you retrace your steps to the plank across the
        ravine. " }
    west: FakeConnector { "You could walk west along the edge of the ravine,
        but there's no indication that anything of any interest lies that way,
        so you decide not to bother until you've explored the more promising
        track running north. " }
    south = ravinePlank
    north = ravineCavernPath
    enterRoom(traveler) { achievement.addToScoreOnce(1); }  
    achievement : Achievement { "crossing the ravine" }
    thinkHere = "You feel convinced that the most promising track is the one
        leading north. "
    roomParts = [fsrGround, defaultSky]
    northLook = "To the north runs what looks like the most promising track
        from here, a relatively easy passage across the rough, rocky ground. "
    southLook = "To the south a narrow wooden plank spans the ravine. "
    eastLook = "To the east the rough ground runs along the side of the
        ravine. "
    westLook = "A rough track continues westwards along the edge of the
        ravine. "
    defaultLook(dir)
    {
        if(dir is in (northwestDirection, northeastDirection))
            "To the <<dir.name>> lies broken, rocky ground that looks like it
            would exceptionally heavy going to walk across. ";
        else
            "To the <<dir.name>> you see part of the ravine. ";
    }
    throwDests = [[southDirection, ravine], [southeastDirection, ravine],
        [southwestDirection, ravine]]
;

+ ravinePlank: Passage ->singleRope 'narrow wooden plank' 'narrow wooden plank'
    "The narrow plank leads back across the ravine; although rationally you
    tell yourself that it looks wide enough and firm enough to walk along -- as
    you have already proved -- viscerally it still looks awfully precarious. "    
    noteTraversal(traveler)
    {
        "With a considerable reluctance and even more trepidation, {you/he} force{s}
        {you/him} to walk back across the plank. ";
    }
    dobjFor(Cross) asDobjFor(TravelVia)
    dobjFor(WalkOn) asDobjFor(TravelVia)
    cannotTakeMsg = 'It seems to be anchored in place. '
;

+ ravineCavernPath : TravelWithMessage, PathPassage 
    'most more promising (north) (n) track/path*paths*tracks' 'track'
    "The most promising path from here looks like the track that runs north.
    For one thing, it leads directly away from that dreadful ravine. For
    another, it leads intriguingly away into the distance, and thus firmly
    conveys the impression of going somewhere. And last, but not least, it
    looks purpose-made to afford easy progress across the rough rocky ground. "
    travelDesc()
    {
        "You set off confidently down the track, which seems to lead north for
        quite a way. As you peer into the distance to try to work out where the
        track might be leading, your feet suddenly land on a section of ground
        that gives way beneath you, sending you plunging into a pit. Your last
        thought before you hit your head against something hard and knock
        yourself out is that you have managed to fall into a carefully laid
        trap.\b";
        inputManager.pauseForMore(nil);
        
        foreach(local cur in gPlayerChar.contents)
            if(isPortable(cur))
            cur.moveInto(nil);
        
        "Some time later you awake to find yourself lying on a cold stone
        slab. ";
    }
    destination = agrathCave
;
//==============================================================================

agrathCave : Room 'Burial Cave' 'the burial cave'
    "At a guess, this is a small burial cave. To one side is a stone slab for
    laying bodies on, while in the opposite wall is a loculus (or burial niche).
    The mouth of the cave is to the north<<caveExit.isOpen ? '' :
      ', but it appears to be covered by a large stone'>>. "
    north = caveExit
    out asExit(north)
    travelerArriving (traveler, origin, connector, backConnector)   
    {      
        if(origin == farSideRavine)
        {
            traveler.moveIntoForTravel(agrathCaveSlab);
            defaultPosture = lying;  
        }
        inherited(traveler, origin, connector, backConnector); 
        defaultPosture = standing;
    }
    
    vocabWords = 'burial cave'
    thinkHere()
    {
        if(caveExit.isOpen)
            "You doubt that there's much more for you to do here, so you
            suppose you may as well leave. ";
        else if(gPlayerChar.canSee(agrath))
            "You're forced to admit that it was fairly unlikely that Agrath
            would simply let you go; there had to be a catch somewhere. Now
            you're wondering what the next catch is going to turn out to be. ";
        else
            "You think this cave looks remarkably like the sort of tomb you
            imagine Jesus to have been buried in, according to the Gospel
            accounts. ";
    }
    northLook
    {
        "To the north ";
        if(caveExit.isOpen)
            "sunlight streams in through the open"; 
        else
            "a large round stone blocks the";
        " mouth of the cave. ";      
    }  
;

+ caveExit : HiddenDoor 'cave open/entrance/mouth/(cave)' 'cave entrance'
    destination = lakeSide
    noteTraversal(traveler) { lakeSide.myCave = agrathCave;  }
    makeOpen(stat)
    {
        if(stat)
        {
            achievement.addToScoreOnce(1);
        }
        caveSunlight.makePresent();
        inherited(stat);
    }
    achievement : Achievement { "making the stone move so you can escape from
        the tomb" }
;

+ agrathCaveSlab : RoomPartItem, Bed, Fixture 'cold large hard stone slab' 
    'stone slab'
    "It's situated against the east wall of the cave, and is just large
    enough to lay a single body on. "
    feelDesc = "It feels cold and hard, just as you'd expect stone to feel. "
    cannotOpenMsg = 'There\'s no lid or anything else you could open on the
        slab. '
    cannotMoveMsg = 'The slab is carved out of the cave wall; you can\'t budge
        it. '   
    cannotTakeMsg = 'Even if the stone slab wasn\'t attached firmly to the
        floor and wall, it would be far too heavy to lift, but the fact that it
        has been carved out of the wall constitutes a second excellent reason
        why picking it up is not a practical proposition. '
    out = nil
    reachableObjects = [defaultEastWall]
    initNominalRoomPartLocation = defaultEastWall
    initSpecialDesc = "A large stone slab nestles against the east wall of the
        cave. "
    nothingBehindMsg = 'Behind the slab is the wall. '
;

/* 
 *   Note that, unusually, we make this stone an Actor. This is so that a 
 *   command can be addressed to it (telling to move or to open). We then 
 *   have to ensure that addressing any other conversation to the stone 
 *   won't give away the puzzle.
 */

+ agrathCaveStone: Hidden, CustomImmovable, Actor 'large round stone' 
    'large stone'
    "A large round stone covers the mouth of the cave, blocking the way out. "
    specialDesc = ""
    discovered = (!caveExit.isOpen)
    cannotTakeMsg = 'It\'s too heavy to budge. '
    dobjFor(Open)
    {
        verify()
        {
            if(gActor == self)
                logicalRank(150, 'open self');
            else
                inherited;
        }    
    }
    dobjFor(Move)
    {
        verify()
        {
            if(gActor == self)
                logicalRank(150, 'open self');
            else
                inherited;
        }    
    }
    obeyCommand(issuingActor, action)
    {
        if(action.baseActionClass is in(OpenAction, MoveAction)
           && action.dobjList_[1].obj_ == self && agrath.canSee(self)) 
        {
            "Feeling a little foolish, but trying to sound confident and
            authoritative and at least approximately like someone who isn't
            about to make a total ass of himself, you command, <q>Stone, move
            aside!</q>\b
            Agrath bursts into peals of helpless laughter, <q>Oh really, you
            are <i>too</i> much!</q> she squeals, <q>A New Testament scholar
            reduced to talking to a stone as if it would listen. Why don't you
            try <q>Open sesame!</q> next?</q>\b
            You blush bright red, but then, much to your astonishment the stone
            starts to judder.\b";
            inputManager.pauseForMore(nil);
            "<q>What is this?</q> Agrath cries, evidently disconcerted.\b
            In reply a loud voice, infinitely distant yet infinitely near booms
            out, <q>Enough, Agrath! Your mockery goes too far!</q>\b
            Very slowly, the stone begins to roll.\b
            <q>No! Stop! You can't do this!</q> Agrath protests.\b
            <q>It has been willed where what is willed must be,</q> the Voice
            replies.\b       
            You blink as the sunlight floods into the cave, then turn to watch
            Agrath's reaction. From the expression on her face, this was
            something else she was not expecting -- the sight of daylight fills
            her with evident horror. A kind of strangulated sound escapes from
            her lips, as she raises a hand to shield her face from the light.
            But even as she does so, she starts to be enveloped in a cloud of
            purple smoke; a moment later she starts to dissolve into the smoke,
            until nothing is left but the cloud. Then that too disperses and
            vanishes away.\b
            Of the Voice, there is no sign.";
            
            agrath.setCurState(agrathAbsent);
            agrath.setConvNode(nil);
            agrath.moveIntoForTravel(nil);
            caveExit.makeOpen(true);      
        }
        else 
            "The stone is deaf to your entreaties. ";
        
        return nil;
    }
    dobjFor(Attack)
    {
        verify() {}
        action()
        {
            "You pound the stone with your <<gVerbName == 'kick' ? 'feet' :
              'hands'>> but you don't even dent it. ";
        }
    }
    dobjFor(Break) asDobjFor(Attack)
    
    /* 
     *   This where we try to make the stone not behave like an actor, 
     *   except when a command is addressed to it.
     */
    
    dobjFor(AskAbout) { verify() { inherited Thing; } }
    dobjFor(TellAbout) { verify() { inherited Thing; } }
    dobjFor(AskFor)  { verify() { inherited Thing; } }
    dobjFor(TalkTo)  { verify() { inherited Thing; } }
    dobjFor(Hug)  { verify() { inherited Thing; } }  
    dobjFor(Kiss) { verify() { illogical(&cannotKissMsg); } }   
    dobjFor(KnockOn) { verify() { inherited Thing; } }  
    
    iobjFor(ShowTo)  { verify() { inherited Thing; } }
    iobjFor(GiveTo)  { verify() { inherited Thing; } }
    
    dobjFor(SmileAt)
    {  
        verify() { inherited Thing; }
        action() { inherited Thing;; }
    }
    notAddressableMsg(obj)
    { 
        gMessageParams(obj);
        return '{The obj/he} do{es} not seem terribly talkative. ';
    }
    notInterestedMsg(obj)
    { 
        gMessageParams(obj);
        return '{The obj/he} prove{s} utterly unresponsive. ';
    }
    nothingBehindMsg = &cannotSeeBehindMsg
    cannotEatMsg = (playerActionMessages.cannotEatMsg)
    tasteDesc = (inherited Thing.tasteDesc)
    
;

+ agrathLoculus: RoomPartItem, Container, Fixture 'burial loculus/niche' 'loculus'
    "The loculus is a niche set at about chest height in the west wall
    of the cave. <<agrathOssuary.discovered ? '' : agrathOssuary.discover()>>"   
    initNominalRoomPartLocation = defaultWestWall
    initSpecialDesc = "A single loculus has been carved in the west wall. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    nothingBehindMsg = &cannotLookBehindMsg
;

++ agrathOssuary: Hidden, ComplexContainer 'limestone (bone) box/ossuary' 'ossuary'
    "The ossuary is a box made of limestone, about nine inches long by six wide
    by five high. On its side are some strange carvings. "
    initDesc = "The ossuary is a box made of limestone; while it\'s in its
        loculus all you can see is one end of it, which is about six inches by
        five. "
    subContainer : ComplexComponent, OpenableContainer {
        dobjFor(Open)
        {
            verify() {
                if(lexicalParent.isIn(agrathLoculus))
                    illogicalNow('{You/he} can\'t open {the dobj/him} while
                        it\'s in the loculus.' );
                else
                    inherited;
            }
        }
    }
    dobjFor(PutIn)  {  preCond = static inherited + objClosed  }
    iobjFor(AttackWith) { verify() { } }
    smellDesc = "The ossuary has a distinctly musty smell. "
;

+++ Component 'strange carvings/designs/pentacles/tridents' 'carvings'
    "The designs carved into the side of the ossuary include pentacles and
    tridents. "
    isPlural = true
;

+++ Thing 'old bones' 'old bones'
    "They look like no more than a collection of old bones, possibly human, all
    scrunched up together. But as you look at them, a strange thing happens:
    <<transmogrify()>> "
    isPlural = true
    subLocation = &subContainer
    dobjFor(Take)
    {
        action()
        {
            "Just as your hand is about to clasp the bones, a strange thing
            happens: ";
            transmogrify();
        }
    }
    dobjFor(LookIn) asDobjFor(Examine)
    dobjFor(Feel)
    {
        action() 
        {
            "As soon as you touch the bones, a strange thing happens. ";
            transmogrify();
        }
    }
    dobjFor(Move) asDobjFor(Feel)
    dobjFor(Push) asDobjFor(Feel)
    dobjFor(Pull) asDobjFor(Feel)
    transmogrify()
    {
        "A cloud of purple smoke rises from the bones, which then dissolve into
        the cloud. Once this transformation is complete, the purple cloud wafts
        away to the centre of the cave, where it assumes a vaguely humanoid
        shape. At that point something green and demoness-shaped appears at its
        heart. The cloud begins to disperse, and as the last tendrils of purple
        smoke drift away, Agrath steps out of it, a fiendish grin on her
        face.\b
        <q>Don't look so surprised to see me -- you didn't really think I'd let
        you go that easily, did you?</q> she asks, <q>Besides, I've just had a
        rather wonderful idea. That egregiously silly little man whose lecture
        bored you to death seemed to think that resurrection was impossible and
        the empty tomb story just a midrashic myth. So, since you thought he
        was talking such tosh, <i>I</i> thought you and I should prove him
        wrong. You've done a good job of rising from the slab, I've just done a
        great conjuring trick with bones, so now all that remains is for you to
        roll back the stone.</q>";     
        moveInto(nil);
        agrath.noteConversation(gActor);
        agrath.moveIntoForTravel(gPlayerChar.getOutermostRoom);
        agrath.setCurState(agrathInTomb);
        agrath.addToAgenda(agrathSitAgenda.setDelay(2));
    }
;

+ caveSunlight : PresentLater, Vaporous 'sun day shaft/light/sunlight/daylight'
    'shaft of sunlight'
    "A shaft of sunlight (or at least, daylight of some description) streams
    in the through the open mouth of the cave. "
;

//==============================================================================

paganTemple : Room 'Pagan Temple' 'the pagan temple'
    "Rows of tall classical columns occupy this large rectangular area, which
    is otherwise devoid of decoration apart from the massive stone altar
    right at the centre, and the large gold thurible mounted directly behind
    it.  The way out to the street lies to the south. "
    south = statueStreet
    out : ConditionalConnector 
    { 
        -> statueStreet
        ": south or down"
        @(altarLid.isOpen)
    }   
    down = altarLid
    thinkHere = "This place makes you feel uncomfortable. Maybe it's simply the
        fact that you instinctively equate <q>pagan</q> with <q>bad</q>, or
        maybe it's the worrying fact that the thurible behind the altar is
        still emitting smoke, suggesting that this temple may not be quite so
        long deserted as the rest of the city would otherwise indicate. Either
        way, you have a bad feeling about this place. "
    southLook = "To the south is the way out back into the street. "
    outLook = (southLook)
    lookDirToRoomPart(dirn) { return nil; }
    defaultLook(dirn) { "You are surrounded by the interior of this pagan temple. "; }
    vocabWords = 'pagan interior/temple'
    disambigName = 'interior of the pagan temple'
;

+ Decoration 'tall classical rows*columns' 'classical columns'
    "Since you wouldn't know a Doric Column from a Corinthian Column unless
    they walked up to you wearing name tags, you're unable to classify the
    columns here as anything more precise than the kind of classical columns
    you normally associate with classical architecture in general and pagan
    temples in particular. "
    isPlural = true  
;

+ stoneAltar: Platform, Fixture 'large substantial massive (stone)
    altar/slab/base*altars*slabs'
    'large stone altar'
    "It's a substantial stone slab mounted on massive stone base. Presumably it
    was once used for blood-sacrifice, but that must have been a very long time
    ago, for you can mercifully see no bloodstains on it now. There is,
    however, a fairly prominent carving on the base. <<altarLid.isOpen ?
      'Moreover, the lid of the altar is open, revealing a way down into the
      darkness beneath. ' : ''>>"
    dobjFor(LookBehind)
    {
        verify() { }
        action() 
        { 
            "Behind the altar a large gold thurible is busily leaking purple
            smoke. "; 
        }
    }
    dobjFor(Enter) maybeRemapTo(altarLid.isOpen, TravelVia, altarLid)
    dobjFor(Climb) asDobjFor(StandOn)
    cannotTakeMsg = 'It would be too heavy for four men twice your strength to
        lift. Besides, it appears to be solidly fixed in place. '
    cannotMoveMsg = 'You can\'t budge it. '
    shouldNotBreakMsg = 'You fail to make any impression on the solid stone. '
    cannotCleanMsg = 'You\'d rather leave that job to the worshippers. '   
    cannotOpenMsg()
    {
        if(altarLid.isOpen)
            return 'It\'s already open. ';
        else
            return 'You pull against the top of the altar but it won\'t budge. ';
    } 
    cannotCloseMsg()
    {
        if(altarLid.isOpen)
            return altarLid.cannotCloseMsg;
        else
            return 'It isn\'t open. ';
    }
    notASurfaceMsg = (gIobj == self ? notWhileOpenMsg : nil)
    notWhileOpenMsg = 'You can\'t do that while the lid is open. ' 
    cannotStandOnMsg = (notWhileOpenMsg)
    cannotSitOnMsg = (notWhileOpenMsg)
    cannotLieOnMsg = (notWhileOpenMsg)
    reachableObjects = [altarLid]
    lookInDesc
    {
        if(altarLid.isOpen)
            "In the altar is an opening through which you could descend. ";
        else
            inherited;
    }
;

+ altarLid : SecretDoor 'altar flat slab lid/top/opening*lids' 'altar lid'
    "<<isOpen ? ' The lid of the altar has swung open, revealing a staircase 
        leading down' : 'It\'s just a flat slab covering the altar'>>. "
    openOrClose() { makeOpen(!isOpen); }
    makeOpen(stat)
    {
        inherited(stat);
        "Pushing the left foot on the carving causes the lid of the altar to
        swing <<stat ? 'open' : 'closed'>>. ";
        if(stat)
        {
            local l = stoneAltar.contents.length;
            if(l > 0)
            {
                "As the lid opens, << l==1 ? stoneAltar.contents[1].theName :
                  'everything'>> resting on it slides off onto the floor. ";
                foreach(local cur in stoneAltar.contents)
                    cur.moveIntoForTravel(stoneAltar.location);
            }
            achievement.addToScoreOnce(1);      
            stoneAltar.setSuperclassList([Fixture]);
        }
        else
        {      
            stoneAltar.setSuperclassList([Platform, Fixture]);      
        }
    }
    achievement : Achievement { "opening the lid of the stone altar in the
        pagan temple" }
    dobjFor(Open) remapTo(Open, stoneAltar)
    dobjFor(Close) remapTo(Close, stoneAltar)
    dobjFor(Push) asDobjFor(Close)
    dobjFor(Pull) asDobjFor(Open)
    dobjFor(LookIn)
    {
        remap()
        {
            if(isOpen)
                return [LookThroughAction, self];
            else
                return [LookInAction, stoneAltar];
        }
    }
    iobjFor(PutOn) remapTo(PutOn, DirectObject, stoneAltar)
    iobjFor(TakeFrom) remapTo(TakeFrom, DirectObject, stoneAltar)
    dobjFor(StandOn) remapTo(StandOn, stoneAltar)
    dobjFor(SitOn) remapTo(SitOn, stoneAltar)
    dobjFor(LieOn) remapTo(LieOn, stoneAltar)
    
    nothingThroughPassageMsg = 'Through the opening on top of the altar
        you see a staircase leading down. '
    cannotCloseMsg = 'You push down on the altar lid, but it won\'t budge. '
;

+ Hidden, StairwayDown, Platform 'staircase/stairs/steps' 'staircase'
    "The staircase leads down through the altar. "
    discovered = altarLid.isOpen
    destination = paganCrypt 
;


+ NameAsOther, SecretFixture
    targetObj = stoneAltar
;

++ womanCarving: Component 'fairly erotic prominent carving/woman/aphrodite/agrath' 
    'carving'
    "The carving depicts a lithe young woman lying on her back in a seemingly
    erotic posture among a cloud of long hair that spills down her back.
    <<gRevealed('green-skin') ? 'Once again you are reminded of the
        green-skinned woman depicted in the cathedral windows; could this be a
        temple to her honour? You wonder which goddess she\'s meant to
        represent.' : 'Perhaps she represents the goddess to whom this temple
            is dedicated: Aphrodite?'>> The entire statue is carved in relief,
    but you notice that the (naked) left foot is particularly prominent,
    perhaps because the woman has her legs crossed at the ankles.
    <<paganKey.isIn(carvingHand) ? 'For some strange reason she\'s shown
        holding a key in her right hand -- though the symbolism of this escapes
        you. ' : ''>>When you look very closely you also note that the pupil of
    the right eye is represented by a hollow, which might even be a small
    hole. "
    cannotKissMsg = 'That would feel too uncomfortably like an act of
        worshipping this pagan goddess. '
    isIt = true
    isHer = true
;

+++ Component 'long copious cloud/hair/tress/tresses' 'hair'
    "It's carved to look almost unbelievably copious, flowing round well over
    half the length of her body. "
    isMassNoun = true
    feelDesc = "Just rough stone. "
    owner = womanCarving
;

+++ carvingLeftFoot: Component 'prominent naked left foot*feet' 'left foot'
    "There may be artistic reasons for it, but the carving's left foot
    does seem rather prominent. "
    dobjFor(Push)
    {
        verify() { nonObvious; }
        action() { 
            if(gActor.isIn(stoneAltar))
                tryImplicitAction(GetOffOf, stoneAltar);
            if(steelRod.isIn(carvingEye))
                altarLid.openOrClose(); 
            else
                "The foot seems to move a bit, but nothing else happens.
                <.reveal push-foot>";
        }
    }
    dobjFor(Move) asDobjFor(Push)
    dobjFor(Pull) 
    { 
        verify() { illogical('You can\'t move it by pulling it. '); }
    }
    owner = womanCarving
;

+++ Unthing 'naked right foot*feet' 'right foot'
    'You can\'t really see it; it\'s hidden behind the left one. '
    owner = womanCarving
;

+++ carvingEye: Component, RestrictedContainer 
    'right small eye hole/eye/hollow/pupil*eyes' 'right eye'  
    "The right eye of the carving contains a small hole or hollow
    at its centre, where you'd expect the pupil to be. "
    validContents = [steelRod]
    owner = womanCarving
;

+++ Unthing 'left eye*eyes' 'left eye'
    'The way the figure is carved, you can only see the right side of her face. '
    owner = womanCarving
;

+++ Unthing 'carving\'s left hand*hands' 'left hand'
    'The carving shows the right side of the woman\'s body, so her left hand
    isn\'t shown. '
    owner = womanCarving
;


+++ carvingHand: RestrictedContainer, Component 'carving\'s right hand/fingers*hands' 
    'carving\'s right hand'
    "The right hand of the carving is depicted with long fingers and pretty
    long nails. <<paganKey.isIn(self) ? 'The fingers lightly clutch a small
        key. ' : '' >>"
    validContents = [paganKey]
    owner = womanCarving
;

++++ paganKey : Key 'small realistic stone stone-coloured metal key*keys' 
    'small stone-coloured key'
    "Although it's made of stone, or at least of something stone-coloured, this
    small key looks like it could be functional. "
    initSpecialDesc = ""
    initDesc = "When you examine the key really closely, it seems not only to
        stand out from the carving but actually to have been carved from a
        separate piece of material. "
    feelDesc = "When you touch it you wonder whether it is actually made of
        stone, or whether it's actually metal cunningly painted to look like
        stone. "
    dobjFor(Pull) maybeRemapTo(isIn(carvingHand), Take, self)
    dobjFor(Take)
    {
        verify()
        {
            if(!moved)
                nonObvious;
            else
                inherited;
        }
        action()
        {
            if(isIn(carvingHand))
                "{You/he} manage{s} to pull the key free of the carved hand. ";
            inherited;
        }
    }   
    hideFromAll(action) 
    { 
        return action.baseActionClass is in (TakeAction, PullAction) && !moved; 
    }
    
;

+ Decoration 'large golden gold thurible/stand/censer/sphere' 
    'large golden thurible'
    "Normally you'd expect to see a thurible wielded by an acolyte, but this
    one is mounted on a stand. It's basically a large gold sphere, pierced with
    holes, from which a thin cloud of purple smoke is gently wafting. "
    notImportantMsg = 'It\'s probably best left alone. '
;

++ Component 'small round (thurible) holes' 'small holes'
    "A number of small round holes allow smoke to emanate from the thurible. "
    isPlural = true
    disambigName = 'thurible holes'
;

+ Vaporous 'thin gently wafting lazily drifting purple smoke/cloud/incense' 
    'purple smoke'
    "The purple smoke rises slowly out of the thurible and drifts lazily
    towards the ceiling. "
    isMassNoun = true
;

++ Odor 'sweet smell/(incense)' 'smell'
    sourceDesc = "It smells strangely sweet, a little like rose petals perhaps.
        Whatever it is, it would be singularly appropriate to Aphrodite. "
    descWithSource = (sourceDesc)
    hereWithSource = "There's a sweet smell of incense in the air, a little
        like rose petals. "
    displaySchedule = [2, 4, 8]
;

+ SimpleNoise 'seductive female voice/silence' 'seductive voice'
    "Almost below the threshold of consciousness, a seductive female voice
    seems to be calling you; but when you strain to listen to it, all you can
    hear is silence. "
;

+ Unthing 'acolyte' 'acolyte'
    'There\'s no acolyte here; perhaps that\'s why the thurible has been left
    on a stand. '
;

//==============================================================================

paganCrypt : Room 'Crypt' 'the crypt'
    "The purpose of this small square chamber isn't entirely clear. There's
    nothing to suggest that anyone's ever been buried here, and if it's simply
    a storage cellar there's nothing stored here now. All this room has to
    offer is a flight of stairs leading up and a faded blue door leading
    north. "    
    north = paganCryptDoor
    up = paganCryptStairs
    thinkHere = "You wonder about the purpose of this small chamber beneath a
        concealed opening on a stone altar. You suspect that it might have been
        designed for some kind of trickery, perhaps to enable the scaring or
        impressing of worshippers with supposedly supernatural manifestations
        of their goddess, but you can't quite figure out how it would work. "
    upLook = "A flight of stairs leads up through a hole in the ceiling. "
    northLook = "Directly to the north is a faded blue door. "
;

+ paganCryptStairs : StairwayUp, Platform ->altarLid 'flight/stairs/staircase' 
    'flight of stairs'
    "The stairs lead back up to the temple above. "
;

+ paganCryptDoor : LockableWithKey, Door 'faded blue door' 'faded blue door'
    "It was once painted blue, but that must have been a very long time ago. "
    keyList = [paganKey]
;


paganCryptTunnel : Room 'Long Tunnel' 'the long tunnel'
    "From the pale blue door immediately to the south the tunnel stretches off
    northwards for about thirty yards, where it meets several more in what
    looks like a fairly confusing junction. "
    north = confusingJunction
    south = paganCryptTunnelDoor
    achievement : Achievement { "getting through the faded blue door" }
    enterRoom(traveler) {  achievement.addToScoreOnce(1);  }
    thinkHere = "You feel torn: part of you feels distinctly apprehensive about
        the junction up ahead, since it looks rather too easy to get lost,
        while another part feels that having got this far, you may as well
        explore further. "  
    roomParts = static inherited - defaultNorthWall
    northLook = "<<cJunction.desc>> "
    southLook = "Immediately to the south is the way back through the blue
        door. "
;


+ paganCryptTunnelDoor : Door ->paganCryptDoor 
    'faded blue door' 'faded blue door'    
;

+ cJunction: Enterable, Distant ->(paganCryptTunnel.north) 
    'fairly confusing junction' 'confusing junction'
    "The junction lies some thirty yards or so to the north. You can't make out
    or count all the passages that meet there, but it looks like it could be
    quite confusing to negotiate. " 
;

/* 
 *   When I wrote these two additional routes to get to the labyrinth I 
 *   wasn't sure about them, so I gave myself the option to exclude them via 
 *   conditional compilation (the #ifdef syntax). In the end my beta-testers 
 *   seemed to like them well enough, so they made it into the game. 
 */  

#ifdef __MULTIROUTE
//==============================================================================
belowCellar : Room 'Under Cellar' 'under the cellar'
    "There seems to be nothing of note in this small square under-cellar, apart
    from a flight of stairs leading up to an aperture in the ceiling and a long
    passage leading away to the north towards a distant junction. "
    up = belowCellarStairs
    north = belowStairsPassage
    northLook = "A long passage leads off to the north towards a distant
        junction. "
    thinkHere = "You're in two minds about proceding from here; some instinct
        warns you that what lies ahead could be quite scary. "
;

+ belowCellarStairs: StairwayUp, Platform ->statueDoor 
    'flight/stairs' 'flight of stairs'
    "The flight of stairs leads up to an aperture in the ceiling. "
;

+ belowStairsPassage: ThroughPassage 
    'long straight passage' 'long passage'
    "The long passage runs straight north for quite a way, until it reaches a
    distant junction. "   
    destination = confusingJunction
;  


+ Enterable, Distant -> (belowCellar.north) 
    'distant junction' 'distant junction'
    "It's a bit too far away to make out the details from here. "
;

+ RoomPartItem, ThroughPassage 'square aperture' 'square aperture'
    "The square aperture is in the ceiling at the top of the flight of stairs
    that leads up to it. "
    destination = gardenCave
    initNominalRoomPartLocation = defaultCeiling
    initSpecialDesc = "In the ceiling is a square aperture at the top of the
        flight of stairs. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
;



confusingJunction : Room 'Confusing Junction' 'the confusing junction'
    "This junction is quite confusing; there are very similar tunnels leading
    off to north, northeast, northwest, east and west, while a passage leads
    back to the south. "
    
    thinkHere = "You're fairly confident
        that the passage to the south will take you back the way you came, but
        you've no ideas where any of the others might go, nor how easy it would
        be to find your way back if you go down any of them. "
    
    south = confusingPassage
    north = confusingTunnel
    northeast = confusingTunnel
    northwest = confusingTunnel
    west = confusingTunnel
    east = confusingTunnel   
    southLook = "To the south a passage runs comfortingly back the
        way you came. "
    lookDirToRoomPart(dirn) { return dirn is in (upDirection, downDirection); }
    defaultLook(dir)
    {
        if(dir is in (southeastDirection, southwestDirection))
            inherited(dir);
        else
            "To the <<dir.name>> you look down a long, gloomy tunnel. ";       
    }
;

+ confusingPassage: TravelWithMessage, ThroughPassage
    '(s) (south) passage' 'passage'
    "The passage leads back to the south. "
    destination = (location.travelOrigin)
    travelDesc = "You retrace your steps back down the passage. "
    getApparentDestination(origin, actor) { return destination; }
    
;

+ confusingTunnel : TravelWithMessage, ThroughPassage 
    'long gloomy uninviting tunnel*tunnels' 'long tunnel'
    "Each of the tunnels looks pretty much like all the others: long, gloomy and
    uninviting. "
    destination = maze1
    travelDesc = "You walk along the tunnel for a short distance, and then find
        that it begins to twist and turn, so that you lose all sense of
        direction. Eventually you arrive at your worst nightmare, another
        junction with exits leading off in all directions and no sense of which
        way you came from. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    nothingBehingMsg = &cannotLookBehindMsg
;


//==============================================================================

vsFloor: Floor
    vocabWords = ''
    name = 'shifting patch of colour'
    theName = (aName)
;

veryStrangePlace: Room 'Very Strange Place' 'the very strange place'
    "Weirdness comes in many forms, but this is one of the weirder ones.
    Presumably this is a place of sorts, since you continue to exist here, but
    it has none of the obvious characteristics of a place -- no obvious
    boundaries, nothing much to orient yourself by, nothing much of anything
    very concrete. What surrounds you is not so much anything you could
    identify as physical objects, but rather continually shifting patches of
    colour. There are, however, two patches of colour -- one green and one
    brown -- that seem to remain relatively constant. "   
    roomParts = [vsFloor] 
    enterRoom(traveler) { achievement.addToScoreOnce(1); }
    achievement: Achievement { "passing through the dawn cave wall" }
    thinkHere = "You think this place is exceedingly strange. You also think you'd
        like to get out of it. "
    defaultLook(dir) { desc; }
;

class ColourPatch: EntryPortal, Distant 'color/colour/patch*patches' 'patch'
    dobjFor(TravelVia)
    {
        action()
        {
            "{You/he} focus{es} on <<theName>>, and somehow manage to will
            {yourself} to move towards it. Somehow, this works, and {you/he}
            find{s} {yourself} passing through it.<.p><.reveal colour-patch>";
            inherited;
        }
    }  
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }  
    dobjFor(LookIn) asDobjFor(Examine)  
    nothingBehindMsg = '{You/he} {can\'t} see behind {the dobj/him}. '
    nothingThroughMsg = '{You/he} {can\'t} see through it; it\'s opaque. '
    collectiveGroup = patchGroup
;

+ patchGroup: CollectiveGroup 
    'continually confusing rainbow shifting psychedelic 
    kaleidoscope/colour/patch*patches*colours' 'patches of colour' 
    
    "There are patches of every shape and shade here, an ever shifting rainbow
    kaleidoscopic rainbow. But amidst the whirling confusion, two patches
    remain relatively fixed: a green patch slighty to the right, and a brown
    patch over to the left. None of the others remain remotely fixed, but are
    in a continual state of flux, shifting shape and size and hue before you
    have a chance to even begin thinking about classifying them. "  
;

+ greenPatch :ColourPatch ->smallCove 'large green -' 'green patch'
    "It keeps shifting shape and shade, but it remains always green, and, so
    far as you can tell without anything to give you any sense of perspective,
    always roughly person-sized. It also seems to remain roughly in the same
    place -- always slightly to the right of the centre of your field of
    vision. "
    
;   

+ brownPatch: ColourPatch ->antiquity 'large brown -' 'brown patch'
    "It keeps shifting shape and shade, but it remains always brown, and, so
    far as you can tell without anything to give you any sense of perspective,
    always roughly person-sized. It also seems to remain roughly in the same
    place -- at the left edge of your field of vision. "
    
;

+ patchPassage : EntryPortal
    connector = patchConnector
;

+ patchConnector: AskConnector, SecretFixture
    travelObjs = [greenPatch, brownPatch]
    travelObjsPhrase = 'patch'
;  


+ SimpleNoise 'abstract electronic atonal music' 'music'
    "There is a sound, but again it's hard to classify. The nearest you can get
    is that it's a little like electronic music, of a peculiarly abstract and
    atonal nature. "  
;

//==============================================================================
class GroundSurface : Fixture
    dobjFor(StandOn) remapTo(Stand)
    dobjFor(SitOn) remapTo(SitOn, location.roomFloor)
    dobjFor(LieOn) remapTo(LieOn, location.roomFloor)
    iobjFor(PutOn) remapTo(Drop, DirectObject)
;

goldKey : Key 'small gold key*keys' 'small gold key'
;

goldCoin: Thing 'large round gold coin' 'gold coin'
    "The coin in large and round. The observe bears the head of a long-haired
    woman with angular features, while the reverse is stamped <q>50 CROWNS</q>."
;

smallCoveGround: defaultGround 'sandy ground/floor' 'sandy ground'
    "The ground here is mostly sand. "
    dobjFor(DigWith) remapTo(DigWith, coveBeach, IndirectObject)
;

smallCove : OutdoorRoom 'Small Cove' 'the small cove'
    "A vast emerald green sea stretches as far as you can see to the west. High
    cliffs enclose the other three sides of the cove, but a narrow path leads
    up that to the east. Someone has planted a wooden notice in the sand just
    by the shore. " 
    west : NoTravelMessage { "<<emeraldSea.cannotWalkOnMsg>>" }
    east = covePath
    up asExit(east)  
    roomParts = [smallCoveGround, blueSky]
    thinkHere = "You think this seems a pleasant enough place, and you're not
        quite sure what it's doing in hell. "
    westLook = "You look out over the vast emerald sea, which stretches to the
        horizon. "
    eastLook = "High cliffs ring the beach, but to the east a narrow path leads
        up the cliffside. "
    defaultLook(dirn)
    {
        if(dirn is in (southwestDirection, northwestDirection))
            westLook;
        else
            "You look <<dirn.name>>wards across the golden sands to the high
            cliffs that ring the beach. ";
    }
;

+ woodenNotice: Readable, CustomFixture 'large white wooden notice/stake/board/sign' 
    'wooden notice'
    "It consists of a large white board attached to a white wooden stake. The
    notice reads: <<readDesc>>. "
    readDesc = "<q>PLEASE DO NOT WALK ON THE WATER</q>"
    cannotTakeMsg = 'It seems that whatever {you/he} do{es}, the notice will not
        come free of the sand. '
;

+ emeraldSea: Fixture 'vast calm emerald green sea/ocean/water/waves' 'emerald green sea'
    "The sea looks fairly calm at the moment, although there's a constant
    stream of gentle waves undulating languidly towards the shore. The sea
    itself stretches all the way to the horizon; for all {you/he} know{s} it
    could be a vast ocean. "
    cannotDrinkMsg = 'The water is too salty to drink. ' 
    cannotWalkOnMsg = 'Walking on water is not allowed here: please read the
        notice. '
    dobjFor(Swim)
    {
        verify() { }
        action() {
            "The sea is cold, but not too cold, and the swim proves bracing.
            Since there's no other land in sight, however, after swimming round
            the cove you eventually have no choice but to return to the
            beach. ";
            if(!goldKey.moved)
            {
                "Just as you are about to wade ashore, you notice a golden
                glint in the sand under the shallow water. You stoop to look
                closer and dig round it, and find that you have found a small
                gold key, which you pick up and keep. ";
                goldKey.moveInto(gActor);
            }       
        }
    }
    lookInDesc = "Basically, there's a lot of water in it. "
    nothingThroughMsg = 'You can\'t see much through the green water. '
    nothingUnderMsg = 'You can\'t see what lies beneath the waves. '
    nothingBehindMsg = 'Whatever lies beyond the ocean is too far away to see. '
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
;

++ SimpleNoise 'sound' 'sound'
    "All seems quiet apart from the gentle sound of waves lapping against the
    shore. "
;

++ SimpleOdor 'salty tang/air' 'salty tang'
    "The air has a distinctly salty tang -- no doubt due to the sea. "
;

+ CustomImmovable 'fine yellow golden sand/sands' 'fine yellow sand'
    "The sand on this beach is fine and yellow. "
    cannotTakeMsg = '{You/he} {has} no conceivable use for {the dobj/him}. '
    isMassNoun = true
    dobjFor(DigWith) remapTo(DigWith, coveBeach, IndirectObject)
    futileToKnockOnMsg = (coveBeach.futileToKnockOnMsg)
    nothingLookBehindMsg = 'Behind the sand stand the cliffs. '
;

+ coveBeach: GroundSurface 'beach/shore' 'beach'
    "The beach is an area of fine yellow sand enclosed by high cliffs to east,
    west and south and the sea to the west. "
    dobjFor(DigWith)
    {
        verify() {}
        action() {
            "You dig in the sand in many places all over the beach";
            if(goldCoin.moved)
                ", but you find nothing more of interest. ";
            else
            {
                " until, just at the point of giving up, you eventually discover 
                a large coin gold. ";
                goldCoin.moveInto(smallCove);
                gSetSeen(goldCoin);
            }
        }
    }
    futileToKnockOnMsg = 'The sand deadens the sound of your knocking. ' 
    nothingLookBehindMsg = 'Behind the beach are the cliffs that enclose it. '
;



+ Fixture 'high steep rugged cliff*cliffs' 'high cliffs'
    "The cliffs surround the beach to north, east and west. They are steep and
    rugged, so the only way to climb would be up the path leading up to the
    east. "
    dobjFor(Climb) remapTo(Climb, covePath)
    dobjFor(ClimbUp) remapTo(Climb, covePath)
    nothingBehindMsg = cannotLookBehindMsg
;

+ covePath: TravelWithMessage, StairwayUp, Platform 'narrow path' 'narrow path'
    "A narrow path winds up the cliff to the east. "  
    travelDesc = "You climb up the long winding path from the beach and
        eventually arrive at a wide open lawn at the top. "
    dobjFor(Follow) asDobjFor(TravelVia)
    dobjFor(Take) asDobjFor(TravelVia)
;

MultiLoc, Distant 'distant far western (w) horizon/line' 'horizon'
    "The horizon is the distant line where the sea meets the sky, far to
    the west. "
    locationList = [smallCove, largeLawnNorth]
;

DistanceConnector [largeLawnSouth, largeLawnNorth];

//==============================================================================
largeLawnNorth : OutdoorRoom 'Large Lawn (north)' 'the north end of the lawn'
    "The clifftop affords a magnificent view over the emerald green sea,
    stretching as far as you can see to the distant horizon. From here, a
    narrow path leads back down the cliff to the cove, though the cove itself
    is hidden from sight. Inland, a perfectly flat lawn sweeps towards the
    south, where, at some distance, you can see a small green building. There's
    another green building, a small garden shed, directly to the north while to
    the east a wide path leads off through a row of evergreens. "
    west = llnPath
    down asExit(west)
    south = largeLawnSouth
    north = gardenShedDoor
    east = largeLawnPath
    in asExit(north)
    thinkHere = "You wonder who keeps this lawn so neatly trimmed, since
        there's no sign of anyone around. "
    northLook = "Directly to the north is a small green garden shed. "
    southLook = "You look southwards across the neatly-kept lawn towards a
        small green building at its far end. "
    eastLook = "To the east a wide path leads off through a row of evergreens. "
    westLook = "The cliff edge is just to the west, but you can see the start
        of the narrow path that leads down it. "
    vocabWords = 'large lawn/clifftop'
;

+ llnPath : TravelWithMessage, StairwayDown, Platform -> covePath 
    'narrow winding path' 'narrow path'
    "The narrow path winds down from the top of the cliff. "
    travelDesc = "You clamber down the long winding path back to the beach. "
;

+ greenGardenShed: Enterable ->gardenShedDoor 
    'green small square (garden) shed/hut*buildings' 'garden shed'
    "It's a small, square neat-looking shed, freshly painted green, with an
    equally green door. "
    dobjFor(Open) remapTo(Open, gardenShedDoor)
    dobjFor(Close) remapTo(Close, gardenShedDoor)
    dobjFor(Unlock) remapTo(Unlock, gardenShedDoor)
    dobjFor(UnlockWith) remapTo(UnlockWith, gardenShedDoor, IndirectObject)
    dobjFor(OpenWith) remapTo(OpenWith, gardenShedDoor, IndirectObject)
    dobjFor(Lock) remapTo(Lock, gardenShedDoor)
    dobjFor(LockWith) remapTo(LockWith, gardenShedDoor, IndirectObject)
    nothingBehindMsg = &cannotSeeBehindMsg
;

++ gardenShedDoor: LockableWithKey, Door 'green (garden) (shed) door*doors' 
    'shed door'
    "It's green, like the rest of the shed. "
    keyList = [shedKey]
    cannotOpenLockedMsg = 'The shed door is locked. <.reveal shed-locked>'
    lockStatusObvious = (gRevealed('shed-locked'))
    dobjFor(Pull) asDobjFor(Open)
    dobjFor(Push) asDobjFor(Close)
;

+ largeLawnPath : TravelWithMessage, PathPassage ->orchardPath 
    'wide broad path' 'wide path'
    "It leads off through the trees to the east, and then disappears out of sight. "
    travelDesc = "You follow the path through the trees, and then on through a
        clump of bushes, and soon arrive at an orchard. "
    nothingBehindMsg = &unclearWhatBehindMsg
;

MultiLoc, Decoration 'tall evergreen row/trees*evergreens' 'tall trees'
    "A row of tall evergreen trees lines the east side of the lawn, effectively
    screening whatever lies behind them. "
    locationList = [largeLawnNorth, largeLawnSouth]
    isPlural = true
;

//==============================================================================
insideShed : Room 'Inside the Shed' 'the inside of the shed'
    "It's a cramped space, with just enough room for the tools used by whoever
    maintains the lawn, and perhaps the shrine as well, though there's not much
    here at the moment. A single shelf runs against the east wall. "
    out = insideShedDoor
    south asExit(out)
    thinkHere = "You think that this seems a very ordinary garden shed. "
    outLook = (southLook)
    northLook
    {
        if(spade.moved)
            defaultLook(northDirection);  
        else
            "You see a spade leaning against the north wall of the shed. ";
    }
    defaultLook(dirn) { "You see nothing that way but the shed wall. "; }
    throwDests = [[southDirection, insideShedDoor]]
;

+ insideShedDoor : RoomPartItem, Door -> gardenShedDoor 
    'plain wooden door' 'door'
    "It's just a plain wooden door. "
    initNominalRoomPartLocation = defaultSouthWall
    initSpecialDesc = "The door is in the south wall of the shed. "
    dobjFor(Push) asDobjFor(Open)
    dobjFor(Pull) asDobjFor(Close)
;

+ RoomPartItem, Surface, Fixture 'short wooden shelf*shelves' 'short wooden shelf'
    "It's a short wooden shelf running along the east side of the hut at about
    chest height. "
    initNominalRoomPartLocation = defaultEastWall
    initSpecialDesc = "A short wooden shelf is fixed to the east wall of the shed. "  
    nothingBehindMsg = 'Behind the shelf is the wall to which it\'s fixed. '
;

++ casket: KeyedContainer 'beautifully engraved gold abstract 
    designs/casket/box*boxes*caskets' 
    'gold casket'
    "The gold casket is beautifully engraved with abstract designs. It's about
    nine inches long by five wide and four high. "
    initiallyLocked = true
    keyList = [goldKey]
    achievement: Achievement { "opening the gold casket" }
    makeOpen(stat)
    {
        inherited(stat);
        if(stat)
            achievement.addToScoreOnce(1);
    }
    cannotOpenLockedMsg = 'The casket is locked. <.reveal casket-lock>'
    lockStatusObvious = (gRevealed('casket-lock'))
    weight = 4
    bulk = 2
    iobjFor(AttackWith) { verify() { } }
    shouldNotBreakMsg = 'You cannot; it is too strongly made. '
    uselessToAttackMsg = 'You can\'t even dent it. '
    
;

+++ ornateScroll : Readable 'ornate scroll*scrolls' 'ornate scroll'
    "The ornate scroll is written in an equally ornate hand. Pity the poet's
    verse wasn't of the same standard as his caligraphy, since it's pretty much
    doggerel:\b<<readDesc>>"
    readDesc = "<q>ODE TO THE GREEN QUEEN\n
        Oh splendid one, who art our Queen,\n
        Thou art so magnificently green!\n
        To serve thee as we know we ought\n
        This is all we need be taught:\n
        First, till thou art wholly stone\n
        Thou wilt in no wise leave alone\n
        Those who elsewise would be fine\n
        To venture boldly in thy shrine.\n
        Those who there do enter in\n
        Must offer there the root of sin:\n
        That is, for those who would believe,\n
        The fruit that Adam took from Eve.\n
        But by itself that's not enough:\n
        Thou dost require some richer stuff:\n
        Some say that sin's as sweet as honey,\n
        While others that its root is money,\n
        So when into thy shrine we dash,\n
        We must be sure to bring some cash\n
        (if all else fails some should be found\n
        well buried in some yellow ground).\n
        Next, if wholly stone some part\n
        Of thee is not, besides thy heart,\n
        Then we must pull what still hangs free\n
        But not too oft, for that would be\n
        To make thee wroth, O fearsome Queen,\n
        and on offender vent thy spleen.\n
        Yet in thy mercy, whate'er's amiss\n
        May yet repaired be with a kiss.</q>"
    futileToKnockOnMsg = 'The scroll rustles a little. '
;


+ spade: Thing 'new sturdy spade*spades' 'sturdy spade'
    "It looks reasonably new and in pretty good condition. "
    initSpecialDesc = "A sturdy spade leans against the wall. "
    initNominalRoomPartLocation = defaultNorthWall
    iobjFor(DigWith) { verify() {} }
    iobjFor(AttackWith) { verify() {} }
    bulk = 4
    weight = 3
;


MultiLoc, GroundSurface 'large spectacularly level neat short green carpet/lawn/grass' 
    'large lawn'
    "The lawn is spectacularly level, an impeccable carpet of neat, short green
    grass. "
    locationList = [largeLawnNorth, largeLawnSouth]
    futileToKnockOnMsg = 'This action proves futile. ' 
;

+ Distant 'emerald green pretty calm sea' 'sea'
    "The emerald green sea stretches all the way to the western horizon. It
    looks pretty calm today. "
;

//=================================================================================
greenApple : Food 'large round juicy picked green apple*apples*fruit' 
    'large green apple'
    "It's large, round, juicy and green. "
    disambigName = 'picked apple'
    dobjFor(Eat)
    {
        action() 
        {
            "It proves to be crisp, juicy and sweet; a fine apple, in fact.
            Once you finish it you toss away the core, and it vanishes
            forgotten out of sight. ";
            moveInto(nil);
        }
    }
    dobjFor(Take)
    {
        verify()
        {
            if(!isIn(gActor) && gActor.canTouch(self))
                logicalRank(120, 'already picked');
            else
                inherited;
        }
    }  
;

orchard : OutdoorRoom 'Orchard' 'the orchard'
    "Fruit-laden apple trees abound in irregular rows to north, south and east,
    while a broad path leads through the thick bushes to the west. Apart from
    that western boundary, it's hard to see where the orchard ends. "
    west = orchardPath
    east : TravelMessage { -> orchardEdge
        "You walk for a mile or so through the orchard, and eventually arrive
        at its eastern edge. "
    }
    south : FakeConnector { "You wander southwards among the trees for a while,
        but finding nothing of any particular interest you eventually return to
        your starting point. " }
    north : FakeConnector { "You amble northwards through the trees without
        encountering anything that grabs your attentions, so after a while you
        turn round and come back. " }   
    thinkHere = "This strikes you as being an unusually large orchard. "
    westLook = "To the west a path leads through thick bushes. "
    defaultLook(d) { "You are surrounded by apple trees on every side. "; }
;

+ orchardPath: PathPassage 'wide broad path' 'wide path'
    "The path leads west through the bushes. "
    nothingBehindMsg = &unclearWhatBehindMsg
;

+ Underside, Fixture 'thick abundant green foliage/bush*bushes' 'thick green bushes'
    "Like everything else round here, the thick bushes grow green and abundant,
    forming a screen along the western border of the orchard.
    <<shedKey.isIn(self) ? 'Something -- perhaps something only half-observed
        and semiconsciously registered -- suggests they may repay closer
        scrutiny. ' : ''>>"
    isPlural = true
    lookInDesc(){
        if(shedKey.isIn(self))
            "You don't actually find much <i>in</i> the bushes, apart from the
            obvious foliage, but maybe whatever it was you thought you saw
            wasn\'t actually <i>in</i> the bushes. ";
        else
            "There\'s nothing in the bushes apart from the foliage you'd expect
            to find. ";
    }
;

++ shedKey: Hidden, Key 'large steel iron key*keys' 'large steel key'
    "It's just a plain ordinary key, of the sort that might be used for an
    outbuilding. "
;

++ Fixture 'apple irregular fruit-laden spreading rows/tree*trees' 'apple trees'
    "The spreading apple trees fill the orchard, each one laden with large
    green apples (naturally the apples here would be green). " 
    
    isPlural = true
;

+++ Component 'large ripe green apple*apples*fruit' 'ripe green apples'
    "The apples look large and green and ripe for picking. "
    dobjFor(Take)
    {
        verify() {  }
        check() {
            if(greenApple.location != nil)
            {
                reportFailure('{You/he} do{es}n\'t need another apple right
                    now, and to take more than {it actor/he} need{s} would be a
                    waste. ');
                exit;
            }
        }
        action()
        {
            "{You/he} pick{s} an apple from one of the trees. ";
            greenApple.moveInto(gActor);
        }
    }
    dobjFor(Eat)
    {
        preCond = [touchObj]
        verify() { }
        action() {
            if(!greenApple.isIn(gActor))
                tryImplicitAction(Take, self);   
            if(greenApple.isIn(gActor))
                replaceAction(Eat, greenApple);
        }
    }
    dobjFor(Examine)
    {
        verify() { logicalRank(90, 'on tree'); }
    }
;

//==============================================================================
orchardEdge: OutdoorRoom 'Edge of Orchard' 'the edge of the orchard'
    "From the eastern edge of the orchard, you see the trees stretching out
    westwards as far as you can tell, while all around you to north, east and
    south is a strange mist. "
    south = mistConnector
    north = mistConnector
    west = orchard
    east = mistConnector
    mistConnector: TravelMessage { ->veryStrangePlace
        "You take a single step into the strange mist and find yourself
        sucked into a very strange place. " }
    thinkHere = "You sense that there is something quite strange -- unnaturally
        strange -- about the mist. "
    defaultLook(d)
    {
        if(d is in (westDirection, southwestDirection, northwestDirection))
            "The trees at the edge of the orchard are a little way to the
            west. ";
        else
            "To the <<d.name>> you see nothing but the strange grey mist. ";
    }
    throwDests = [[northDirection, strangeMist], [northeastDirection, strangeMist], 
        [eastDirection, strangeMist],
        [southeastDirection, strangeMist], [southDirection, strangeMist] ]
;

+ strangeMist: Enterable, CustomFixture 'strange immobile cold grey gray mist' 
    'strange mist'
    "It looks cold, grey and strangely immobile, as it if it were more like
    an alternative form of reality than a genuine mist. "
    cannotTakeMsg = 'It\'s too insubstantial to manipulate in
        any way. '
    feelDesc = "It feels very cold. " 
    connector = static orchardEdge.mistConnector
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
    throwIntoMsg = '{The dobj/he} disappears into the mist. '
    nothingBehindMsg = &cannotSeeBehindMsg
;


+ Distant 'apple rows/trees/orchard' 'trees'
    "Rows of apple trees march west from here. "
    isPlural = true
    dobjFor(Enter) remapTo(West)
;

//==============================================================================
largeLawnSouth : OutdoorRoom 'Large Lawn (south)' 'the south end of the lawn'
    "The lawn stretches quite a way north from here, but immediately to the
    south is a curious green building that looks like some kind of shrine. In
    front of this building is an equally curious green statue. "
    north = largeLawnNorth
    south = (shrine.connector)
    in asExit(south)
    thinkHere = "You suspect that the entire lawn is somehow here for the sake
        of the shrine. "
    northLook = "You look northwards across the neatly-kept lawn towards a
        small garden shed at the far end. "
    southLook = "Immediately to the south is a curious green building that
        appears to be some kind of shrine. In front of the shrine is an 
        equally curious green statue. "
    enterRoom(traveler)
    {
        traveler.lastStatueLoc = self;
    }
;

+ shrine: Enterable ->insideShrine 'curious small square 
    green building/shrine/threshold*buildings'
    'green building'
    "It appears to be a shrine of some sort, perhaps to the goddess (if that's
    what she is) depicted in the statue that stands just outside. In design,
    it's roughly square, a single story in height, and painted a similar shade
    of green to the statue. "
    distantDesc = "The building at the far end of the lawn looks square and
        green. "
    sightSize = large
    dobjFor(ThrowInto)
    {
        verify() { illogical('You can\'t throw anything into it from here. '); }
    }
    nothingBehindMsg = &cannotSeeBehindMsg
;

+ greenStatue: CustomImmovable '(equally) curious green angular arguably
    gaudily painted gaudily-painted beautiful (stone) statue/goddess/woman' 
    'green statue'
    "The gaudily-painted statue is about as tall as you are, and depicts an
    angular and arguably beautiful green goddess (at least, you assume it's a
    goddess, for it's certainly no ordinary woman) with a spectacular mane of
    flaming orange hair and scant clothing. With all this green around you
    wonder if she's some kind of fertility goddess, but it may be that the
    colour has some other significance. "
    cannotTakeMsg = 'The statue is too heavy to budge. '
    dobjFor(Kiss)
    {
        verify() {}
        action() {
            "Your lips experience a strange tingle as they press agains the
            cold stone lips of the statue, as if there is some kind of
            elemental life force buried deep within. Although it's only a
            statue you kissed, you feel as if some significant transaction has
            just taken place. ";
            statueHair.pullCount = statueHair.isStone ? 1 : 0;
        }
    } 
    beforeTravel (traveler, connector)
    {
        if(connector != shrine.connector)
            return;
        if(!statueHair.isStone)
        {
            "A hollow groan comes from somewhere deep in the statue: <q>I am
            not in the right state to receive worshippers in my shrine!</q>.\b
            {You/he} find{s} that {it actor/he} cannot step over the threshold.
            <.reveal shrine-barrier>";
            exit;
        }
        if(!(greenApple.isIn(traveler) && goldCoin.isIn(traveler)))
        {
            "{You/he} {is} brought to an abrupt halt when a voice from within
            the statue calls out, <q>Only those who bring worthy gifts are
            worthy to enter and worship at my shrine.</q><.reveal
            shrine-barrier>";
            exit;
        }
    }  
    notAddressableMsg = 'The statue maintains an enigmatic silence. '
    uselessToAttackMsg = 'Something in the look of the statue\'s eyes stops
        you. '
    isHer = true
    isIt = true
;

++ Component 'scant clothing/clothes' 'scant clothing'
    "The clothing depicted on the statue is rather less than strictly needed
    for the sake of modesty, were modesty a consideration for statues. "
    owner = location
;

++ Component 'fierce eyes' 'eyes'
    "They look decidedly fierce. "
    isPlural = true
    owner = location
;

++ statueHair: Component 'spectacular flaming bright orange mane/hair' 
    'orange hair'
    "The orange hair is <<isStone ? 'carved out of stone like the rest of the
        statue, but looks painted a different colour. It\'s depicted as' : '
            the most curious part of the statue, since while the rest of the
            statue is clearly carved from stone, the hair appears to be, if not
            genuine, at least something that closely resembles genuine hair.
            There\'s also an awful lot of it,'>> falling thickly and copiously
    below the statue's waist and almost to its thighs. "
    isMassNoun = true
    feelDesc = "<<isStone ? 'It feels just like the rough stone carving it is'
          : ' {You/he} can\'t quite be sure from feeling it whether it\'s
            human, animal or synthetic -- not that you can be sure about
            anything much round here in any case. It feels kind of soft and
            coarse at the same time -- not unpleasant to the touch, but rather
            odd'>> . "
    isStone = nil
    owner = location
    pullCount = 0
    transform() { 
        isStone = ! isStone; 
        "A very curious thing happens; the statue's hair <<isStone ? 'suddenly
            goes hard and rigid, for all the world looking as if it were carved
            from the same block of stone as the rest of the statue' : 'loses
                its stoniness and turns into what looks just like real
                hair'>>. ";
        switch(++pullCount)
        {
        case 2:
            "<.p>A hollow voice emanates from the statue, <q>I am not a toy to
            be played with -- as you will discover if you wish to become my
            true worshipper. Now go and find me a gift worthy to offer at my
            shrine, or else depart hence and never return.</q>"; break;
        case 4:
            "<.p>A hollow voice emanates from the statue, <q>You are toying
            with a mystery too deep for you to understand. If you persist, you
            will learn the meaning of disobedience -- to your everlasting
            cost.</q>"; break;
        case 5:
            "<.p>Once more the hollow voice sounds from deep inside the statue,
            <q>You were warned!</q>.\b
            Suddenly, you find you cannot move. Then you cannot breathe. Then
            you cannot even think.\b";
            finishGameMsg('YOU HAVE TURNED TO STONE', 
                          [finishOptionUndo, finishOptionFullScore]);
            break;
        }
    }
    dobjFor(Pull)
    {
        verify() { nonObvious; }
        action() { transform; }
    }
    dobjFor(Push)
    {
        verify() {
            if(isStone)
                illogicalNow('It\'s attached pretty firmly to the statue, so
                    that\'s unlikely to achieve much. ');
        }
        action()
        {
            "You push the statue's hair this way and that, but when you\'ve
            finished playing with it you let it fall back much the way it
            was. ";
        }
    }
    dobjFor(Move) asDobjFor(Push)
    dobjFor(KnockOn)
    { 
        verify() 
        {
            if(!isStone)
                illogicalNow('You can hardly knock on it while it\'s in this
                    state. ');
        }
    }
    nothingBehindMsg = 'There\'s nothing much there -- just the statue. '
;

//==============================================================================

shrineFloor : Floor 'green floor/ground' 'floor'
    "The floor is covered in green paint. <<altarHole.isOpen ? 'There\'s a
        large square hole in the floor just by the altar. ' : ''>> "
;

insideShrine: Room 'Inside the Shrine' 'the inside of the shrine'
    "Not being much of a devotee of pagan shrines, you're not in much of a
    position to assess whether this is a relatively unimpressive example, but
    you don't feel particularly impressed by it. It seems rather cramped,
    there's too much green paint everywhere, and the only objects of note are a
    small stone altar and a tall bronze lampstand placed just behind it. "  
    out : FakeConnector { "A disembodied voice stops you in your tracks by
        calling out, <q><<altarHole.isOpen ? 'Not that way! Since you have
            shown yourself to be a worthy worshipper, you are to come to me
            through the tunnels that lie beneath.': 'You do not have my
                permission to leave -- first make your offering!'>></q> " }
    down = altarHole  
    enterRoom(traveler) { achievement.addToScoreOnce(1); }
    achievement: Achievement { "entering the shrine" } 
    roomBeforeAction()
    {
        if(gActionIs(Examine) && gDobj.ofKind(RoomPart) && gDobj != shrineFloor)
        {
            "It's covered with green paint. ";      
            exit;
        }
    }
    thinkHere = "You wonder whether finding your way in here was really such a
        great idea. Something about this place strikes you as not just
        aggressively pagan but positively sinister. "
    defaultLook(d) { "You are surrounded by acres of green paint whichever
        way you look here. "; }
    lookDirToRoomPart(dir) { return dir == downDirection; }
    vocabWords = 'green shrine'
    roomParts = static inherited - defaultFloor + shrineFloor
;

+ Surface, Fixture 'small dressed stone green altar' 'small stone altar'
    "It's little more than a block of dressed stone placed at the centre of the
    shrine. It, too, has been painted green. "
    afterAction()
    {
        if(greenApple.isIn(self) && goldCoin.isIn(self) && !altarHole.isOpen)
        {
            "The censer suddenly becomes more active, enveloping the entire
            altar in a thick cloud of purple smoke. When the smoke clears you
            find that the altar is bare: presumably this means that your
            offering has been accepted. A second indication that your offering
            has achieved something is that a large square hole has appeared in
            the floor just next to the altar. ";
            foreach(local cur in contents)
                cur.moveInto(nil);
            altarHole.makeOpen(true);
        }
    }  
;

+ Heavy 'tall crude ugly bronze lampstand/contraption/censer' 
    'tall bronze lampstand'
    "The main thing that can be said in its favour is that it's one of the few
    things round here that hasn't been painted green. Otherwise, it's a rather
    ugly contraption, a spindly length of twisted bronze supporting a crude
    censer, which is reluctantly emitting a thin trail of vile-smelling purple
    smoke. "   
;

+ Vaporous 'vile-smelling purple thin trail/smoke' 'purple smoke'
    "The thin trail of purple smoke winds langorously towards the ceiling,
    without exerting itself overmuch to actually get there. "
;

++ SimpleOdor 'pungent vile smell' 'vile smell'
    "It smells like a particular malodorous chemistry experiment performed by
    an exceptional mischievous schoolboy: the sort of thing you might get from
    combining hydrogen sulphide with an unusually pungent bleach, mixing in a
    healthy dose of car fumes, and then stirring in a whiff of rotting cat. "
;

+ SimpleNoise 'silence' 'silence'
    "It is at least quiet here: there's no sound to listen to but the silence. "
;

+ Decoration 'green paint' 'green paint'
    "It's all over the walls, floor, ceiling and altar. "
;

+ altarHole : HiddenDoor 'large square hole' 'large square hole'
    "It's just to the right of the altar as you stand facing it with your back
    to the exit. It's about two foot square or so, or in any case large enough
    to go through without discomfort. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }   
;
//==========================================================================

shrineTunnel: Room 'Start of Long Windy Tunnel' 'the long windy tunnel'
    "Above you is a large square hole; ahead of you a long tunnel winds off to
    the east -- that is to say it starts by heading off to the east but then
    starts to bend in the middle distance. "
    up = shrineTunnelHole
    east : TravelMessage { ->maze1
        "The tunnel turns out to curve quite a bit. In fact it twists and turns
        so much that you soon lose all sense of direction, at which point the
        worst possible thing happens: you arrive at junction which has tunnels
        leading off in every direction. "
    }
    enterRoom(traveler) { achievement.addToScoreOnce(1); }
    achievement: Achievement { "entering the tunnel under the shrine" }
    thinkHere = "You're not sure which way feels less appealing, the way back
        up to the shrine or the way down the tunnel. "
    eastLook = "The long tunnel winds off to the east. "
    vocabWords = 'long windy tunnel'
;

+ shrineTunnelHole: RoomPartItem, ThroughPassage ->altarHole 'large square hole' 
    'large square hole'
    "It's about two foot square, and low enough to haul yourself up through. "
    initNominalRoomPartLocation = defaultCeiling
    initSpecialDesc = "In the ceiling is a two-foot square hole. "
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
;

+ EntryPortal 'long tunnel' 'long tunnel'
    "The long tunnel starts by heading east, but in the middle distance it looks
    like it starts to bend. "
    dobjFor(Take) asDobjFor(TravelVia)
    dobjFor(Follow) asDobjFor(TravelVia)
    dobjFor(TravelVia) remapTo(East)
    dobjFor(KnockOn) { verify() { illogical(&cannotKnockOnHoleMsg); } }
;

#endif // ifdef __MULTIROUTE