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

class ShopliftingTag: Fixture 'magnetic anti-shoplifting tag; (on) (dress) (gown) (hem) shoplifting'
    "The tag is firmly clipped to the hem of the gown. "
    cannotTakeMsg = 'There seems to be no way to remove it from the dress. '
;

brokenCombBowl: Immovable 'broken bowl; glass brandy (comb); shards snifter'
    "There's nothing left of the bowl but some glass shards. "
    cannotTakeMsg = 'You have no pressing need for a bunch of broken glass. '
    cannotMoveMsg = 'You nudge the glass shards with your toe, accomplishing nothing. '
    dobjFor(Break) {
        verify() {}
        check() {
            "It's already broken. ";
        }
    }
;

spilledCombs: Fixture 'plastic combs; spilled scattered brightly colored;; them'
    "The hair combs are scattered across the floor. "
    cannotTakeMsg = 'The combs are not the sort of thing you yourself would ever wear,
                and Samantha has decreed them <q><i>so</i> last year.</q> '
;
     
//-----------------------------------------------------------------------------
// hotRags
//-----------------------------------------------------------------------------

hotRags: Shop, StopEventList 'Fashion Boutique'
    "Among the racks of brightly colored, attractive clothing stand more than a few mannequins in stiff, stylized
    poses. A large glass display case stands against one wall, and a modern computerized cash
    register sits on one end of a long counter.
    <p>The shop door is to the south.
    To the east is an open passageway above which is a sign that says <q>Dressing Rooms.</q> "
    
    // You just plain won't be able to leave the room with the prom dress, no matter which
    // direction you're going.
    regions = [joeFollowingRegion]
    beforeTravel(traveler, connector) {
        if ((traveler == gPlayerChar) && (promDress.isIn(gPlayerChar)))
        {
            biancaArrival();
            abort;
        }
    }
    biancaArrival() {
        promDress.moveInto(bianca);
        inanimateBianca.moveInto(nil);
        combBowl.moveInto(nil);
        brokenCombBowl.moveInto(hotRags);
        spilledCombs.moveInto(hotRags);
        roundKey.moveInto(hotRags);
        inanimateBianca.seen = nil;
        gPlayerChar.setHasSeen(bianca);
        "You scan the bar code on the dress, feed your credit card through the
        machine, snip off the bar code, and head for the door. Mission accomplished!
        <.p>Your feeling of triumph is short-lived, however. As you head toward the
        door, a slim white hand reaches over your shoulder
        and snatches the dress! You whirl around, and your jaw drops in
        astonishment. Clutching the prom dress tight to its --- or perhaps we
        should say <q>her</q> --- barely perceptible bosom is a mannequin.<.p>
        <q>You can\'t have it,</q> she proclaims in a thin and rather strident
        voice. <q>I was wearing it until this morning, and I like it! It\'s mine!</q>
        The mannequin glares at you with a haughty and simmering contempt.<.p>
        
        <q>Excuse me,</q> you manage to choke out. <q>What makes you think---</q><.p>
        
        <q>You wouldn\'t understand,</q> she snaps. <q>You're a real person. You
        couldn't possibly understand what it's like not to be real!</q><.p>
        
        You try to grab the dress away from her, but without tearing it. In the
        tussle, a bowl of combs is knocked off the counter and falls to the floor
        with a complicated clatter.<.p>
        
        The mannequin darts away from you. As you watch in dismay, she shimmies out
        of the skimpy teddy she was wearing (and no, there\'s nothing to speak of under a mannequin\'s
        clothing, not that you ever gave the question much thought), pulls the prom dress
        down over her head, zips up the back, and adjusts the straps.
        <q>There, now,</q> she says, fluffing and
        shaking out her hair. <q>That\'s more like it. Now I'm going to go look at myself.</q><.p>
        
        The mannequin strides across the room and plunges through the door of the
        dressing rooms. She's gone --- and so is the only possible prom dress! ";
        bianca.startPhantomBiancaDaemon();
    }
    
    // An atmospheric message generator that will mention the moving mannequin:
    doScript { if (!inanimateBianca.isIn(hotRags)) return; else inherited; }
        
    eventList = [
            nil,
            nil,
            '<.p>That\'s odd. That mannequin was over across the room, you\'re pretty sure, but when you
            turn around she\'s practically at your heels. ',
            nil,    
            nil,
            '<.p>As you move around the shop, you can\'t escape the uneasy feeling that that one
            mannequin is following you. She\'s not moving, at least not while you\'re looking
            at her --- but still, every time you turn
            your back and then turn to look at her again, she seems to be a little closer than
            before. ',
            nil,
            'There\'s that restless mannequin again, almost at your elbow. ',
            nil,
            nil,
            'This is getting silly. Mannequins can\'t actually <i>move</i> ... can they? ',
            nil
        ]   
    south = hotRagsDoorInside
    east = mazeEntrance
;

+ hotRagsDoorInside: ShopDoorInside '+;(fashion) (boutique)'
    otherSide = hotRagsDoorOutside
;

+ shopliftDetectors: Fixture 'shoplifting detectors; beige bulky;; them'
    "The shoplifting detectors flank the door. They're an attractive beige, but rather bulky. "
;

+ boutiqueMirrors: Fixture 'mirrors; cold;; them'
    "The mirrors glitter coldly. "
    dobjFor(LookIn) {
        verify() {}
        check() {}
        action() {
            "You look pretty much the way you did an hour ago. ";
        }
    }
    dobjFor(Search) {
        verify() { illogical ('The mirrors can\'t contain things. At least, you hope not. '); }
    }
;

+ boutiqueCounter: Surface, Fixture 'long counter'
    "The counter itself is unremarkable. A computerized cash register sits on
    it<<combBowl.isIn(boutiqueCounter) ? ', and next to the cash register sits a
        very large glass bowl full of hair combs' : ''>>. "
    contentsListed = nil
    contentsListedInExamine = nil
;

++ cashRegister: Decoration 'cash register; modern sleek; device'
    "The cash register is a modern, sleek device. "
;

++ combBowl: Immovable, Container 'large bowl; brandy (comb); snifter'
    "The bowl is transparent. It\'s the size and shape of a large brandy
    snifter. It\'s chock-full of colorful plastic hair combs. "
    contentsListedInExamine = nil
    cannotTakeMsg = 'You have no pressing need for a bowl containing dozens of plastic
        hair combs. '
    cannotMoveMsg = 'You jiggle the bowl experimentally, and it produces a clicky rattling noise. '
    notifyInsert (obj) {
        "The bowl is full to the brim with combs. There's no room for anything
        else. ";
        exit;
    }
    dobjFor(LookIn) {
        action () {
            "There must be hundreds of combs in the bowl. If there\'s anything
            else in there, you\'re never going to find it. ";
        }
    }
    dobjFor(Break) {
        verify() {}
        check() {
            "But then there would be combs all over the floor, and it would
            take you half an hour to pick them all up. To say nothing of the broken
            glass. ";
        }
    }
;

+++ plasticCombs: Fixture 'plastic combs; brightly colored;; them'
    "The bowl is jam-packed with large combs, in every color of the rainbow. "
    cannotTakeMsg = 'The combs are not the sort of thing you yourself would ever wear,
                and Samantha has decreed them <q><i>so</i> last year.</q> '
    dobjFor(LookIn) {
        verify() {}
        check() {}
        action() { doInstead (Search, combBowl); }
    }
;
 
+ glassCabinet: LockableContainer, Fixture 'glass display cabinet;; case'
    "The glass cabinet stands proudly against one wall. Within it, on display,
    are innumerable sensuous and dignified bottles, vials, and
    jars.<<if (eauBottle.isIn(self))>> One big square bottle in
    particular catches your eye. Its label proclaims it <q>l\'eau d\'ennui.</q><<end>> "
    contentsListed = nil
    contentsListedInExamine = nil
    // examineStatus = nil
    isLocked = true
    dobjFor(UnlockWith) {
        verify() {}
        check() {
            if (!isLocked) "The glass cabinet isn\'t locked. ";
            else if (gIobj && (gIobj != roundKey)) "That doesn\'t seem to fit the lock. ";
        }
        action() {
            makeLocked(nil);
            "You unlock the glass cabinet. ";
        }
    }
    dobjFor(Unlock) {
        verify() {}
        check() {
            if (!isLocked) "The cabinet isn\'t locked. ";
            else if (!roundKey.isDirectlyIn(me)) "You don\'t seem to be holding the right key. ";
        }
        action() {
            makeLocked(nil);
            "You unlock the glass cabinet. ";
        }
    }
    isTransparent = true
    reachBlockedMsg(target)
    {
        local obj = self;
        gMessageParams(obj);
        gMessageParams(target);
        return  BMsg(cannot reach, '{I} {can\'t} reach {the target} through
            the glass door of {the obj}. ');
    }
;

++ perfumeBottles: Decoration
    'cologne bottles; fragrance perfume scent attractive contoured; shapes shape vials jars vial jar; them'
    "The bottles have attractive contoured shapes and bold colors. Someone has arranged them by
    color, in a pattern that alternates orange, green, red, and violet. "
    notImportantMsg = 'As a class, the bottles of cologne are not worth hesitating
        over.<<if (eauBottle.isIn(glassCabinet))>> That big square bottle labeled <q>Eau
        d\'ennui</q> looks interesting, though.<<end>> '
;

+ mannequins: Fixture
    'mannequins; motionless (slim) elegantly poised stylishly attired; mannequin dummies figures; them'
    "The mannequins are slim, elegantly poised, stylishly attired, and entirely motionless.
    The latter fact oughtn\'t to be surprising.... "
    cannotMoveMsg = 'If you push them, they\'ll fall right over. '
    cannotTakeMsg = 'At the moment you have no pressing need for a life-size dummy. '
    cannotPutMsg {return cannotTakeMsg; }
;

+ clothesRacks: Fixture, Surface
    'clothes racks; brightly colored attractive; rack dress clothing dresses garments; them'
    "Racks of brightly colored garments crowd the sales area.<<if (!promDress.moved)>> If the
    prom dress is anywhere around here, you\'re bound to be able to find it by searching the
    racks.<<end>> "
    cannotTakeMsg = 'You have no pressing need for an entire rack of dresses. You only need
        one particular dress. (You might try searching the racks for it.) '
    cannotMoveMsg = 'You try giving one of the racks a shove, but it isn\'t on wheels.
        It doesn\'t move. '
    // validContents = []
    dobjFor(PutOn) {
        verify() {}
        check() {
            "The racks are pretty full already. ";
        }
    }
    dobjFor(Search) asDobjFor(LookIn)
    dobjFor(LookIn) {
        verify() { logical; }
        check() {
            if (inanimateBianca.isIn(nil)) "You paw through the racks for another minute, hoping against hope ---
                but no, the sales clerk you spoke with on the phone was quite clear: There was only the one
                left in a size 8 in teal. And now that fiendish mannequin has run off with it! ";
        }
        
        action() {
            promDress.moveInto(me);
            promDress.moved = true;
            "It takes less than a minute to locate the dress you're seeking. There it is! You
            draw it out and hold it up to make sure. Teal satin, spaghetti straps, a white ruffle
            at the hem --- and it\'s size 8. Samantha\'s entire life (to hear her tell it) won\'t
            be ruined after all. ";          
        }
    }
;

//-----------------------------------------------------------------------------
// mazeEntrance
//-----------------------------------------------------------------------------

mazeEntrance: Room 'Entrance to the Dressing Rooms'
    "Floor-to-ceiling mirrors set at cunning angles give this cramped little room an oddly self-referential
    air. Exits lead off in several directions, but the mirrors make it difficult to tell exactly <i>which</i>
    directions. You feel a bit nervous about accidentally walking into a mirror, in fact. The route back
    to the fashion boutique is to the west, you're fairly sure of that, at least. "
    regions = [joeFollowingRegion]
    west = hotRags
    east = mR1
    north = mR3
    northeast = mR2
    southeast = mR2
    south = mR4
    southwest = mR7
    northwest = mR4
;

+ Decoration 'mirrors; floor-to-ceiling; mirror'
    "You admire yourself momentarily in the mirrors. "
    plural = true
;

//------------------------------------------------------------------------------
// The mirror maze
//------------------------------------------------------------------------------

mazeMirrors: MultiLoc, Decoration 'mirrors; ; mirror reflection reflections'
    "In the mirrors, you can see yourself from several different angles. "
    locationList = [mR1, mR2, mR3, mR4, mR5, mR6, mR7, mR8, mR9, behindCaboosePanel]
    plural = true
;

/*
    This may be a modestly interesting maze. It's mostly lawful, but four or five
    of the exits are randomized. As a result, you can map it in the canonical way,
    as long as you don't use any of those exits. At the moment you'll read the
    "disoriented" message when travel becomes random. That's probably a friendly
    thing to do, but possibly the testers will have other thoughts about it.
    From the Entrance to the Dressing Rooms, go e, e, se, ne to reach the alcove.
    From the alcove, go sw, s to get back to the Entrance.
*/

class mirrorRoom: Room
    roomTitle = 'Mirrored Dressing Room'
    desc = "Floor-to-ceiling mirrors set at cunning angles give this cramped little room an oddly self-referential
    air. Exits lead off in several directions, but the mirrors make it difficult to tell exactly <i>which</i>
        directions. "
    num = 0
    roomList = [mR1, mR2, mR3, mR4, mR5, mR6, mR7, mR8, mR9]
;

class RandTravel: TravelConnector
    destination {
        local L = me.getOutermostRoom.roomList;
        local R = rand(4) + 1;
        return L[R];
    }
    travelDesc = "For a moment you feel slightly disoriented. "
;

mR1: mirrorRoom
    num = 1
    east = mR2
    northeast = mazeEntrance
    north = mR7
    northwest = mR2
    west = mR6
    southwest = mR3
    south = RandTravel
    southeast = mR8 
;
mR2: mirrorRoom
    num = 2
    east = mR4
    northeast = mR6
    north = mR1
    northwest = mR6
    west = mR2
    southwest = mR3
    south = mazeEntrance
    southeast = mR9
    
;
mR3: mirrorRoom
    num = 3
    east = mR9
    northeast = mR1
    north = mR3
    northwest = mR5
    west = mR3
    southwest = RandTravel
    south = mR2
    southeast = mR7
;
mR4: mirrorRoom
    num = 4
    east = mR6
    northeast = mR2
    north = mR8
    northwest = mR8
    west = mR4
    southwest = machineRoom
    south = mR3
    southeast = mR2
;
mR5: mirrorRoom
    num = 5
    east = mR5
    northeast = RandTravel
    north = mR4
    northwest = mR9
    west = mR3
    southwest = mR5
    south = mR9
    southeast = mazeEntrance
;
mR6: mirrorRoom
    num = 6
    east = mR5
    northeast = mR9
    north = mR7
    northwest = mR6
    west = hatchRoom
    southwest = mR3
    south = mR6
    southeast = RandTravel
;
mR7: mirrorRoom
    num = 7
    east = mR7
    northeast = mR4
    north = mR6
    northwest = mR7
    west = mR1
    southwest = mR2
    south = RandTravel
    southeast = mR1
;
mR8: mirrorRoom
    num = 8
    east = mR4
    northeast = mR3
    north = mR7
    northwest = mazeEntrance
    west = mR9
    southwest = mR8
    south = mR1
    southeast = mR5
;
mR9: mirrorRoom
    num = 9
    east = mR3
    northeast = behindCaboosePanel
    north = mR9
    northwest = mR4
    west = mR8
    southwest = mR9
    south = mR2
    southeast = mR7
;

behindCaboosePanel: Room 'A Mirrored Alcove'
    "This sheltered alcove is bordered by entrances to little rooms with mirrors
    on the west, northwest, and southwest. To the east is a wooden panel. "
    regions = [joeFollowingRegion]
    west = mR3
    northwest = mR6
    southwest = mR2
    east = caboosePanelMirrorSide
;

+ caboosePanelMirrorSide: Door 'wooden panel'
    "The wooden panel is about the size and shape of a door. "
    isOpen = nil
    hasBeenOpened = nil
    otherSide = caboosePanelCabooseSide
    makeOpen(stat) {
        hasBeenOpened = true;
        if (caboosePanelCabooseSide.isIn(nil))
            caboosePanelCabooseSide.moveInto(chartreuseCaboose);
        inherited(stat);
    }
;

Doer 'undo'
    execAction(c) {
        "Nope --- you can't undo an action here. (You didn't take the
        warning seriously, did you?) ";
        abort;
    }
    where = machineRoom
;

machineRoom: Room 'A Mirrored Alcove'
    "This sheltered alcove is bordered by mirrors on every side. 
    A large machine stands here. "
    west = mR8
    northwest = mR3
    north = mR1
    northeast = mR6
    east = mR6
    southeast = mR9
    south = mR7
    southwest = mR4
;

+ banditMachine: Fixture 'large gray machine; bandit'
    "The machine, if that's what it is, is slightly smaller than a refrigerator. It's
    gray. There's a lever on the front, and also a plaque. The plaque reads, <q>Danger!
    Under no circumstances should you pull this lever! You have been warned!</q> "
;
++ banditPlaque: Component 'plaque;; message'
    "The message of the plaque is very clear: <q>Danger!
    Under no circumstances should you pull this lever! You have been warned!</q> "
    readDesc { return desc; }
;
++ banditLever: Component 'lever'
    "The lever is mounted vertically in the machine, next to the plaque. "
    dobjFor(Pull) {
        verify() {}
        action() {
            "The machine makes a loud groaning noise, in the midst of which a
            mournful, echoing voice says, <q>You <i>were</i> warned.</q> ";
            addToScore(-20, 'pulling a lever when advised not to');
        }
    }
;

hatchRoom: Room 'A Mirrored Alcove'
    "This sheltered alcove is bordered by mirrors on every side except the
    west. To the west is a low hatch. "
    west = hatch
//    : TravelConnector {
//        travelBarriers = [wagonBarrier]
//        destination = hatch
//    }
    northwest = mR3
    north = mR1
    northeast = mR6
    east = mR6
    southeast = mR9
    south = mR7
    southwest = mR4
;

+ hatch: Door 'low hatch; slanted; tunnel'
    "The hatch is set in the west wall, down near the floor. <<if isOpen>>Peering
    through it, you can see a slanted tunnel extending downward. "
    isOpen = nil
    isOpenable = true
    destination = ancientCrypt
    otherSide = ceilingTunnel
    canTravelerPass(t) {
        if (rope.isIn(t)) return nil;
        return true;
    }
    explainTravelBarrier(t) {
        "For some reason the hatch seems to be stuck. ";
    }
    travelDesc = "You plummet down a narrow chute, which ejects you with a thump
        on the floor of... "
;
    
    