#charset "us-ascii"
#include <advlite.h>


//      The main level:
//              archedPassage
//              sandwichShop
//              securityOffice
//              breakRoom
//              palmTreeNiche
//              smokeShop
//              fileRoom
//              longBalcony
//              arcadeNorth
//              artGallery
//              artStudio
//              travelAgency
//              inTheTarzan is now in its own file...
//              arcadeWest
//              beautyParlor
//              tackyLounge
//              coatCloset
//              restroom
//              arcadeCenter ... diorama is now in its own file
//              arcadeEast
//              goingToPot
//              scootersPub
//              billiardRoom
//              seeressLair
//              rareBookShop
//              printery

//-----------------------------------------------------------------------------
// archedPassage
//-----------------------------------------------------------------------------

#ifdef __DEBUG
Test 'guard return' ['s', 's', 's', 'w', 'knock on window', 'x woman', 'e', 'e', 'e', 'd', 'nw', 'take lid',
    'se', 'u', 'n', 'n', 'w', 'tell guards about octopus', 'take key']
;
#endif

archedPassage: Room 'Arched Passage'
    "In spite of the high, arched ceiling and gilt brickwork, this passageway fails to
    cast an inviting spell. Perhaps the pervasive odor of dry dust
    is to blame. Standing against the wall on the east side of the passage is a wooden
    Indian.
    
    <.p>Beside the Indian is a <<if (smokeShopDoorOutside.isOpen)>>half-open <<end>>door, above which is fixed a sign that bears
    the legend <q>PUFF THE MAGIC STOGIE.</q> The open doorway in the west wall, next
    to which is a small placard engraved with the words <q>SECURITY OFFICE,</q> seems more businesslike.
    The passage is open to the north and south, and there's a recess or niche in the northwest
    corner, in which stands a tall but unhappily drooping potted palm. "
    
    beforeTravel (traveler, connector) {
        local wd = 'along';
        if (connector == smokeShopDoorOutside) wd = 'across';
        if (ollie.released && !ollie.recaptured && masterKey.moved) {
            "<.p>As you're moving <<wd>> the passage,
            the guards trudge past you and re-enter the Security Office. They're breathing hard, and they
            look a bit disheveled. <q>Damned octopus,</q> one of them says to the other. <q>Hope we don't
            have to go through that again this week.</q> ";
            guardsGroup.returnToOffice();
        }
    }
    
    regions = [betsyGoneRegion, joeFollowingRegion, ajouMarchingRegion]
    
    north = mainEntrance
    northwest = palmTreeNiche
    in asExit(northwest)
    south = arcadeNorth
    east = smokeShopDoorOutside
    west = securityOffice
;

+ securityPlacard: Decoration 'placard; security office; sign'
    "The placard says <q>Security Office.</q> "
    vocabLikelihood = -15
;

+ stogieSign: ShopSign 'Puff the Magic Stogie +; cigar cigarette smoke tobacco; tobacconist smokeshop'
    "The red lettering of the <q>PUFF THE MAGIC STOGIE</q> sign has been rendered
    along a swollen brown cylinder that resembles,
    at least in a vague way, a cigar. "
    vocabLikelihood = -10
;

+ smokeShopDoorOutside: ShopDoorOutside '+ ;smoke shop puff (the) magic stogie'
    "The door to the smoke shop is on the east side of the passage. <<if isOpen>>It's standing
    open. <<end>>"
    otherSide = smokeShopDoorInside
    isOpen = nil
    isLocked = true
    // This bit is needed as a precaution so the Indian's message won't accidentally tell
    // you too much:
    hasEverBeenUnlocked = nil
    makeLocked(stat) {
        if (stat) hasEverBeenUnlocked = true;
        inherited(stat);
    }
;

+ viewOfNiche: Enterable 'niche'
    "The niche is occupied by a tall but unhappy-looking potted palm tree. "
    destination = palmTreeNiche
;

+ viewOfPalm: Distant 'potted palm; tall unhappily drooping; tree'
    "The potted palm is at least seven feet tall, and would be taller if only it
    would stand up straight. At a guess, it's pinin' for Fiji. "
;

+ woodenIndian: Fixture 'wooden Indian; wood noble buckskin carved deep mahogany; chest complexion suit; it him'
    "The wooden Indian is taller than you. His complexion is a deep mahogany, his expression
    implacable but not unkindly. If he weren't carved entirely from wood, you'd have to say
    he was wearing a buckskin suit and a swept-back feathered headdress. His right hand clutches
    to his chest a cup (also wooden), in which repose several wooden cigars. "
    winked = nil
    armed = nil
    cigarGiven = nil
    arm() {
        armed = true;
    }
    afterTravel (traveler, connector) {
        if (armed && !winked) {
            winked = true;
            "As you pass the wooden Indian, you have the odd, momentary impression that he
            has turned his head and winked at you. You pause to stare closely at him. No,
            he's as motionless as before. ";
        }
        // Give that lady a cigar!
        else if (winked && (betsy.getOutermostRoom == nil) && !cigarGiven) {
            cigarGiven = true;
            cigar.moveInto(me);
            "As you walk down the passage, the wooden Indian beckons to you. What?!?
            Well, that's what he does. In a deep, slow voice, he says, <q>You look like
            a lady who could use a cigar.</q> He proffers a cigar, and after hesitating
            for a moment you take it. <q>Good,</q> the Indian says solemnly. <q>That is
            all.</q> He returns to stoic immobility. ";
        }
    }
    dobjFor(Burn) {
        verify() {}
        check() {
            if (singleMatchbook.isDirectlyIn(gPlayerChar))
                "That would attract quite a lot of unwanted attention, don't you think? ";
            else
                "Bad idea --- and anyway, you don't seem to have any matches handy. ";
        }
    }
;

++ woodenCigars: Component, Decoration 'cup of wooden cigars; ; cigar'
    "The cigars are in a cup in the Indian's hand. "
    notImportantMsg = 'The cup of wooden cigars is not, in any immediate sense, important. '
;

++ headdress: Component, Decoration 'feathered headdress'
    "It looks pretty much the way you'd expect a feathered headdress to look, except
    that it's carved from wood. "
;

//-----------------------------------------------------------------------------
// sandwichShop
//-----------------------------------------------------------------------------

sandwichShop: Shop 'Sandwich Shop'
    "The sandwich shop is equipped with a large cooler,
    which has glass doors. The room is equipped with the usual
    nondescript tables and chairs. On the wall behind the cash
    register is a chalkboard that lists various menu items --- coffee,
    sandwiches, and such things. It's a good thing you're not hungry,
    as there's no coffee brewing and nobody here to make a sandwich.
    <.p>The door through which you entered is to the north. "
    north = sandwichShopDoorInside
    out asExit(north)
;

+ sandwichShopDoorInside: ShopDoorInside '+ ; groaning sandwich board snack bar'
    "The door is on the north side of the shop. "
    otherSide = sandwichShopDoorOutside
;

+ chalkboard: Fixture 'chalkboard; chalk; board price prices menu'
    "The chalkboard lists, in three columns, a variety of beverages and sandwiches. 
    There's something odd about the prices on the chalkboard, though.
    They're not even in dollars and cents. Reading down the right-hand side of
    each column,
    the list of prices (assuming they're prices) is 12-3-10-4-18-15, 7-9-13-11-16-8,
    and 17-1-2-5-14-6. "
    readDesc = (desc)
;

+nondescriptTables: Decoration
    'nondescript tables; formica ordinary; chairs; them'
    "The tables and chairs look like something that might have been ordered out of a
    Sears & Roebuck catalog (and whatever happened to Roebuck, by the way?) during
    the brief period in the 1950s when Formica was considered a stylish substance. "
;

+ Decoration 'cash register'
    "It's a very ordinary cash register. "
;

+ Decoration 'treats; alleged assorted; assortment treat'
    "The treats are about what you'd expect to see in a snack bar cooler. "
    plural = true
    notImportantMsg = 'The assorted treats are not important. The beer and
        pizza, however.... '
;

+ cooler: Fixture
    'cooler; large humming; fridge refrigerator icebox'
    "The cooler is humming quietly. Through the glass door in the front you can see
    a variety of alleged treats, notably boxes of frozen pizza and six-packs of beer. At
    a guess, the Groaning Sandwich Board caters a lot of fraternity parties. "
    remapIn: SubComponent, OpenableContainer {
        isTransparent = true
        contentsListed = nil
        reachBlockedMsg(target)
        {
            local obj = self;
            gMessageParams(obj);
            gMessageParams(target);
            return  BMsg(cannot reach, 'To get at {the target}, you\'ll need to open
                {the obj}. ');
        }
    }
;

++ coolerDoor: Component 'glass door; (cooler) (fridge) (refrigerator) (icebox)'
    "The glass door is part of the cooler. "
    dobjFor(Open) {
        verify() {}
        action() {
            doInstead(Open, cooler);
        }
    }
    dobjFor(Close) {
        verify() {}
        action() {
            doInstead(Close, cooler);
        }
    }
;

++ frozenPizzaCollection: Food
    'frozen pizza; pepperoni anchovy veggie sausage chicken pineapple; box boxes stack'
    "Pepperoni, sausage, anchovy, veggie, chicken, pineapple --- there's quite
    a variety of boxed pizza in the cooler. "
    aName = 'some ' + name
    subLocation = &remapIn
    vocabLikelihood = 30
    onePizzaTaken = nil
    outOfReach = true
    dobjFor(GetWith) {
        verify() {}
        action() {
            doInstead(Take, frozenPizzaCollection);
        }
    }
    dobjFor(LookBehind) asDobjFor(Feel)
    dobjFor(Push) asDobjFor(Feel)
    dobjFor(Pull) asDobjFor(Feel)
    dobjFor(Feel) {
        verify() {}
        check() {
            "The pizza boxes are too far away. ";
        }
    }
    dobjFor(Take) {
        check() {
            if (!snookerBridge.isDirectlyIn(gPlayerChar)) "Alas, the stack of pizza boxes
                is clear back at the back of the shelf. Even by stretching your arm, you
                can't quite reach them. ";
            else if (onePizzaTaken) "You've already taken a pizza. There's probably no need
                to burden yourself with more. ";
        }
        action() {
            onePizzaTaken = true;
            aPizza.moveInto(gPlayerChar);
            "Reaching deep into the cooler with the snooker bridge, you drag a pizza box
            far enough toward you that you can pick it up. It proves to be a pepperoni
            pizza. Whatever. ";
        }
    }
;

++ beerCollection: Thing
    'stacked six-packs of beer; dark pretentious German imported glass six packs; (bottles); them'
    "Imported beer in dark bottles with pretentious German names. "
    oneSixPackTaken = nil
    vocabLikelihood { return (gActionIs(Take) ? 20 : 8); }
    outOfReach = true
    subLocation = &remapIn
    dobjFor(GetWith) {
        verify() {}
        action() {
            doInstead(Take, beerCollection);
        }
    }
    dobjFor(LookBehind) asDobjFor(Feel)
    dobjFor(Push) asDobjFor(Feel)
    dobjFor(Pull) asDobjFor(Feel)
    dobjFor(Feel) {
        verify() {}
        check() {
            "The six-packs of beer are too far away. ";
        }
    }
    dobjFor(Take) {
        check() {
            if (!snookerBridge.isDirectlyIn(gPlayerChar)) "Alas, the six-packs of beer
                are clear back at the back of the shelf. Even by stretching your arm, you
                can't quite reach them. ";
            else if (oneSixPackTaken) "You've already taken a six-pack. There's probably no need
                to burden yourself with a whole brewery. ";
        }
        action() {
            oneSixPackTaken = true;
            aSixPack.moveInto(gPlayerChar);
            "Reaching deep into the cooler with the snooker bridge, you drag a six-pack of beer
            far enough toward you that you can pick it up. ";
        }
    }
    dobjFor(Drink) {
        preCond = [objHeld]
        verify() {}
        check() {
            if (!cooler.isOpen) "You'll need to open the cooler first. ";
            //"You've never cared much for the taste of beer. You're more a white wine person. ";
        }
    }
;

aPizza: PDportable 'pepperoni pizza; frozen pizza cardboard boxed; box'
    "The pepperoni pizza is in a cardboard box. The box is about a foot square. "
    vocabLikelihood = 10
    dobjFor(Eat) {
        verify() {}
        check() {
            "Even opening the box would be pointless. The pizza is bound to be frozen solid. ";
        }
    }
    dobjFor(Open) {
        preCond = [objHeld]
        verify() {}
        check() {
            "You're not that hungry. There's a pizza inside -- you can tell that much by
            shaking the box. ";
        }
    }
;

aSixPack: PDportable
    'six-pack{-zz} of beer; frosty dark pretentious German imported glass six-pack six pack'
    "A frosty six-pack of imported beer in dark bottles, with an unpronounceable German name liberally
    festooned with umlauts. "
    vocabLikelihood = 10
    dobjFor(Drink) {
        preCond = [objHeld]
        verify() {}
        check() {
            "You've never cared much for the taste of beer. You're more a white wine person. ";
        }
    }
    dobjFor(Open) {
        preCond = [objHeld]
        verify {}
        check() {
            "You're not that thirsty. ";
        }
    }
;

//-----------------------------------------------------------------------------
// securityOffice
//-----------------------------------------------------------------------------

Doer 'yell'
    execAction (c) {
        if (franklin.isIn(securityOffice)) "Do you want to make the guards suspicious? Or
            are you just feeling exuberant? No, don't answer that. ";
    }
    where = securityOffice
;

securityOffice: Room 'Security Office'
    desc () {
        "Dominating this businesslike room is a large flat-panel video display
        mounted on one wall. Across from the display is a corkboard onto which several
        untidy layers of paper have been tacked. On the wall next to the
        corkboard is mounted a brass hook, and on the floor below the corkboard is
        a wooden box.<<tGuards.makeFamiliar()>>
        
        <.p>The exit back to the arched passage is to the east, and there's
        an inner doorway to the southwest. ";
    }
    southwest = breakRoom
    east = archedPassage
    out asExit (east)
;

// The only utility of the lost and found box, at present, is that the
// flashlight is in it. The flashlight is not strictly needed, although
// the bat cave can cause you to lose the game if you don't have it. For
// now, let's leave the box where it is.

+lostAndFoundBox: Fixture, OpenableContainer 'well-scuffed wooden box; scuffed lost (and) found'
    "On the lid of the well-scuffed wooden box are lettered the words
    <q>Lost & Found</q>. "
    dobjFor(Open) {
        check () {
            if (franklin.getOutermostRoom == securityOffice) {
                "As you move toward the box, one of the guards holds out a hand to halt
                you. <q>Are you missing something, ma'am? If you are, you might tell us
                what you're looking for --- but I have to say, you don't look like the
                type that just scatters things around. I doubt there's anything in there
                that belongs to you.</q> ";
                exit;
            }
        }
    }
    cannotTakeMsg = 'It\'s far too bulky for you to consider hauling it around. '
;


+ brassHook: Surface, Fixture 'small brass hook'
    "The brass hook is mounted on the wall next to the corkboard<<masterKey.discover()>>. "
    notifyInsert (obj) {
        if (obj != masterKey) {
            "There's no need to put things on the brass hook. ";
            exit;
        }
    }
;

+ notMasterKey: Unthing 'shiny aluminum key; master'
    notImportantMsg = 'Key? Is there a key around here somewhere? '
;

+ corkboard: Surface, Fixture 'bulletin board; cork; corkboard'
    "The corkboard is nearly invisible behind a blizzard of official notices,
    cartoons, wanted posters, and advertising flyers.<.p>
    
    Mounted on the wall next to the corkboard is a small brass hook<<if (masterKey.isHidden)>>, and hanging
    on the hook is <<masterKey.discover()>>a shiny key<<end>>. "
    notifyInsert (obj) {
        "Someone obviously devoted months of patient effort to getting that mess of paper arranged just so.
        Why spoil the effect? ";
        exit;
    }
;

// Note: The player may have matches, in which case she will try to burn this stuff!
++ corkboardPapers: Fixture
    'mess of papers; wanted ad advertising; ads advert adverts notice notices cartoon cartoons
    poster posters flyer flyers stuff paper; them'
    "There's far too much random stuff on the corkboard for you to want to waste time
    scrutinizing it. "
    readDesc = (desc)
    cannotTakeMsg {
        if (franklin.isIn(securityOffice)) return 'The guards probably wouldn\'t want
            you running off with their wanted posters. ';
        else return 'Burdening yourself with a bushel of waste paper would achieve nothing. ';
    }
;

//-----------------------------------------------------------------------------
// breakRoom
//-----------------------------------------------------------------------------

breakRoom: Room 'Break Room'
    "Other than a table, a couple of chairs, a coffee machine, and a microwave, there's not much
    to be seen in this little room. At a guess, this is where the guards take
    their lunch breaks and coffee breaks. Nothing here looks like it would be
    useful to you.
    
    <.p>The door through which you entered is to the northeast. "
    northeast = securityOffice
    out asExit(northeast)
;

+ Decoration 'coffee machine; stained; stains'
    "The stains on the coffee machine suggest that it's well used. "
;
+ Decoration 'microwave'
    "The microwave must be where the guards heat their snacks. "
;
+ Decoration 'table'
    "You've seen tables before. "
;

+ Decoration 'chairs; ; chair'
    "The chairs are not new, and not remarkable in any way. "
    plural = true
;
     
//-----------------------------------------------------------------------------
// flatPanelMonitor is in its own file
//-----------------------------------------------------------------------------
    
//-----------------------------------------------------------------------------
// palmTreeNiche
//-----------------------------------------------------------------------------

palmTreeNiche: Room 'Palm Tree Niche'
    "This niche was small enough ten years ago to feel crowded with only one person in it,
    during those uncomfortable moments when you hid in it to avoid
    the security guard. Now, dominated by a large concrete urn in which stands a very
    unhappy-looking potted palm tree, it's almost too small to turn around in.
    The arched passage is mere steps away to the east. "
    vocab = 'niche'
    regions = [betsyGoneRegion]
    
    east = archedPassage
    out asExit(east)
    southeast asExit(east)
;

+ concreteUrn: Container, Heavy 'concrete urn; cement pebbly chipped; pot vase planter'
    "The pebbly surface of the urn is somewhat chipped. The urn is full of dirt (and
    cigarette butts). There's a spindly, unhappy-looking palm tree growing in it ... or
    perhaps <q>growing</q> is too optimistic. <q>Languishing</q> might be better. "
    hiddenIn = [coin2]
    dobjFor(Take) {
        verify() {}
        check() {
            "It must weigh half a ton. ";
        }
    }
    iobjFor(PutIn) {
        verify() {}
        check() {
            "Between the palm, the dirt, and the cigarette butts, the urn is
                pretty full already. ";
        }
    }
;

// There's a gold coin hidden in the urn as well, but it's in the PDthings file.

++ cigaretteButts: Decoration 'cigarette butts; filthy cigaret; butt smokes mound; them'
    "The cigarette butts are not scattered randomly but rather are heaped in a little mound, as
    if someone dumped out an ashtray in the urn. "
    dobjFor(Take) {
        verify() {}
        check() {
            "They're too filthy to bother with. ";
        }
    }
    dobjFor(LookIn) {
        verify() {}
        action() {
            doInstead (LookIn, concreteUrn);
        }
    }
    decorationActions = [Examine, Take, Search, LookIn]
    notImportantMsg = 'The usefulness of the cigarette butts is approximately zero. '
;

++ urnDirt: Decoration 'dirt'
    "The dirt is liberally sprinkled with cigarette butts. "
    aName = 'some ' + name
    dobjFor(Take) {
        verify() {}
        check() {
            "The urge to burden yourself with handfuls of dirt passes quickly. ";
        }
    }
    decorationActions = [Examine, Take]
    notImportantMsg = 'The dirt is beneath your notice. '
;

++ pottedPalm: Fixture 'potted palm; drooping; tree plant'
    "The palm is taller than you are. It's drooping sadly. "
    dobjFor(Search) {
        verify() {}
        check() {
            "There are no coconuts, that's certain. You might try searching the urn in
            which the tree is planted, though. ";
        }
    }
    dobjFor(Take) {
        verify() {
            illogical ('You\'d look pretty darn silly sauntering around with an uprooted
                palm tree under your arm. ');
        }
    }
    dobjFor(Climb) {
        verify() {}
        check() {
            "It would never support your weight. Besides, there's
                nothing up there, not even a coconut. ";
        }
    }
;

//-----------------------------------------------------------------------------
// smokeShop
//-----------------------------------------------------------------------------

smokeShop: Shop 'Smoke Shop'
    "Tobacco products of various kinds are on display in this tiny, overcrowded room. Curiously,
    however, there seem to be no cigars. Against
    one wall stands a tall glass-front case displaying packs of cigarettes. On the counter
    is what looks like an oversize brandy snifter containing books of matches. The door
    back to the arched passage is to the west. "
    
    out asExit(west)
    west = smokeShopDoorInside
;

+ smokeShopDoorInside: ShopDoorInside '+ ; puff (the) magic stogie'
    "The door out to the arched passage is on the west. "
    otherSide = smokeShopDoorOutside
;

+ cigaretCase: OpenableContainer, Fixture
    'cigarette case; tall display glass glass-front cigaret'
    "Within the case are neat stacks of cigarette packs. "
    isTransparent = true
;

++ cigaretPacks: Fixture
    'packs of cigarettes; filter tip menthol cigaret; pack cigarets smokes cigs; them'
    "The case is stocked with at least fifty brands of cigarettes, foreign and domestic.
    Filter tip, menthol --- you pretty much have your choice. "
    vocabLikelihood = -10
    dobjFor(Take) {
        verify() {}
        check() {
            if (!marlboros.isIn(nil)) "Probably one pack of cigarettes is all you'll
                need. ";
        }
        action() {
            marlboros.moveInto(gPlayerChar);
            marlboros.moved = true;
            "You extract a bright red pack of Marlboros from the case. 
            <<if (betsy.getOutermostRoom() == smokeShop)>>{The betsy}'s eyes flick
            in your direction, but she lifts her nose into the air and pretends
                to have seen nothing. <<end>>";
        }
    }
;

+ brandySnifter: Container, Fixture 'brandy snifter; glass large; jar'
    "The brandy snifter is quite large, and nearly full of books of matches. "
    cannotTakeMsg = 'Not being a pyromaniac, you have no use for a jar containing at least 200
        books of matches. '
;

++ pluralMatchbooks: Fixture 'matchbooks;; matches match matchbook; them'
    "The matchbooks are in the brandy snifter. "
    dobjFor(Take) {
        verify() {}
        check () {
            if (singleMatchbook.getOutermostRoom() != nil) "You already have
                some matches. Or at least you did. Did you lose them? ";
            // "We can all hope that setting fire to the shopping center won't be necessary. ";
        }
        action () {
            singleMatchbook.moveInto(gPlayerChar);
            "You select a matchbook from the brandy snifter. ";
        }
    }
;

singleMatchbook: PDportable 'matchbook; ; match matches; it them'
    "The matchbook has the usual supply of matches in it. (No need to take a match or
    strike it, just say what you want to light.) "
    vocabLikelihood = 10
    dobjFor(Light) {
        verify() {}
        check() {
            "Lighting matches at random is not likely to be useful. If you want
            to set fire to something, you'll need to say so. ";
        }
    }
    iobjFor(BurnWith) {
        verify() {}
        check() {
            if ((gDobj != cigar) && (gDobj != candleStub))
                "Setting fire to random things is not safe. ";
        }
    }
;

//-----------------------------------------------------------------------------
// fileRoom
//-----------------------------------------------------------------------------

// The fileRoom is initially blockedByStuffy. When the power is restored by the
// junction box, the HVAC is already switched on, so the junction box will replace
// blockedByStuffy with blockedByBlizzard. blockedByStuffy should never return.
// Whenever the HVAC is switched off, blockedByBlizzard is nil, and whenever it's
// switched on, blockedByBlizzard is true. We're not going to allow you to enter
// the room at all unless it's passable.

fileRoom: Room 'File Repository'
    "The floor of this room is a carpet of <<gotHere()>>
    loose paper. There's a stone arch to the north, an open doorway to the southwest, and another
    door to the southeast. "
    gotHere() {
        fileRoomAch.awardPointsOnce();
    }
    blockedByStuffy = true
    blockedByBlizzard = nil
    north = fileRoomArch
    southwest = goingToPot
    southeast = longBalconyDoorInside
;

+ fileRoomArch: OctagonExteriorPassage '+; (north) (green); arrow'
    "Carved into the stone at the summit of the stone arch is a green arrow that curves
    down to the left, as if it were drawn from 12:00 to 9:00 on a clock face.<<if blocked>> At the
    moment, passage through the arch is blocked by a sheet of gray stone.<<else>>
    At the moment, the arch stands invitingly open.<<end>> "
    blocked = true
;

+ longBalconyDoorInside: Door 'wooden door; wood ordinary'
    "It's an ordinary wooden door. "
    otherSide = longBalconyDoorOutside
    canTravelerPass(traveler) {
        return (!hvacSwitch.isOn);
    }
    explainTravelBarrier(traveler) {
        "If there's a door there, you can't get to it or even see it due to the blizzard of paper
        flying everywhere. ";
    }
;

+ flyingPapers: Decoration 'loose papers; flying whirling flapping fluttering; paper carpet; them'
    "<<if (hvacSwitch.isOn)>>The papers are whirling through the air in a very blizzard<<else>>The
    papers lie thick on the floor<<end>>. "
    notImportantMsg = 'The papers are numerous, varied, and too trivial to worry about. '
;


//-----------------------------------------------------------------------------
// longBalcony
//-----------------------------------------------------------------------------

// To do: Add to the grammar for 'climb' so as to add 'climb in through window' and
// 'climb out of window'.

longBalcony: Room 'Long Balcony'
    "This rather narrow balcony runs from north to south along the eastern
    side of the building. There's a door at the north and a conveniently open
    window at the south end. To the east you can
    see a driving range through a high net fence. "
    
    north = longBalconyDoorOutside
    south = balconyWindowOutside
;

+ Distant 'driving range'
    "The driving range is off to the east, behind the high net fence. "
;
+ Distant 'high net fence'
    "The net fence is off to the east. "
;

+ balconyWindowOutside: Door 'open window'
    isOpen = true
    otherSide = balconyWindowInside
    dobjFor(LookThrough) {
        verify() {}
        action() {
            "There's a room on the other side of the window. ";
        }
    }
;
+ Distant 'room'
    "There's a room on the other side of the window, but you can\'t make out
    any details from here. "
;

+ longBalconyDoorOutside: Door 'wooden door; wood ordinary'
    "It's an ordinary wooden door. "
    otherSide = longBalconyDoorInside
;

//-----------------------------------------------------------------------------
// arcadeNorth
//-----------------------------------------------------------------------------

arcadeNorth: Room 'North Side of the Arcade'
    "You are standing at the north end of an open arcade area, which stretches away
    to the south. The center of the arcade is open to the sky. A covered walkway 
    with a railing runs around the north, east, and west sides of the arcade, and
    you can see a second, similar walkway that runs around the open center area one story up.
    
    <.p>From here you can go north into the arched passage, east or west along the walkway (which
    soon turns a corner, bringing you to the east or west side of the arcade),
    or south through a gap in the railing into the open central area.
    
    <.p>In the northeast corner, near where this walkway makes a right
    angle with the one that runs along the east side of the arcade, is a door above
    which a sign reads <q>GOING TO POT.</q> In the northwest corner is another
    door, above which a sign proclaims <q>THE FINEST IN TASTE.</q> "
    
    regions = [betsyGoneRegion, joeFollowingRegion, ajouMarchingRegion]
    
    north = archedPassage
    northwest = artGalleryDoorOutside
    northeast = potteryDoorOutside
    west = arcadeWest
    south = arcadeCenter
    east = arcadeEast
;

+ finestInTasteSign: ShopSign 'Finest in Taste +; fine curlicued refined; lettering curlicues'
    "The delicate curlicued lettering of the <q>FINEST IN TASTE</q> sign is almost excessively refined. "
;

+ potSign: ShopSign 'going to pot +; ; ceramic ceramics selection'
    "The <q>GOING TO POT</q> sign depicts not the leafy green intoxicant you were probably expecting
    but rather a selection of ceramics. "
;

+ potteryDoorOutside: ShopDoorOutside
    '+ ; going (to) pot pottery'
    otherSide = potteryDoorInside
;

+ artGalleryDoorOutside: ShopDoorOutside '+ ; art gallery finest in taste'
    "The door is northwest of where you're standing. "
    otherSide = artGalleryDoorInside
    isLocked = nil
;

//-----------------------------------------------------------------------------
// artGallery
//-----------------------------------------------------------------------------

artGallery: Shop 'Art Gallery'
    "Subtly lighted canvases decorate the walls of this charming and refined room.
    Standing in the middle of the room is what looks at first glance (and, indeed,
    at second and third glances) like a surrealist replica of a Roman birdbath constructed
    of chromium, plastic, and straw.<<tArchibald.makeFamiliar()>>
    
    <.p>The door to the arcade is to the southeast, and there's an open doorway in
    the north wall. Stationed next to the latter is a straight-backed chair. "
    proper = nil
    southeast = artGalleryDoorInside
    north = artStudio
    out asExit(southeast)
;

+ artGalleryDoorInside: ShopDoorInside '+; gallery'
    "The door is in the southeast corner of the room. "
    otherSide = artGalleryDoorOutside
    isLocked = nil
;

+ galleryChair: Booth, Fixture 'straight-backed chair; stark austere wood blond wooden'
    "The chair is straight-backed and rather austere. It's made of blond wood. "
;

+ paintings: Fixture 'paintings; subtly lighted abstract; exhibit canvas picture canvases; them'
    "A few of the paintings are abstract, or at least difficult to describe,
    but most are conventional depictions of various things. <<if (!detailsGiven)>>There
    are so many that it's hard for
    you to fix on details. It occurs to you that perhaps if you ask the gallery owner about the
    paintings, he could indicate which of them are most worthy of your attention. <<else>>
    Casting your eyes around the room, you can see a vineyard, a sailing ship, a circus clown,
    a wolf baying at the moon, a golden sunset, a race car, a vase filled with flowers, a
    waterfall, a woman sitting on a bench, some ice skaters on a frozen pond, a butterfly,
    and a child reaching out to catch a ball. "
    dobjFor(Take) {
        verify() {}
        check() {
            "Carrying around an armload of paintings would be impractical, even if the gallery
            owner weren't watching. ";
        }
    }
    vocabLikelihood = 3
    detailsGiven = nil
    giveDetails() {
        detailsGiven = true;
        assortedPaintings.moveInto(nil);
        butterflyPainting.moveInto(artGallery);
        childPainting.moveInto(artGallery);
        vasePainting.moveInto(artGallery);
        waterfallPainting.moveInto(artGallery);
        womanPainting.moveInto(artGallery);
        skatersPainting.moveInto(artGallery);
        vineyardPainting.moveInto(artGallery);
        shipPainting.moveInto(artGallery);
        clownPainting.moveInto(artGallery);
        wolfPainting.moveInto(artGallery);
        sunsetPainting.moveInto(artGallery);
        carPainting.moveInto(artGallery);
    }
;

+ assortedPaintings: Unthing
    'assorted paintings;; vineyard ship clown wolf sunset car vase flowers waterfall woman bench skaters pond butterfly child ball'
    notHereMsg = 'There are too many paintings for you to fix your attention on any one of them
        without the help of the gallery owner. '
    vocabLikelihood = -5
;

// The weirdBirdbath is now in PDhelmet.t

//-----------------------------------------------------------------------------
// artStudio
//-----------------------------------------------------------------------------

artStudio: Room 'Art Studio'
    "Evidently a studio or workshop for a painter, this cozy little room is equipped with an
    easel and a workbench. The doorway is to the south. "
    canTravelerPass(traveler) {
        if (archibald.curState == archibaldSad) return nil;
        return true;
    }
    explainTravelBarrier (traveler) {
        "<q>I'm afraid that room is off-limits,</q> the art dealer says. <q>I'm really
        very sorry. Perhaps some other time I'll show you around.</q> ";
    }
    south = artGallery
    out asExit(south)
;

+ artWorkbench: Surface, Fixture 'workbench; sturdy stained work; bench'
    "The sturdy workbench is plentifully stained in many colors with glops of dried paint. "
;

+ easel: Surface, Fixture 'easel; plain wood; tripod'
    "The easel, built of plain wood, is essentially a tall tripod. "
    notifyInsert (obj) {
        "<<if ((obj.plural) || (obj.ambiguouslyPlural))>>They<<else>>It<<end>> would only fall off. ";
        exit;
    }
    cannotTakeMsg = 'You consider picking up the easel, and decide there\'s really no
        reason to want it. '
;

//-----------------------------------------------------------------------------
// travelAgency
//-----------------------------------------------------------------------------

travelAgency: Shop 'Colossal Adventure Travel Agency'
    "Garishly colored posters extolling the exotic delights to be sampled in distant lands 
    are plastered on every available square foot of wall, leaving
    no doubt that you've discovered the travel agency. The door through which you
    entered is to the southwest.
    
    <.p>Standing in an inner corner of the room is what appears at first glance
    to be an old-fashioned British police call box. A telephone booth, more or less. "
    
    out asExit(southwest)
    southwest = travelAgencyDoorInside
    in = inTheTarzan
;

+ travelAgencyDoorInside: ShopDoorInside '+ ; travel agency'
    "The door is in the southwest corner of the room. "
    otherSide = travelAgencyDoorOutside
;

+ travelPosters: Decoration
    'travel posters;; train trains slogan camel camels head heads; them'
    "What's curious about the posters, other than the slogan emblazoned on every
    one --- <q>Colossal Adventure: We Get You There And Back Again, or Vice-Versa</q> ---
    is the way the little airplanes, trains (trains? who travels in trains
    anymore?), blimps, and camel caravans are shown in a sort of reciprocal, bidirectional movement. Surely
    the artist didn't mean the viewer to conclude that the two trains rushing in
    opposite directions down the same track were about to smash head-on into one
    another. Nor that a single camel might have two heads facing in opposite directions.
    On the other hand, perhaps the word <q>artist</q> is needlessly optimistic. "

;

+ tarzanExterior: Enterable
    'telephone booth; dark British police call old-fashioned green solidly built; tarzan box'
    "The booth is dark green, and looks rather solidly built. It has little multi-paned windows
    on three sides, and the fourth side stands open. Above the open side is a brass
    plaque whose fussy Olde English lettering reads, <q>Time And Relative Zones
    Amazingly Nearby.</q> "
    destination = inTheTarzan
    dobjFor(Board) asDobjFor(Enter)
;

tarzanPlaque: Decoration 'brass plaque; fussy olde english; lettering'
    "The plaque declares that the booth is something called Time And Relative Zones
    Amazingly Nearby. Or, for short, TARZAN. "
;

//-----------------------------------------------------------------------------
// arcadeWest
//-----------------------------------------------------------------------------

arcadeWest: Room 'West Side of the Arcade'
    "A covered walkway runs along the west side of the central arcade. A gap
    in the railing affords access to the center
    of the arcade on the east, and the walk extends northward from here, turning
    a corner into the north side of the arcade.
    To the southwest,
    flush with the west wall, is the sliding door of what appears to be an elevator.

    <.p>At the south end of the passage is a door above which a sign in elaborate
    Olde English letters reads <q>INKWELL FINE PRINT.</q> In the west wall
    is a broad display window, and next to it a door above which is a flowery pink sign
    that reads <q>YOUR GORGEOUS SELF.</q> A gray door to the northwest bears
    a small sign with the universal symbol for unisex lavatories.<<checkForBetsy()>> "
    
    // This worries me, because I don't know if it will interfere with Betsy's
    // travel-allowed region:
    regions = [betsyGoneRegion, joeFollowingRegion, ajouMarchingRegion]

    checkForBetsy() {
        if ((betsy.isIn(beautyParlor)) && !betsy.hasJustExited) {
            gPlayerChar.setHasSeen(betsy);
            "<.p>Through the window of the beauty parlor you can see ";
            if (betsy.proper) "Betsy";
            else if (beautyParlor.visited) "the young woman";
            else "a thin, awkward-looking young woman";
            " wandering around in a vague, desultory way. ";
        }
    }
    north = arcadeNorth
    northwest = restroom
    west = gorgeousSelfDoorOutside
    east = arcadeCenter
    south = bookshopDoorOutside
    southwest = mainElevatorDoor
;

+ mainElevatorDoor: ElevatorDoorExterior '+'
    otherSide = fakeDoorToNowhere
;

+ mainBrassPlate: SummonButtonPlate '+'
;

++ mainSummonButton: SummonButton '+'
    myNumber = 2
;

+ bookshopDoorOutside: ShopDoorOutside '+ ; book inkwell fine print'
    otherside = bookshopDoorInside
;

+ inkwellSign: ShopSign 'Inkwell Fine Print +; bookstore'
    "The <q>INKWELL FINE PRINT</q> sign depicts a couple of open books and an old-fashioned inkwell, into
    which has been inserted a quill pen. "
;

+ gorgeousSelfSign: ShopSign 'Your Gorgeous Self +; beauty parlor'
    "Around the letters of the <q>YOUR GORGEOUS SELF</q> sign is curled an extravagant
    mass of blond hair. "
;

+gorgeousSelfDoorOutside: ShopDoorOutside '+ ; (your) gorgeous self beauty parlor'
    otherSide = gorgeousSelfDoorInside
    isLocked = nil
    execTravel(actor, traveler, conn) {
        if (!beautyParlor.visited) {
            betsy.setState(betsyClinging);
            betsy.startFollowing();
            betsy.addToAgenda(mentionSmoking.setDelay(7));
            "You tap lightly on the door. The young woman in the beauty parlor
            jumps about a foot, stares at you for a moment, and then scurries
            over to unlock and open the door. <q>We're closed,</q> she
            says. <q>I'm really sorry. I mean --- did you want to make an
            appointment or --- or anything? I don't mean to be rude. I'm
            just --- I'm waiting for somebody, is all. Would you like to --- oh,
            I don't mean to be rude. Come on in, please. Come in.</q> She stands aside,
            and you enter the shop. ";
        }
        inherited(actor, traveler, conn);
    }
    dobjFor (KnockOn) {
        check() {
            if (isOpen) "Why not just walk on in? ";
        }
        action() {
            if (betsy.isIn(beautyParlor) && !beautyParlor.visited) {
                // makeLocked(nil);
                makeOpen(true);
                betsy.setState(betsyClinging);
                betsy.addToAgenda(mentionSmoking.setDelay(7));
                "You tap lightly on the door. The young woman in the beauty parlor
                jumps about a foot, stares at you for a moment, and then scurries
                over to unlock and open the door. <q>We're closed,</q> she
                says. <q>I'm really sorry. I mean --- did you want to make an
                appointment or --- or anything? I don't mean to be rude. I'm
                just --- I'm waiting for somebody, is all. Would you like to --- oh,
                I don't mean to be rude. Come on in, please. Come in.</q> She stands aside,
                and you enter the shop.<.p> ";
                me.moveInto(beautyParlor);
                beautyParlor.lookAroundWithin();
                betsy.startFollowing();
            }
            else inherited;
        }
    }
;

+viewOfBetsy: Distant 'young woman; thin wandering'
    "<<if (betsy.isIn(beautyParlor))>>Within the beauty parlor a thin, awkward-looking
    young woman is wandering around<<else>>You see no one who answers to that description<<end>>. "
;

+ beautyParlorWindow: Fixture 'broad display window; (beauty) (parlor)'
    "Through the window you can see the usual appurtenances of a beauty parlor --- chairs,
    basins, and shelves along which march rows of bottles. <<checkForBetsy>>"
    checkForBetsy {
        if (betsy.isIn(beautyParlor)) {
            tBetsy.makeFamiliar();
            gPlayerChar.setHasSeen(betsy);
            "Within the beauty parlor ";
            if (betsy.proper) "Betsy";
            else if (beautyParlor.visited) "the young woman";
            else "a thin, awkward-looking young woman";
            " is wandering around in a vague, desultory way. ";
        }
    }
    dobjFor(KnockOn) {
        check() {
            if (beautyParlor.visited) "Instead of tapping on the window, why
                not just walk through the door? ";
        }
        action() {
            if (betsy.isIn(beautyParlor) && !beautyParlor.visited) {
                gorgeousSelfDoorOutside.makeLocked(nil);
                gorgeousSelfDoorOutside.makeOpen(true);
                betsy.setState(betsyClinging);
                betsy.addToAgenda(mentionSmoking.setDelay(7));
                "You tap lightly on the window. The young woman in the beauty parlor
                jumps about a foot, stares at you for a moment, and then scurries
                over to unlock and open the door. <q>We're closed,</q> she
                says. <q>I'm really sorry. Your hair --- I mean --- did you want to make an
                appointment or --- or anything? I don't mean to be rude. I'm
                just --- I'm waiting for somebody, is all. Would you like to --- oh,
                I don't mean to be rude. Come on in, please. Come in.</q> She stands aside,
                and you enter the shop.<.p> ";
                me.moveInto(beautyParlor);
                beautyParlor.lookAroundWithin();
                betsy.startFollowing();
            }
            else "You tap lightly on the window. ";
        }
    }
    dobjFor(LookIn) asDobjFor(LookThrough)
    dobjFor(LookThrough) {
        verify() {}
        check() {}
        action() {
            replaceAction (Examine, self);
        }
    }
;

//-----------------------------------------------------------------------------
// restroom
//-----------------------------------------------------------------------------
    
holeConnector: TravelConnector
    destination = damagedHallwayNorth
    canTravelerPass(t) {
        // Note: Neither Betsy nor Joe will be able to climb the ladder...
        if (t == gPlayerChar) 
            return (stepladder.isDirectlyIn(restroom) && stepladder.unfolded);
        else return nil;
    }
    explainTravelBarrier(t) {
        if (t == gPlayerChar)
            "The hole is too far overhead. You can't quite reach it. ";
        else if (t == redWagon)
            "The wagon can only roll on a level surface. ";
        else if (stepladder.isDirectlyIn(restroom) && stepladder.unfolded) {
            "You're the only one who wants to climb the ladder. ";
        }
        else "There's no way up from here. ";
    }
    travelBarriers = [wagonBarrier]
;

// An attempt to short-circuit the problem with 'pull wagon up':

Doer 'pull redWagon up'
    execAction (c) {
        "The wagon can only roll on a level surface. ";
        abort;
    }
    where = restroom
;

restroom: Room 'Restroom'
    "The fixtures in this tiled cubicle are about what you'd expect --- a commode,
    a toilet paper dispenser (empty, of course), a paper towel dispenser (ditto),
    a sink, and above the sink a mirror. In the past ten years,
    one new fixture has been added: A baby-changing
    station is mounted on the wall. Oh, and also, the ceiling has caved in. The
    worst of the debris
    has been swept up, but there's still a gaping hole directly overhead, which would
    tend to eliminate any chance of privacy were you in need of the usage of the
    facilities, which fortunately you're not.
    
    <.p>The exit back to the arcade is to the southeast. "
    
    roomBeforeAction() {
        if (gActionIs(Jump)) {
        "Even by jumping, you're unable to reach the edge of the hole. ";
            exit;
        }
    }
    out asExit(southeast)
    southeast = arcadeWest
    up = holeConnector
;

+ holeFromBeneath: Fixture 'gaping hole; ; ceiling'
    "The hole in the ceiling is quite wide. There seems to be another room up there. "
    iobjFor(PutUnder) {
        verify() {}
        check() {}
        action() {
            doInstead(Drop, gDobj);
        }
    }
    dobjFor(GoThrough) asDobjFor(Enter)
    dobjFor(Enter) {
        verify() {}
        action() {
            doInstead(Go, upDir);
        }
    }
;

+ anotherRoom: Distant 'another room'
    "You can\'t see much of it from down here. "
;

+ toilet: Fixture 'porcelain toilet; (white); commode'
    "It's an ordinary-looking toilet. "
    dobjFor(SitOn) {
        verify() {}
        check() {
            "At the moment, you have no need to do that. ";
        }
    }
    iobjFor(PutIn) {
        verify() {}
        check() {
            "{The dobj} would get wet. Also unsanitary. ";
        }
    }
;

+ sink: Decoration 'sink'
    "It's an ordinary-looking sink. "
;

+ faucet: Decoration 'faucet;; spigot'
    "The faucet isn't dripping. "
;

+ restroomMirror: Decoration 'wall-mounted mirror; (restroom) smeared; smear smears'
    "The wall-mounted mirror is a bit smeared. "
;

+ babyChanging: Decoration 'baby-changing station'
    "It's a typical baby-changing station. "
;

++ tpDispenser: Decoration 'toilet paper dispenser; empty'
    "There's nothing in the toilet paper dispenser. "
;

//-----------------------------------------------------------------------------
// beautyParlor
//-----------------------------------------------------------------------------

beautyParlor: Shop 'Beauty Parlor'
    "A typical hairdresser's salon --- a row of chairs, some basins,
    shelves overflowing with bottles of lotions, all the expected accoutrements.
    Some tattered magazines are scattered on a low table in the waiting area,
    and the room has a strong flowery scent.<<tBetsy.makeFamiliar()>>
    
    <.p>The door back to the arcade is to the east.
    An open doorway leads south, and an unmarked door is situated in the north wall. "
    
    firstDeparturePrinted = nil
    lockingSuggested = nil
    beforeTravel(traveler, connector) {
        if (connector != gorgeousSelfDoorInside) return;
        if (betsy.curState != betsySmoking) return;
        if (coatClosetDoorOutside.isLocked) return;
        if (betsy.getOutermostRoom() == nil) return;
        if (!lockingSuggested) {
            lockingSuggested = true;
            "As you're headed for the door, it occurs to you that {the betsy} is
            only going to be in there smoking for a couple of minutes, after which
            she'll likely track you down again. Let's face it, she's a pest. Maybe
            you could lock her in the closet. Yes, it's an evil thing to do, but
            on the other hand, she stole your grandmother's ring, and anyway her
            boyfriend will surely be here to pick her up in a few minutes, so 
            really it's no big deal. Having made up your mind, you tiptoe over
            to the closet and stealthily flip the latch. ";
            coatClosetDoorOutside.makeLocked(true);
            coatClosetDoorOutside.makeOpen(nil);
            exit;
        }
    }
    
    regions = [betsyGoneRegion]
    
    east = gorgeousSelfDoorInside
    south = tackyLounge
    north = coatClosetDoorOutside
    in asExit(north)
    out asExit(east)
;

+ gorgeousSelfDoorInside: ShopDoorInside
    '+; (beauty) (parlor) (gorgeous) (self)'
    "The door leading back out to the arcade is in the east wall. "
    otherSide = gorgeousSelfDoorOutside
    isLocked = nil
;

+ Decoration 'low table'
    "The table is the final resting place for some magazines. "
;

+ Decoration 'tattered magazines; women\'s; magazine issue issues'
    "The magazines seem to be neither current nor interesting. "
    plural = true
;

+ Decoration 'lotion bottles; graceful; shapes'
    "The lotion bottles have various graceful shapes. "
    plural = true
;

+ Decoration 'basins; ; basin'
    "The basins are not worth lingering over. "
    plural = true
;

+ Decoration 'row of chairs; ; chair; it them'
    "Resting your feet for a moment is a temptation, but really the chairs are not important. "
;

+ Decoration 'shelves; ; shelf'
    "The shelves are crammed with the usual stuff. "
    plural = true
;

// The portable stuff on the counter is in PDthings:

+ beautyParlorCounter: Surface, Fixture
    'display case; glass-enclosed glass enclosed'
    "The glass-enclosed display case supports the cash register. "
;

     
+ coatClosetDoorOutside: Door 'closet door; coat'
    "The door looks to be fairly solid. It has a brass latch. <<if (!isOpen && betsy.curState == betsySmoking)>>A curl
    of gray cigarette smoke is escaping from under the door. "
    isLocked = nil
    lockability = indirectLockable
    otherSide = coatClosetDoorInside
    dobjFor(Lock) {
        verify() {}
        check() {
            if (isLocked) "The closet door is already locked. ";
        }
        action() {
            makeLocked(true);
            "You flip the latch, locking the closet door. ";
            
            if ((betsy.curState == betsySmoking) && (!beautyParlor.lockingSuggested))
                "This feels a bit cruel, but after all,
                she <i>did</i> steal your grandmother's ring, and anyway, you're fed up with
                her following you around, and anyway it's a good bet her boyfriend will be here
                any minute to pick her up, so he'll let her out. ";
        }
    }
    dobjFor(Unlock) {
        verify() {}
        check() {
            if (!isLocked) "The closet door is not locked at present. ";
            else if ((betsy.curState == betsySmoking) && (betsy.getOutermostRoom() == coatCloset))
                "As your hand moves toward the latch, you hesitate. She must like
                being in there. Why disturb her? ";
        }
        action() {
            makeLocked(nil);
            "You flip the latch, unlocking the closet door. ";
        }
    }
;

++ brassLatch: Component 'brass latch;; lever'
    "The latch is a lever mounted on the door, just above the doorknob. At the moment
    the upper end of the latch is angled <<coatClosetDoorOutside.isLocked ? 'toward' : 'away from'>>
    the near edge of the door. "
    
    dobjFor(Flip) asDobjFor(Turn)
    dobjFor(Push) asDobjFor(Turn)
    dobjFor(Turn) {
        preCond = [touchObj]
        verify() {}
        check() {}
        action() {
            coatClosetDoorOutside.makeLocked (!(coatClosetDoorOutside.isLocked()));
            "You flip the latch, ";
            if (coatClosetDoorOutside.isLocked) "locking";
            else "unlocking";
            " the closet door. ";
        }
    }
; 

//-----------------------------------------------------------------------------
// tackyLounge
//-----------------------------------------------------------------------------

/* 
 *   Note: At the moment (2/14/14) this room exists strictly because it was in
 *   the first game. There are at least two possibilities. We could replace it
 *   with an entirely different room, or we could put something interesting in
 *   it. Worth thinking about.
 */

tackyLounge: Room 'Tacky Lounge'
    "Judging by the narrow cot in the corner, this room is intended to be
    used by hairdressers or patrons who need to lie down. The restfulness
    of the room is open to debate, however, as one wall is dominated by
    a large and garish portrait of Elvis Presley --- painted, inevitably,
    on black velvet. The open doorway leads north. "
    
    regions = [betsyGoneRegion]
    north = beautyParlor
    out asExit(north)
;

+ Decoration 'cot; narrow'
    "Ten years ago, there was a mechanism hidden under the cot. A quick glance
    reveals that today there's nothing at all under the cot. Evidently the cot
    isn't important. "
;

+ elvisPortrait: Fixture
    'portrait of Elvis Presley; tacky bilious king black head potato-head potato mr cherry-red; poster sneer halo cheeks velvet'
    "The Elvis portrait would be stunningly tacky even if it were a good
    likeness --- and it's not. It's about five feet high and three feet
    wide, and painted on black velvet. His head is surrounded by a bilious multicolored halo
    that probably glows in the dark. The cherry-red cheeks and pasted-on sneer
    resemble Elvis less than they resemble Mr.\ Potato-Head.
    
    <.p>The border of the portrait, a thick stripe with alternating patches of green, pink,
    blue, and violet, matches the halo. "
    
    takeCount = 0
    dobjFor(Take) {
        verify() {}
        check() {
            takeCount++;
            if (takeCount == 1)
            "As you deftly detach the black velvet portrait of
                Elvis from the wall, you\'re pole-axed by an attack of
                indigestion the like of which you\'ve never even imagined.
                Gas? Pancreas? Gall bladder? All of the above? Doubled over
                with pain and nausea, you stagger to the cot and collapse, whimpering.
                The minutes pass with excruciating slowness, but eventually
                the pain slackens. Chastened by your encounter with worldly
                idolatry, you totter over to the wall and put the poster back
                where you found it. Almost immediately you feel much, much
                better. ";
            else
                "No force on Earth could persuade you to touch the Elvis portrait again. ";
        }
    }
;

//-----------------------------------------------------------------------------
// coatCloset
//-----------------------------------------------------------------------------

coatCloset: Room 'Closet'
    "The horizontal bar and pink plastic hangers make it seem likely that this
    tiny, cramped chamber is used as a coat closet. No coats are in evidence,
    however; the hangers on the rod are empty. Extra bottles of this and that
    are stored on a shelf. The closet smells powerfully of stale cigarette smoke.
    
    <p>The door is to the south. "
    
    dobjFor(Close) {
        verify() {}
        action() {
            doInstead (Close, coatClosetDoorInside);
        }
    }
    dobjFor(Open) {
        verify() {}
        action() {
            doInstead (Open, coatClosetDoorInside);
        }
    }
    
    regions = [betsyGoneRegion]
    
    out asExit(south)
    south = coatClosetDoorInside
;

+ Odor 'cigarette smoke; foul; fug odor stink stench'
    "What a foul stench! "
    smellDesc = "You breathe in the foul odor of cigarette smoke. "
;

+ coatClosetDoorInside: Door 'door; closet'
    "The door has a knob on this side, but no keyhole and no latch. "
    otherSide = coatClosetDoorOutside
    vocabLikelihood = 15
    dobjFor(Lock) {
        verify() {}
        check() {
            "It appears there's no way to lock the door from the inside. ";
        }
    }
    dobjFor(Unlock) {
        verify() {}
        check() {
            "If it were locked, you wouldn't have been able to get into the closet. ";
        }
    }
;
   
+ closetShelf: Surface, Fixture '(closet) shelf'
    "The shelf is strewn with plastic bottles. "
    bulkCapacity = 80
    // lookInMsg = 'You find nothing of interest among the bottles on the shelf. '
    dobjFor(Search) {
        verify() {}
        check() {}
        action() {
            
            if (ashtray.isHidden) {
                ashtray.discover();
                "Tucked well back among the bottles on the shelf, you spot a small plastic ashtray. ";
                if (contents.length() < 3) "There's nothing else of any interest on the shelf. ";
                else inherited;
            }
            else inherited;
        }
    }
;

++ closetBottles: Decoration 'plastic bottles; beauty; products; them'
    "An assortment of beauty products. "
    decorationActions = [Search, LookIn]
    notImportantMsg = 'The plastic bottles are not important. '
    bulk = 20
    dobjFor(Search) {
        verify() {}
        check() {}
        action() {
            doInstead (Search, closetShelf);
        }
    }
;

// Note: If the ashtray becomes a possible solution to another puzzle, we'll need to
// allow you to remove it.
++ ashtray: Container 'filthy plastic ashtray; small round dirty smelly stinky'
    "The ashtray is small and round, like most of its tribe. It hasn't been cleaned
    for a while, and smells powerfully of cigarette ash. However, there are no butts
    in it at the moment. "
    isHidden = true
    dobjFor(Take) {
        verify() {}
        check() {
            discover();
            "You ponder, briefly, burdening yourself with a filthy ashtray,
                and reject the idea as absurd. ";
        }
    }
    notifyInsert (obj) {
        if (obj != marlboros) {
            "{The obj} would only get filthy. ";
            exit;
        }
    }
;

// Note: There's some possibility of a puzzle here. If you could loosen the bar,
// you could slide a hanger off. It might be good for something, though I can't
// think what....

+ horizontalBar: Fixture 'horizontal bar;; rod pole'
    "The bar runs, at about head height, from one side of the closet to the other.
    Half a dozen pink plastic hangers (empty) are suspended from it. "
    cannotTakeMsg = 'The bar proves to be firmly mounted at both ends. It\'s not
        going anywhere. '
;

+ pinkHangers: Surface, Fixture 'pink plastic hangers;; hanger; them'
    "The hangers are suspended from the horizontal bar. Inspired, perhaps, by the
    design of hangers in motel rooms, their hooks completely encircle the bar. "
    cannotTakeMsg = 'The hangers are securely attached to the bar. '
    notifyInsert (newCont) {
        "Hanging anything from the pink plastic hangers is surely unnecessary. ";
        exit;
    }
    plural = true
;

//-----------------------------------------------------------------------------
// arcadeCenter
//-----------------------------------------------------------------------------

arcadeCenter: Room 'Center of the Arcade'
    "The center of the arcade is open to the cloudless blue sky, but surrounded on
    all sides by the main and upper levels of Stufftown. On the main level there are
    railings on the east, north and west, each railing containing an opening through
    which you can pass. The railings on the upper walkways are not reachable from
    here, except via a stairway on the west side. Above a door to the southeast is
    a sign that proclaims <q>MADAME BLOVIATSKY, SEERESS.</q>
    
    <.p>The south end of this area is occupied by a very large table containing a diorama
    of some sort. "
    
    // Garbage collection:
    beforeTravel(traveler, connector) {
        if (traveler != gPlayerChar) return;
        local toBeDroppedList = [];
        local obj = nil;
        local thingie = nil;
        if (shoppingBag.isIn(me)) {
            foreach (obj in shoppingBag.contents) {
               if (!obj.stillNeeded && !obj.ditchedOnce) {
                    obj.ditchedOnce = true;
                    toBeDroppedList += obj;
                } 
            }
        }
        foreach (obj in me.contents) {
            if (!obj.stillNeeded && !obj.ditchedOnce) {
                obj.ditchedOnce = true;
                toBeDroppedList += obj;
            }
        }
        if (toBeDroppedList.length > 1) {
            foreach (thingie in toBeDroppedList) {
                thingie.ditchedOnce = true;
                thingie.moveInto(arcadeCenter);
            }
            "Realizing you have no current need for some of the things you\'re carrying,
            such as <<thingie.theName>>, you
            decide to leave some stuff here for the time being. ";
        }
        else if (toBeDroppedList.length == 1) {
            local thatThing = toBeDroppedList[1];
            thatThing.moveInto(arcadeCenter);
            "Realizing you have no current need for <<thatThing.theName>>, you
            decide to leave <<if (thatThing.plural)>>them<<else>>it<<end>> here for the time being. ";
            
        }
    }
    
    regions = [betsyGoneRegion, joeFollowingRegion, ajouMarchingRegion]
    
    north = arcadeNorth
    west = arcadeWest
    east = arcadeEast
    southeast = seeressLair
    up: TravelConnector, AjouStairs {
        destination = arcadeStairwayUp
        travelBarriers = [wagonBarrier]
    }
;

+ Decoration 'sky'
    "It looks bluish. "
;

+ arcadeStairwayUp: StairwayUp 'flight of stairs;; staircase stairway; it them'
    "The stairs lead up to a covered walkway that runs around the four sides
    of the central arcade. "
    destination = upperConcourseWest
    dobjFor(ClimbUp) {
        action() {
            if ((betsy.getOutermostRoom() == gPlayerChar.getOutermostRoom()) &&
                betsy.curState == betsyClinging)
                betsyClinging.departMessages.doScript();
            inherited();
        }
    }
    dobjFor(Climb) {
        action() {
            if ((betsy.getOutermostRoom() == gPlayerChar.getOutermostRoom()) &&
                betsy.curState == betsyClinging)
                betsyClinging.departMessages.doScript();
            inherited();
        }
    }
;

//--------------------------------------------------------------------------------------
// the underside is implemented as a separate room:
//--------------------------------------------------------------------------------------

squareHole: Fixture 'square hole'
    "The square hole is in the underside of the diorama. Looking up through the hole,
    you can't see a darn thing that's up there. "
    dobjFor(LookThrough) asDobjFor(LookIn)
    iobjFor(PutIn) {
        verify() {}
        check() {
            "You'd only clutter up the nice diorama. ";
        }
    }
    iobjFor(AimAt) {
        verify() {}
        check() {
            if ((gDobj != moneyMagnet) || (fakeGoldCoin.isIn(nil))) "Nothing happens. ";
        }
        // Here, the player has aimed the u-shaped piece of metal at the square hole,
        // and coin3 is still in the diorama:
        action() {
            fakeGoldCoin.moveInto(nil);
            coin3.moveInto(gPlayerChar);
            coin3.moved = true;
            coin3.seen = true;
            coin3Ach.awardPointsOnce();
            "For a moment, the only result is a quiet scooting noise. But then a
            gold coin drops through the square hole into your hand. ";
        }
    }
    dobjFor(LookIn) {
        verify() {}
        check() {
            if (fakeGoldCoin.isIn(nil)) "Groping around in the diorama, you're unable
                to put your fingers on anything else that's loose enough to pull free. ";
        }
        action() {
            fakeGoldCoin.moveInto(nil);
            coin3.moveInto(gPlayerChar);
            coin3.moved = true;
            coin3.seen = true;
            coin3Ach.awardPointsOnce();
            "Not much is to be seen through the hole. Groping around, however, your
            fingers encounter something
            round and metallic, which you draw out. It proves to be a gold coin. ";
        }
    }
;

dioramaUnderside: Room 'Beneath the Diorama'
    "Not much is to be seen down here, other than bits of trash. Inches above your
    head, however, is a small square metal plate, which appears to be fastened in
    place by a screw.<<if (squareHole.isIn(self))>> The plate has been loosened,
    revealing a square hole.<<end>> "
    // Rather than make the diorama a separate object, we'll let the room
    // handle the player's possible actions:
    dobjFor(LookThrough) asDobjFor(LookIn)
    dobjFor(LookIn) {
        verify() {}
        check() {
            if (!squareHole.isIn(self)) "If you want to search the diorama, you'll
                need to loosen the screw holding that square plate. ";
        }
        action() {
            doInstead (Search, squareHole);
        }
    }
    dobjFor(Move) {
        verify() {}
        check() {
            "You hunch your shoulders and give the thing a shove, but it's much too
            heavy. ";
        }
    }
    beforeTravel(t, c) {
        if (betsy.curState == betsyByDiorama) {
            "<q>Oh, there you are,</q> {the betsy} says. <q>I wondered where you
            had gone.</q> ";
            betsy.setState(betsyClinging);
        }
    }
    north asExit(out)
    out = arcadeCenter
;

+ Decoration 'scatter of useless trash[n]; ; junk rubbish'
"It's just a scatter of useless trash. "
notImportantMsg = 'None of it is of any conceivable use. '
;

+ squareMetalPlate: Fixture 'square metal plate; ; hatch panel'
    "<<if (!unscrewed)>>The plate seems to be fastened in place by a screw<<else>>The
    plate is hanging down from the underside of the diorama by a hinge along one side<<end>>. "
    
    // Here's the important action -- getting the coin:
    dobjFor(LookIn) {
        verify() {}
        check() {
            "It's just a metal plate.<<if unscrewed>> If you want to search the square
            hole, you should probably say so.<<end>> ";
        }
    }   
    unscrewed = nil
    dobjFor(Loosen) asDobjFor(Unscrew)
    dobjFor(Unfasten) asDobjFor(Unscrew)
    dobjFor(Unscrew) {
        verify() {}
        check() {
            if (unscrewed) "You've already unscrewed the metal plate. ";
            else if (!screwdriver.isDirectlyIn(gPlayerChar))
                "You don't seem to be holding a screwdriver. ";
        }
        action() {
            unscrewed = true;
            squareHole.moveInto(dioramaUnderside);
            "You unscrew the metal plate, so that it's dangling down from a hinge along one side.
            A square hole in the underside of the diorama has been revealed. ";
        }
    }
    dobjFor(OpenWith) asDobjFor(UnscrewWith)
    dobjFor(UnscrewWith) {
        verify() {}
        check() {
            if (gIobj && (gIobj != screwdriver)) "{The dobj} doesn't appear to be a suitable implement. ";
        }
        action() {
            doInstead(Unscrew, self);
        }
    }
    dobjFor(Fasten) asDobjFor(Screw)
    dobjFor(Screw) {
        verify() {}
        check() {
            if (!unscrewed) "The metal plated is already screwed firmly into place. ";
            else if (!screwdriver.isDirectlyIn(gPlayerChar))
                "You don't seem to be holding a screwdriver. ";
        }
        action() {
            unscrewed = nil;
            squareHole.moveInto(nil);
            "You screw the plate back into place. ";
        }
    }
    dobjFor(ScrewWith) {
        verify() {}
        check() {
            if (gDobj != screwdriver) "{The dobj} doesn't appear to be a suitable implement. ";
        }
        action() {
            doInstead(Screw, self);
        }
    }
;

+ plateScrew: Fixture 'screw; slotted'
    "The screw is slotted for a standard screwdriver. "
    dobjFor(Loosen) asDobjFor(Unscrew)
    dobjFor(Unscrew) {
        verify() {}
        check() {
            if (squareMetalPlate.unscrewed) "You've already unscrewed the metal plate. ";
            else if (!screwdriver.isDirectlyIn(gPlayerChar))
                "You don't seem to be holding a screwdriver. ";
        }
        action() {
            doInstead(Unscrew, squareMetalPlate);
        }
    }
    dobjFor(UnscrewWith) {
        verify() {}
        check() {
            if (gDobj != screwdriver) "{The dobj} doesn't appear to be a suitable implement. ";
        }
        action() {
            doInstead(Unscrew, squareMetalPlate);
        }
    }
    dobjFor(Screw) {
        verify() {}
        check() {
            if (!squareMetalPlate.unscrewed) "The metal plated is already screwed firmly into place. ";
            else if (!screwdriver.isDirectlyIn(gPlayerChar))
                "You don't seem to be holding a screwdriver. ";
        }
        action() {
            doInstead(Screw, squareMetalPlate);
        }
    }
    dobjFor(ScrewWith) {
        verify() {}
        check() {
            if (gDobj != screwdriver) "{The dobj} doesn't appear to be a suitable implement. ";
        }
        action() {
            doInstead(Screw, squareMetalPlate);
        }
    }
;

//-----------------------------------------------------------------------------
// arcadeEast
//-----------------------------------------------------------------------------

arcadeEast: Room 'East Side of the Arcade'
    "This covered walkway runs north and south along the east side of the shopping
    mall's central arcade. A gap in the railing here affords access
    to the center of the arcade to your west. To the south is a stairway leading
    downward. To the northeast is a door above which a sign
    reads <q>COLOSSAL ADVENTURE,</q> and directly to the east is an open doorway
    beneath a sign that reads <q>SCOOTERS IRISH PUB.</q> " 
    regions = [joeFollowingRegion, ajouMarchingRegion]
    west = arcadeCenter
    north = arcadeNorth
    northeast = travelAgencyDoorOutside
    // south asExit (down)
    south: TravelConnector, AjouStairs {
        destination = southStairsTop
        travelBarriers = [wagonBarrier]
    }
    down: TravelConnector, AjouStairs {
        destination = southStairsTop
        travelBarriers = [wagonBarrier]
    }
    east = scootersPub
;

+ scootersPubSign: ShopSign
    'Scooters Irish Pub +; green passed out; leprechaun'
    "The <q>SCOOTERS IRISH PUB</q> sign depicts a green leprechaun who is passed out, flat on his back. "
;

+ colossalAdventureSign: ShopSign
    'Colossal Adventure +; mount; pyramids planes airliner airplane airliners airplanes planes rushmore motif'
    "The <q>COLOSSAL ADVENTURE</q> sign is decorated with a motif of palm trees and airliners. The pyramids squat
    in one corner, but the Sphinx has been omitted in favor of Mount Rushmore. "
;

+ travelAgencyDoorOutside: ShopDoorOutside '+ ; colossal adventure travel agency'
    "The door is northeast of where you're standing. "
    otherSide = travelAgencyDoorInside
;

+ southStairsTop: StairwayDown, AjouStairs 'flight of stairs;; stairway staircase; them'
    "The flight of stairs leads downward from the south end of the walkway. "
    destination = footOfStairs
    dobjFor(ClimbDown) {
        action() {
            if ((betsy.getOutermostRoom() == gPlayerChar.getOutermostRoom()) &&
                betsy.curState == betsyClinging)
                betsyClinging.departMessages.doScript();
            inherited();
        }
    }
;
    
//-----------------------------------------------------------------------------
// goingToPot
//-----------------------------------------------------------------------------
    
goingToPot: Shop 'Pottery Shop'
    "Ceramics of all kinds line the shelves of this tidy little shop. In one corner
    stands a horizontally mounted wheel, before which is a stool on which one could sit.
    Beneath the wheel are a small motor and a gear assembly. 
    <.p>The door to the arcade is to the southwest, and an open doorway is to the northeast. "
    southwest = potteryDoorInside
    out asExit(southwest)
    northeast: TravelConnector {
        destination = fileRoom
        canTravelerPass(t) {
            if (fileRoom.blockedByStuffy || fileRoom.blockedByBlizzard) return nil;
            return true;
        }
        explainTravelBarrier(t) {
            if (fileRoom.blockedByStuffy) "You take a few steps past the door and
                catch a glimpse of a carpet of loose papers on the floor, but the air
                is so terribly stuffy that you can't breathe! You retreat hurriedly. ";
            else "Beyond the doorway is a swirling, tempestuous blizzard of loose papers,
                which are flying everywhere. There would seem to be no way to fight
                your way through all that. ";
        }
    }
;

+ potteryDoorInside: ShopDoorInside
    otherSide = potteryDoorOutside
;

+ Decoration 'ceramics'
    "The ceramics are varied, and nicely turned. "
    plural = true
;

+ Decoration 'shelves'
    "The shelves hold ceramics. "
    plural = true
;

+ Decoration 'stool'
    "The stool is for sitting on while one works clay on the wheel. But you have
    no clay, and learning the craft of pottery-making is not your goal this afternoon. "
;

+ wheel: Fixture, Surface 'horizontal wheel; potter\'s'
    "The wheel is about 60cm in diameter (that's two feet, to you Americans). It's mounted
    horizontally, and the surface is dotted here and there with crumbs of dried clay. Beneath
    the wheel is a small motor.<<if (turning)>> The wheel is spinning rapidly.<<end>> "
    notifyInsert(obj) {
        gMessageParams(obj);
        if (turning) "Anything you put on the wheel would only fly off. Centrifugal
            force, you know. ";
        else "You put {the obj} on the wheel for a moment to judge the aesthetic
            effect. No, the resemblance to a lump of clay is not overwhelming, so
            you pick {that obj} up again. ";
    }
    turning() { return (motor.running && gearAssembly.connected); }
    dobjFor (Turn) {
        verify() {}
        check() {
            if (turning) "The wheel is already turning at a good clip. ";
        }
        action() {
            "You give the wheel an experimental nudge. Sure enough, it turns. ";
        }
    }
    startTurning() {
        if (!gearAssembly.connected) return;
        "The wheel starts spinning rapidly. ";
        wheelAch.awardPointsOnce();
        mirrorBall.startSpinning();
    }
    stopTurning() {
        if (!turning) return;
        "The wheel slows and stops. ";
        mirrorBall.stopSpinning();
    }
;

++ Decoration 'crumbs of dried clay'
    "The crumbs of dried clay are possibly the least interesting thing you've seen today. "
    plural = true
;

++ motor: Component, Switch 'motor; small; tank'
    "The motor is a small, pleasant-looking contraption. It's equipped with a switch,
    a round cap labeled with the word FUEL, and a gear assembly that lies between the motor
    and the geared shaft beneath the wheel.<<if (running)>> The motor is putt-putting happily
    to itself.<<end>> "
    // Not sure we need both running and switchedOn, but let's be tidy.
    running = nil
    fueled = nil
    switchedOn = nil
    iobjFor(AttachTo) asIobjFor(PutOn)
    iobjFor(PutOn) {
        verify() {}
        check() {
            if (gDobj != leatherBelt) "You can't put that on the motor. ";
        }
        action() {
            doInstead (PutOn, gDobj, gearAssembly);
        }
    }
    dobjFor(Start) {
        verify() {}
        action() {
            doInstead (SwitchOn, self);
        }
    }
    dobjFor(Stop) {
        verify() {}
        action() {
            doInstead (SwitchOff, self);
        }
    }
    dobjFor (SwitchVague) {
        action() {
            inherited;
            switchThrown(0);
        }
    }
    dobjFor (SwitchOn) {
        action() {
            inherited;
            switchThrown(1);
        }
    }
    dobjFor (SwitchOff) {
        action() {
            inherited;
            switchThrown(-1);
        }
    }
    // We don't know which way the switch
    // is being thrown, so we'll send -1 if it's being switched off, 1 if it's
    // being switched on, and 0 if called from SwitchVague:
    switchThrown(val) {
        if (!fueled) "You fiddle with the switch, but it doesn't seem to be
            doing anything. ";
        // In this branch, we don't know if it's being switched on or off:
        else if (val == 0) {
            if (!switchedOn) {
                switchedOn = true;
                running = true;
                "The motor starts up smoothly with a little putt-putt noise. ";
                wheel.startTurning();
            }
            else {
                switchedOn = nil;
                running = nil;
                if (wheel.turning) wheel.stopTurning();
                "The motor falls silent. ";
            }
        }
        // we're being switched on:
        else if (val == 1) {
            if (switchedOn) "The motor is already switched on. ";
            else {
                switchedOn = true;
                running = true;
                "The motor starts up smoothly with a little putt-putt noise. ";
                if (leatherBelt.attached) {
                    wheel.startTurning();
                }
            }
        }
        // we're being switched off:
        else {
            if (!switchedOn) {
                "The motor is already switched off. ";
            }
            else {
                switchedOn = nil;
                running = nil;
                "The motor stops. ";
            }
        }
    }
    dobjFor(Open) {
        verify() {}
        action() {
            doInstead(Unscrew, fuelCap);
        }
    }
    dobjFor(Close) {
        verify() {}
        action() {
            doInstead(ScrewOn, fuelCap);
        }
    }
    iobjFor(PutIn) asIobjFor(PourInto)
    // The wineBox handles checking the fuel cap:
    iobjFor(PourInto) {
        verify() {}
        check() {
            if (gDobj != wineBox) "That's probably not suitable as fuel for a motor. ";
        }
    }
;
+++ motorSwitch: Component, Switch 'switch'
    "The switch is mounted on the side of the motor. "
    dobjFor(Throw) asDobjFor(SwitchVague)
    dobjFor (SwitchVague) {
        action() {
            inherited;
            motor.switchThrown(0);
        }
    }
    dobjFor(Pull) asDobjFor(Push)
    dobjFor(Push) {
        verify() {}
        action() {
            if (isOn) doInstead(SwitchOff, self);
            else doInstead(SwitchOn, self);
        }
    }
    dobjFor (SwitchOn) {
        action() {
            inherited;
            motor.switchThrown(1);
        }
    }
    dobjFor (SwitchOff) {
        action() {
            inherited;
            motor.switchThrown(-1);
        }
    }
;
+++ fuelCap: Component 'fuel cap'
    "The fuel cap is part of the motor. It can be unscrewed and screwed back on. "
    unscrewed = nil
    unscrewedBefore = nil
    dobjFor(Close) asDobjFor(ScrewOn)
    dobjFor(ScrewOn) {
        verify() {}
        check() {
            if (!unscrewed) "The fuel cap is already screwed on. ";
        }
        action() {
            doInstead (Screw, self);
        }
    }
    dobjFor(Open) asDobjFor(Unscrew)
    dobjFor(Unscrew) {
        verify() {}
        check() {
            if (unscrewed) "You have already unscrewed the fuel cap. ";
        }
        action() {
            unscrewed = true;
            unscrewedBefore = true;
            "You unscrew the fuel cap. ";
        }
    }
    dobjFor(Screw) {
        verify() {}
        check() {
            if ((!unscrewed) && (unscrewedBefore)) "You have already screwed the fuel cap back on. ";
            else if (!unscrewed) "You haven't unscrewed it. ";
        }
        action() {
            unscrewed = nil;
            "You screw the fuel cap back on. ";
        }
    }
    iobjFor(PourInto) {
        verify() {}
        check() {
            "Trying to pour something into the <i>cap</i> wouldn't make a lot of sense.
            If you want to pour something, try pouring it directly into the motor. ";
        }
    }
;

++ gearAssembly: Component 'gear assembly;; gears'
    "The gear assembly has two separate gears, one attached to the motor and the other
    attached to the geared shaft.<<if (!connected)>> Oddly, the two gears are not touching one another. It would seem
    that something or other ought to connect them.<<else>> A leather belt connects the two gears.<<end>> "
    connected = nil
    iobjFor(AttachTo) asIobjFor(PutOn)
    dobjFor(Connect) {
        verify() {}
        check() {
            if (connected) "You've already fixed the gear assembly. ";
            else "The question is how to do that. Perhaps with some other object. ";
        }
    }
    iobjFor(TieTo) asIobjFor(PutOn)
    iobjFor(PutOn) {
        verify() {}
        check() {
            if (connected) "You've already fixed the gear assembly. ";
            else if (gDobj != leatherBelt) "{That subj dobj} {is} not a good fit for the gears. ";
            else if (motor.running) "One of the gears is spinning rapidly. You'll need to
                switch off the motor before you try that. ";
        }
        action() {
            connected = true;
            // We're not going to attach it, we're just going to claim that it's attached.
            // It's actually just in the room, but that's where it will stay.
            leatherBelt.moveInto(goingToPot);
            leatherBelt.attached = true;
            // So it won't show up in room descriptions, I hope:
            leatherBelt.isFixed = true;
            "You wrap the belt around the gears and tighten it. Looks pretty good. ";
        }
    }
;

++ shaft: Component 'geared shaft'
    "The shaft connects to the underside of the wheel. There's a gear on the shaft, and another
    gear (close to it but not touching) on the motor. "
    iobjFor(PutOn) {
        verify() {}
        action() {
            doInstead(PutOn, gDobj, gearAssembly);
        }
    }
    dobjFor(Turn) {
        verify() {}
        check() {
            if (wheel.turning()) "The shaft is already rotating rapidly. ";
            else "The way to do that would be to get the wheel turning. Possibly starting the
            motor would be a useful step to take. And maybe something with the gear assembly? ";
        }
    }
;
    
//-----------------------------------------------------------------------------
// scootersPub
//-----------------------------------------------------------------------------

scootersPub: Shop 'Scooter\'s Irish Pub'
    "The dim interior of this friendly neighborhood pub is illuminated mainly by glowing neon
    signs advertising various types of liquid refreshment. The tables and chairs are entirely
    deserted, but the bartender is at his station. On the wall behind him is a collection of
    framed photographs of celebrities, most of them autographed.<<tSteve.makeFamiliar()>>
    
    <.p>The doorway back to the arcade is to the west, and another doorway, next to the bar,
    opens eastward. "
    
    out asExit(west)
    west = arcadeEast
    east = "<q>Sorry,</q> the bartender says. <q>The billiard room is closed right now.</q> "
;

+ Decoration 'glowing neon signs; liquid; sign assortment beverages refreshment'
    "The signs advertise an assortment of beverages. "
    plural = true
;
+ Decoration 'tables; deserted; chairs table chair'
    "The chairs and tables are about what you'd expect. "
    plural = true
;

+ photosGroup: CollectiveGroup
    collectiveActions = [Take, Examine]
    vocab = 'signed photos; autographed celebrity; celebrities collection'
    desc = "Various photos of celebrities are affixed to the wall. You spot
        movie stars (such as Godzilla), historical figures (a photo of Mount
        Rushmore), well-known scientists (such as physicist Albert Einstein
        and primatologist Jane Goodall), and TV stars (such as Homer Simpson). "
    myObjects = [einsteinPhoto, welkPhoto, goodallPhoto, rushmorePhoto, homerPhoto, godzillaPhoto]
    // myScopeObjects() { return [goodallPhoto, rushmorePhoto, homerPhoto, godzillaPhoto]; }
    dobjFor(Take) {
        verify() { logical; }
        check() {
            "The bartender says, <q>I guess you're pretty impressed by my celebrity photo collection.
            Every single one of them is autographed. You wouldn't believe the trouble I
            had to go to.</q> ";
        }
    }
;

+ wallBehindBar: Surface, Fixture 'wall behind[prep] the bar'
    "Hanging on the wall behind the bar is a collection of autographed photos. "
    photoTaken = nil
    checkReach(actor) {
        if (!steve.friendly)
            "The wall of photos is behind the bar, and so is the bartender. ";
        else if (photoTaken) 
            "<q>I can't just give you the whole collection,</q> the bartender
            says. <q>Sorry.</q> ";
    }
;
    

//-----------------------------------------------------------------------------
// billiardRoom
//-----------------------------------------------------------------------------

billiardRoom: Room 'Billiard Room'
    "The broad green expanse of a snooker table dominates this wood-paneled room. A cork
    dartboard is mounted on one wall. A doorway leads west, and there's an open window
    to the north. "
    
    west = "Considering how you got in here, maybe you shouldn't just waltz back out
        through the bar. "
    north = balconyWindowInside
    out asExit(north)
;

+ balconyWindowInside: Door 'balcony window'
    "The window is open, and an afternoon breeze flows through. "
    otherSide = balconyWindowOutside
    isOpen = true
    dobjFor(Close) {
        verify() {}
        check() {
            "There's no obvious way to do that, and probably no need. ";
        }
    }
;

+ snookerTable: Surface, Fixture 'snooker table; broad green; felt'
    "The snooker table looks well cared for. There don't seems to be any balls or
    cues; probably they're locked up somewhere. "
;
++ Decoration 'pockets; ; pocket'
    "The pockets are empty. "
    plural = true
    decorationActions = [Examine, LookIn, Search]
    dobjFor(LookIn) {
        verify() {}
        check() { "There\'s nothing in any of the pockets. ";
        }
    }
;

+ dartBoard: RestrictedContainer, Fixture 'dartboard; circular cork; design board target'
    "The dartboard has the usual circular design. "
    allowedContents = [featheredDart]
    iobjFor(ThrowAt) {
        verify() {}
        action() {
            if (gDobj != featheredDart) {
                "{The dobj} hits the dartboard, bounces off harmlessly, and
                lands on the floor. ";
                gDobj.moveInto(billiardRoom);
            }
            else {
                "The dart flies at the dartboard and attaches itself. ";
                featheredDart.moveInto(self);
            }
        }
    }
;

//-----------------------------------------------------------------------------
// rareBookShop
//-----------------------------------------------------------------------------

rareBookShop: Shop 'Inkwell Fine Print'
    "The musty odor of old books pervades this little shop. Shelves reaching from floor to ceiling
    are crammed with books --- and the word <q>crammed</q> describes the situation pretty well,
    as the books are not arrayed neatly. Some stacks are on the floor, in fact, and half-full
    cartons make the footing treacherous. The cartons and floor stacks are under foot pretty much everywhere, although
    there's a clear space in front of the shelves along the south wall.<<if (shelfDoor.isOpen)>> A tall
    shelf unit in the south wall has swung open, making it possible for you to proceed further
    south.<<end>>
    
    <.p>Gazing upon the chaos in a lordly manner is a rather large plaster bust of Shakespeare,
    which sits atop the counter. A sign affixed to the front of the counter says, <q>Rare First
    Editions While U Wait.</q> The door back to the arcade is to the north. "
    north = bookshopDoorInside
    south = shelfDoor
    out asExit(north)
;

+ bookshopDoorInside: ShopDoorInside
    otherSide = bookshopDoorOutside
;

+ Decoration 'first editions sign; edition'
    "The sign says, <q>Rare First Editions While U Wait.</q> There\'s something faintly suspect
    about this. You don\'t suppose they\'re printing up bogus rare books in a secret print shop
    nearby, do you? "
;

+ shelfDoor: SecretDoor 'door'
    "The shelf in the south wall has swung aside, allowing passage through to another room. "
    otherSide = shelfDoorInside
;

+ bookshelves: Fixture '(book) shelves; tall packed untidy; bookshelves; them'
    desc {
        "The packed, untidy bookshelves line the walls of the room. The floor in front of the center shelf
        unit on the south side of the room is marred with a semicircular scrape, or scar, which begins at
        one side of the shelf and curves outward. ";
        if (!secretBook.appeared) {
            secretBook.appeared = true;
            secretBook.moveInto(rareBookShop);
            "<.p>Oops! As you're idly fingering the books on the shelf, a slim leather-bound volume tumbles to the floor
            with a dusty thump. ";
        }
    }
;

+ centerSouthShelf: Fixture 'center shelf unit; (south)'
    "Like the other shelves, the center unit <<if (!shelfDoor.isOpen)>>standing
    against<<else>>that has swung out from<<end>> the south wall is packed with books. "
    dobjFor(LookBehind) {
        verify() {}
        check() {
            if (!shelfDoor.isOpen) "The shelf unit is flush with the wall. Looking behind
                it is not possible. ";
        }
        action() {
            "Behind the shelf unit is an entrance to another room. ";
        }
    }
;

+ curvingScrape: Fixture 'curving scrape; semicircular; scar'
    "The curving scrape extends outward across the floor from one side of the central bookshelf unit
    on the south side of the room. "
;

+ manyBooks: Decoration 'assorted books; teetering dusty jumbled; stack stacks (book); them'
    "The books are jammed into shelves and boxes and teetering in stacks across the floor. "
    notImportantMsg = 'The books are too numerous, too jumbled, and too dusty to be worth
        dallying over. '
;

+ shakespeareBust: Actor, Fixture 'bust of Shakespeare; plaster large detailed lifelike dignified william; statue carving will poet bard; it him'
    "The bust of Shakespeare is a detailed and lifelike carving. The Bard gazes out at the sea of books
    with imperturbable equanimity. "
    specialDesc = ""
    refuseCommandMsg = 'The bust of Shakespeare is an inanimate object. It can neither obey nor disobey. '
    cannotTakeMsg = 'The bust of Shakespeare is firmly affixed to the counter. '
    shouldNotKissMsg = 'Showering affection on men who are completely unresponsive? Don\'t you get enough of
            that at home? '
    shouldNotAttackMsg = 'Oh, come on. His plays weren\'t <i>that</i> bad. '
    dobjFor(Pull) asDobjFor(Feel)
    dobjFor(Feel) {
        check() {
            if (secretBook.appeared)
            "The bust of Shakespeare is cool and slightly rough to the touch. ";
        }
        action() {
            "As your fingers brush the bust of Shakespeare, there's a thump behind you. Turning, you
            find that a slim leather-bound volume has tumbled off of one of the shelves. ";
            secretBook.moveInto(rareBookShop);
            secretBook.appeared = true;
        }
    }
    dobjFor(Turn) asDobjFor (Take)
;

++ DefaultSayTellTalkTopic
    "The bust of Shakespeare shows no interest in conversing with you. Not surprising, really. "
;

++ DefaultGiveShowTopic
    "The bust of Shakespeare quite evidently has no interest in worldly things. "
;

++ DefaultAnyTopic
    "The bust of Shakespeare fails to respond. "
;

//-----------------------------------------------------------------------------
// printery
//-----------------------------------------------------------------------------

Doer 'go east'
    execAction(c) {
        printeryExitDoorInterior.makeLocked(nil);
        printeryExitDoorInterior.makeOpen(true);
        "You push the exit door open and pass through the doorway. Behind you, the
        door closes with a solid <i>thump.</i> ";
        doInstead(Go, eastDir);
        printeryExitDoorInterior.makeOpen(nil);
        printeryExitDoorInterior.makeLocked(true);
    }
    where = printery
;

Doer 'open printeryExitDoorInterior'
    execAction(c) {
        "You push the exit door open, but as soon as you let go of it, it closes again. ";
    }
    where = printery
;

printery: Room 'Secret Printery'
    desc {
        "This little room is rather untidy. Assorted printing equipment is assembled here,
        and scraps of paper litter the floor. ";
        
        if (longTable.contents.length >= 1) { "On the long table against the
            west wall you can see <<list of (longTable.contents)>>. ";
        }
        else "A long table stands against the west wall. ";
    
        "<.p>Squatting in the center of the room is a large and rather intimidating machine
        equipped with a projecting tray, a small video display, and a numeric keypad. 
    
        <.p>The open door is to the north. Above a businesslike door in the east wall
        is a green sign that says EXIT. ";
    }
    // You can't walk away with the cell phone attached to the cable -- but we'd like this
    // to print before the Doer's message prints, and that's a bit tricky, because if the
    // player exits back to the bookstore, we need something like this here!
    beforeTravel(t, c) {
        if (cellPhone.isIn(gPlayerChar) && cellPhone.attachedTo) {
            doNested(DetachFrom, cellPhone, idkCable);
            "(first detaching the cell phone from the cable)";
            }
    }
    
    out asExit(north)
    north = shelfDoorInside
    east = printeryExitDoorInterior
;

+ printeryExitDoorInterior: Door 'exit door'
    "It's a solid-looking door with a crash bar. "
    otherSide = printeryExitDoorExterior
    checkTravelBarriers(traveler) {
        if (traveler == redWagon) return nil;
        else return inherited(traveler);
    }
;

+ shelfDoorInside: SecretDoor 'shelf door'
    "The door is standing open. "
    otherSide = shelfDoor
    dobjFor(Close) {
        check() {
            "There seems to be no way to do that. ";
        }
    }
;

+ paperScraps: Decoration 'scraps of paper;;;them'
    "The scraps of paper are scattered here and there across the floor. "
;
+ printingEquipment: Decoration 'printing equipment'
    "Copiers, fax machines, the usual stuff. "
;

+ longTable: Surface, Fixture 'long table'
    "The long table sits against the west wall of the room. "
;

+ identikitMachine: Heavy 'IdentiKit machine; large intimidating; dispenser'
    "Engraved on the upper part of the machine is a logo that identifies it as an IdentiKit
    Dispenser. On one side is a projecting tray. Next to the tray is
    a small video display, below which is a numeric keypad. A short cable dangles from the
    machine near the display. On the other side of the display is a large lever, which looks
    rather like the lever for a slot machine. "
    cannotTakeMsg = 'It must weigh at least a ton. '
    // The keypad will evaluate the code and switch this property:
    codeCorrect {
        if (idkDisplay.codeEntered[1] != idkDisplay.correctCode[1]) return nil;
        if (idkDisplay.codeEntered[2] != idkDisplay.correctCode[2]) return nil;
        if (idkDisplay.codeEntered[3] != idkDisplay.correctCode[3]) return nil;
        if (idkDisplay.codeEntered[4] != idkDisplay.correctCode[4]) return nil;
        return true;
    }
    biancaFace = nil
    ajouFace = nil
    dobjFor(AttachTo) {
        verify() {}
        action() {
            doInstead(AttachTo, idkCable, gIobj);
        }
    }
    iobjFor(AttachTo) {
        verify() {}
        // action() { doInstead(AttachTo, gDobj, idkCable); }
    }
    leverPulled () {
        if (!junctionBox.isPowered || !codeCorrect()) { "You pull the lever, but nothing happens. "; return; }
        if (!biancaFace && !ajouFace) {
            "The machine beeps, and a message
            crawls across the video display. The message reads, <q>Insufficient Data. Photo input required.</q> ";
            return;
        }
        // Parameters to store whether or not we're ready to
        // deliver IdentiKits:
        local biancaReady = (biancaFace && !biancaIdentiKit.created);
        local ajouReady = (ajouFace && !ajouIdentiKit.created);
        if (biancaReady && ajouReady) {
            biancaIdentiKit.created = true;
            ajouIdentiKit.created = true;
            biancaIdentiKit.moveInto(idkTray);
            ajouIdentiKit.moveInto(idkTray);
            identikitAch.awardPointsOnce();
            "The machine hums briefly and makes a cheerful chiming noise. Two fat folders, one
            pink and one blue, fall into the projecting tray. ";
        }
        else if (biancaReady) {
            biancaIdentiKit.created = true;
            biancaIdentiKit.moveInto(idkTray);
            "The machine hums briefly and makes a cheerful chiming noise. A fat pink folder
            is extruded into the projecting tray. ";
        }
        else if (ajouReady) {
            ajouIdentiKit.created = true;
            ajouIdentiKit.moveInto(idkTray);
            "The machine hums briefly and makes a military chugging noise. A fat blue folder
            tumbles into the projecting tray. ";
        }
        // Else we know at least one face has been uploaded, so evidently the documents
        // have already been extruded:
        else "The machine beeps, and a message crawls across the video display. The message
            reads, <q>Documents already delivered.</q> ";
    }
;

++ idkLever: Component 'large lever'
    "The lever is attached to the machine. "
    dobjFor(Pull) {
        verify() {}
        check() {}
        action() {
            "Ka-chunk! ";
            identikitMachine.leverPulled();
        }
    }
;

++ idkKeypad: Component 'numeric keypad'
    "The keypad has buttons for numbers 0 through 9. "
;

class idkButton: Button 'button; square gray rubber rubbery'
    "The button is square, gray, and rubbery-looking. On it is the number <<num>>. "
    num = 0
    dobjFor(Push) {
        verify() {}
        check() {
            // no need to check for power here -- the idkDisplay will do that.
        }
        action() {
            idkDisplay.buttonPressed(num);
        }
    }
;

+++ idkZeroButton: idkButton '+; 0 zero'
    num = '0'
;
+++ idkOneButton: idkButton '+; 1 one'
    num = '1'
;
+++ idkTwoButton: idkButton '+; 2 two'
    num = '2'
;
+++ idkThreeButton: idkButton '+; 3 three'
    num = '3'
;
+++ idkFourButton: idkButton '+; 4 four'
    num = '4'
;
+++ idkFiveButton: idkButton '+; 5 five'
    num = '5'
;
+++ idkSixButton: idkButton '+; 6 six'
    num = '6'
;
+++ idkSevenButton: idkButton '+; 7 seven'
    num = '7'
;
+++ idkEightButton: idkButton '+; 8 eight'
    num = '8'
;
+++ idkNineButton: idkButton '+; 9 nine'
    num = '9'
;

++ idkDisplay: Component 'video display; small'
    "The display is about the size of a cell phone LCD.
    <<if (junctionBox.isPowered)>><<showDisplay()>><<else>>It's dark. <<end>>"
    showDisplay() {
        "The display now
        reads <<codeEntered[1]>><<codeEntered[2]>><<codeEntered[3]>><<codeEntered[4]>>. ";
    }
    correctCode = ['3', '8', '1', '5']
    codeEntered = ['-', '-', '-', '-']
    enterNumber (num) {
        codeEntered[1] = codeEntered[2];
        codeEntered[2] = codeEntered[3];
        codeEntered[3] = codeEntered[4];
        codeEntered[4] = num;
    }
    buttonPressed(num) {
        if (!junctionBox.isPowered) {
            "You press the button, but nothing happens. ";
            return;
        }
        enterNumber(num);
        showDisplay();
    }
;

++ idkTray: Surface, Component 'projecting tray'
    "The tray projects from one side of the IdentiKit machine. "
    iobjFor(PutIn) asIobjFor(PutOn)
;

// I think the way to deal with the cable/phone relation is to fake it.
// The phone will never actually be attached, in the sense that the library
// defines that relation; it will only tell the player that it's attached,
// and behave accordingly.
//
// All of the actions will be handled by the cellPhone object.

++ idkCable: Component 'short cable; metal beige; plug'
    "The cable is about two feet long, and beige. It has a metal plug on its free end;
    the other end is firmly attached to the machine. <<if (attachedToPhone)>>At the moment,
    your cell phone is dangling from the end of the cable. <<else>>The plug looks as if it
    might fit into the socket in the base of a cell phone. <<end>>"
    
    possiblyUpload() {
        if (!junctionBox.isPowered) return;
        local len = cellPhone.photoList.length;
        local someUpload = 0;
        // Let's find out if the photos of the lieutenand and the mannequin are in the list:
        for (local i = 1; i <= len; i++) {
            if ((cellPhone.photoList[i] == 'a wooden soldier') || 
                (cellPhone.photoList[i] == 'Lieutenant Ajou'))
            {
                identikitMachine.ajouFace = true;
                someUpload++;
            }
            else if ((cellPhone.photoList[i] == 'a mannequin') || 
                (cellPhone.photoList[i] == 'Bianca'))
            {
                identikitMachine.biancaFace = true;
                someUpload++;
            }
        }
        if (someUpload == 2) "The machine beeps twice. ";
        else if (someUpload == 1) "The machine beeps. ";
    }
    
    attachedToPhone = nil
    
    dobjFor(PlugInto) asDobjFor(AttachTo)
    iobjFor(PlugInto) asIobjFor(AttachTo)
    dobjFor(FastenTo) asDobjFor(AttachTo)
    iobjFor(FastenTo) asIobjFor(AttachTo)
    // attach cable to phone:
    dobjFor(AttachTo) {
        preCond = [touchObj]
        verify () { }
        check() {
            if ((gIobj != cellPhone) && (gIobj != phoneJack)) "You can't plug the cable into {the iobj}. ";
            else if (attachedToPhone) "The cable is already attached to the cell phone. ";
        }
        action() {
            cellPhone.attachToCable();
            possiblyUpload();
        }
    }
    // attach phone to cable:
    iobjFor(AttachTo) {
        preCond = [touchObj]
        verify() {}
        check() {
            if ((gDobj != cellPhone) && (gDobj != phoneJack)) "You can't attach {the dobj} to the cable. ";
            else if (attachedToPhone) "The cable is already attached to the cell phone. ";
        }
        // We'll let the phone handle the action, because it's the dobj.
    }
    dobjFor(Unfasten) asDobjFor(Detach)
    dobjFor(Unplug) asDobjFor(Detach)
    dobjFor(Detach) {
        preCond = [touchObj]
        verify() {}
        check() {
            if (!attachedToPhone) "The free end of the cable isn't attached to anything. ";
        }
        action() {
            doInstead (DetachFrom, idkCable, cellPhone);
        }
    }
    dobjFor(Remove) {
        verify() {}
        check() {
            if (!attachedToPhone) "You give the cable a tug, but it seems to be
                permanently attached to the machine. ";
        }
        action() { doInstead (DetachFrom, idkCable, cellPhone); }
    }
    dobjFor(UnfastenFrom) asDobjFor(DetachFrom)
    dobjFor(UnplugFrom) asDobjFor(DetachFrom)
    iobjFor(UnfastenFrom) asIobjFor(DetachFrom)
    iobjFor(UnplugFrom) asIobjFor(DetachFrom)
    dobjFor(TakeFrom) asDobjFor(DetachFrom)
    iobjFor(TakeFrom) asIobjFor(DetachFrom)
    dobjFor(DetachFrom) {
        preCond = [touchObj]
        verify() {}
        check() {
            if (gIobj == identikitMachine) "The cable seems to be permanently attached to the machine. ";
            else if (gIobj != cellPhone) "The cable isn't attached to {the dobj}. ";
            else if (!attachedToPhone) "The cable isn't attached to the cell phone. ";
        }
        action() {
            cellPhone.detachFromCable();
        }
    }
    iobjFor(DetachFrom) {
        preCond = [touchObj]
        verify() {}
        check() {
            if (gDobj == identikitMachine) "The cable seems to be permanently attached to the machine. ";
            else if (gDobj != cellPhone) "{The dobj} {is} not attached to the cable. ";
            else if (!attachedToPhone) "The cable isn't attached to the cell phone. ";
        }
        // We'll let the phone handle the action, because it's the dobj.
    }
;

//-----------------------------------------------------------------------------
// seeressLair
//-----------------------------------------------------------------------------

seeressLair: Shop 'The Lair of the Fortune Teller'
    "Purple draperies stitched with golden astrological symbols festoon this tiny shop.
    On a shelf along one wall is a collection of marionettes, some small and some rather
    large, which stare here and there at random in a wooden, unmoving way. The air is redolent with the
    smoky, spicy odor of --- well, let's call it incense.
    It's a familiar smell, but not one that you've encountered since a couple of memorable
    parties years ago in college, let's put it that way.
    
    <.p>The door back to the arcade is on the north side of the room. "
    
    out asExit(north)
    north = arcadeCenter
    northwest asExit(north)
;

+ ralphGhost: Unthing 'ghost ralph; sir; traveler author'
    'There seem to be no ghosts in the vicinity. '
    alreadySummoned = nil
    decorationActions = [Summon]
    responseGiven = nil
    dobjFor(Summon) {
        verify() {}
        check() {
            
        }
        action() {
            responseGiven = true;
            if (!madameB.cardsReceived)
                "<q>I'd like to help you, dear,</q> she says, <q>but I can't do
                anything like that without my wonderful Tarot cards.</q> ";
            else if (!alreadySummoned) {
                alreadySummoned = true;
                "<q>Yes, let's try it,</q> the seeress says. She lays out a few cards,
                makes a magical pass over them with her hands while mumbling a few words
                in a language  you don't know --- and suddenly the ghost of Sir Ralph
                himself is hovering in the middle of the room.<.p>He looks a bit peeved at
                being interrupted, but says, <q>Hello, Gloria. How nice to see you.</q>
                <.p><q>This young lady was inquiring about your book,</q> she says.<.p>
                <q>Ah, yes. All of my travels are detailed there. I customarily used a
                teleporting device --- so much faster and more convenient than chartering
                a private helicopter. One expedition in particular comes to mind. It's
                described in detail on page 327 of my book. Perhaps you recall it. Deep
                in the jungle, I encountered a hostile ocelot. A little further on, an
                enormous statue of a seated Buddha captured my attention....</q> He goes
                on in this vein for quite some time.<.p>At length, the seeress makes another
                magical gesture over the cards, and the ghost dissolves, slowly, his mouth
                still moving though you can no longer hear him. <q>I do love Sir Ralph
                dearly,</q> the seeress says, <q>but he <i>can</i> be a bit long-winded.</q> ";
            }
            else "<q>But he's a tedious old bore,</q> she replies. <q>He did mention that
                adventure on page 327 of his book. Wasn't that the information you were
                seeking?</q> ";
        }
    }
;

+ Decoration 'draperies; golden astrological; symbols'
    "The draperies lend the room an air of exotic elegance. "
;

+ lairTable: Surface, Fixture 'cloth-covered table; square'
    "The table is square, and is covered by a satiny cloth with a swirling paisley pattern
    of yellow and purple. Sitting at the fortune teller's elbow is a handsome china
    teapot, which is flanked by a pair of teacups. "
;

++ Decoration 'teapot; lovely handsome china'
    "The teapot is quite lovely. "
;
++ Decoration 'pair of teacups'
    "The teacups match the teapot. "
;
++ Decoration 'satin cloth; satiny swirling paisley yellow purple; pattern'
    "The satin cloth covers the fortune teller's table. "
;

+ lairShelf: Surface, Fixture 'shelf'
    "The shelf runs along one wall. "
    notifyInsert (obj) {
        "The shelf is already quite cluttered. ";
        exit;
    }
;

++ marionettes: Fixture 'painted marionettes; wooden; puppets; them'
    "The painted wooden marionettes are strewn, not very neatly, along the shelf.
    Some are sitting up, some are slumped against one another or even lying face-down. 
    Black strings are attached to their limbs. "
    cannotTakeMsg = 'It\'s not likely {the madame} would be happy to see you grab
        one of her marionettes. '
;

+++ marionetteStrings: Component 'strings; black dark tangled; threads; them'
    "The black strings are attached to the marionettes' limbs, and droop everywhere in
    a tangle. "
    cannotTakeMsg = 'Detaching bits of string from the marionettes would be time-consuming,
        and would surely earn the enmity of {the madame}. '
;
