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

/*
 *   Notes on the Octagonal Room:
 *
 *   The room travels up and down to five levels: roof, 2nd floor, 1st floor,
 *   lower floor, and sub-basement. Its possible exits are as follows. On the
 *   roof level, southeast to the narrow ledge. On the 2nd
 *   floor, to Upper Promenade East (sw), the balcony (n), and the Secluded Lair
 *   (se). On the 1st floor, to the alcove behind the stairs (w), the garden (e), and
 *   the file room (s). On the lower floor, to the cloak room (se). In the
 *   sub-basement, to the jewel-encrusted grotto (nw).
 *
 *   The white lever causes it to rise one floor. The black lever causes it to
 *   fall one floor. The buttons arm it for subsequent rotation during its rise
 *   or fall: The red button arms the room for a 1/8 clockwise turn, the green
 *   button for a 1/4 counter-clockwise turn.
 *
 *   Initially the ivy door is pointing sw and the rose door e.
 
 grottoArch (nw)
 
 cloakRoomArch (se)
 
 behindStairsArch (w)
 fileRoomArch (s)
 gardenArch (e)
 
 secludedArch (se)
 balconyArch (n)
 promenadeEastArch (sw)

 narrowLedgeArch (se)
 
 */

//////////////////////////////////////////////////////////////////////////////////////
// First, modify the exit listers for the Octagonal Room:
//////////////////////////////////////////////////////////////////////////////////////

modify exitLister
    showExitsCommand()
    {
        if (gPlayerChar.getOutermostRoom == octagonalRoom)
            "In this room the compass directions are more than a bit confused. To exit,
            you can go through the rose door or the ivy door. ";
        else inherited();
    }
;

modify ExitLister
    showListAll(lst, options, indent)
    {
        if (gPlayerChar.getOutermostRoom == octagonalRoom)
            lst = [ivyDoor, roseDoor];
        local cnt = lst.length;
        
        if(cnt == 0)
        {
            showListEmpty(nil, nil);
            return;
        }
        
        showListPrefixWide(1, nil, nil);
        
        for(local obj in lst, local i = 1 ; ; ++i)
        {
            showListItem(obj, nil, nil, nil);
            showListSeparator(nil, i, cnt);
           
        }
        
        showListSuffixWide(cnt, nil, nil);
        
    }
    
    listerShowsDest = nil
    
    exitsPrefix = BMsg(exits, 'Exits:');
;

modify statuslineExitLister
    showListItem(obj, options, pov, infoTab)
    {
        if (gPlayerChar.getOutermostRoom == octagonalRoom) {
                htmlSay('<FONT COLOR="<<unvisitedExitColour>>">');
            "<<aHref('go ' + obj.name, obj.name, 'Go ' + obj.name,
                     AHREF_Plain)>>";
            if(highlightUnvisitedExits)
                htmlSay('</FONT>');
        }
        else {
            if(highlightUnvisitedExits && (obj.dest_ == nil || !obj.dest_.seen))
                htmlSay('<FONT COLOR="<<unvisitedExitColour>>">');
            "<<aHref(obj.dir_.name, obj.dir_.name, 'Go ' + obj.dir_.name,
                     AHREF_Plain)>>";
            if(highlightUnvisitedExits && (obj.dest_ == nil || !obj.dest_.seen))
                htmlSay('</FONT>');
        }
    }
;

modify explicitExitLister
    showListPrefixWide(cnt, pov, parent)
    {
        if (gPlayerChar.getOutermostRoom == octagonalRoom) 
            DMsg(exits from here, 'From {here} {i} could go through the ');
        else
            DMsg(exits from here, 'From {here} {i} could go ');
    }
        showListItem(obj, options, pov, infoTab)
    {
        if (gPlayerChar.getOutermostRoom == octagonalRoom) {
            htmlSay('<FONT COLOR=#00A030><b><<aHref('go ' + obj.name, obj.name, 'Go through ' + obj.name,
                 AHREF_Plain)>></b></FONT>');
        }
        else
      htmlSay('<FONT COLOR=#00A030><b><<aHref(obj.dir_.name, obj.dir_.name, 'Go ' + obj.dir_.name,
                 AHREF_Plain)>></b></FONT>');
        
    }
;

//---------------------------------------------------------------------------
// Classes for the portals:
//---------------------------------------------------------------------------

class OctDoor: Fixture 'door;; portal arch archway exit'
    desc = "The doorframe of the <<plant>> door is of the same gray stonework as the surrounding walls. In
        the semicircular area above the lintel is carved a <<if (plant == 'ivy')>>twining ivy vine<<else>>rose blossom<<end>>.
        <<if blocked>>The doorway is
        blocked by a darker, much-scarred stone wall which is recessed behind the doorsill. <<else>>The
        doorway is open. <<end>>"
    destination() {
        if (blocked) return nil;
        return trueDestination;
    }
    blocked = true
    plant = 'ivy'
    trueDestination = upperPromenadeEast
    // Trying something that may not work:
    iobjFor(PushTravelDir) asIobjFor(PushTravelThrough)
    iobjFor(PushTravelThrough) {
        verify() {}
        check() {
            if (gDobj != redWagon)
                "You can't push that through the door. ";
        }
        action() {
            // doInstead(GoThrough, self);
        }
    }
    pullingTheWagon = nil
    wagonMover() {
        pullingTheWagon = true;
        nestedAction(GoThrough, self);
    }
    dobjFor(Enter) asDobjFor(GoThrough)
    dobjFor(GetOutOf) asDobjFor(GoThrough)
    dobjFor(GoThrough) {
        verify() {}
        check() {
            if (blocked) "Alas, the <<plant>> door is blocked by a sheet of gray stone. ";
            if (trueDestination == fileRoom) {
                if (fileRoom.blockedByStuffy) "Stepping through the door, you find that
                    the room you've entered is unbearably stuffy, as if it hasn't been
                    aired out in years. You retreat swiftly. ";
                else if (fileRoom.blockedByBlizzard) "As you approach the door, you can
                    see that the space beyond it is a blizzard of flying paper from floor
                    to ceiling. Plunging into the blizzard is likely to be a very bad idea. ";
            }
        }
        action() {
            if (pullingTheWagon) {
                if (trueDestination == grotto) {
                    "The floor of the room beyond the arch is too uneven for
                    the wagon to roll across it. ";
                    pullingTheWagon = nil;
                    exit;
                }
                else {
                    redWagon.moveInto(trueDestination);
                    "You pull the little red wagon through the doorway.\b";
                    gPlayerChar.moveInto(trueDestination);
                    trueDestination.lookAroundWithin();
                    pullingTheWagon = nil;
                }
            }
            else {
                gPlayerChar.moveInto(trueDestination);
                trueDestination.lookAroundWithin();
                pullingTheWagon = nil;
            }
        }
    }
    dobjFor (Open) {
        verify() {}
        check() {
            if (blocked) "The method by which you would do that is not immediately obvious. ";
            else "The door is already open. ";
        }
    }
    dobjFor (Close) {
        verify() {}
        check() {
            if (blocked) "Passage through the doorway is already impeded quite materially by a wall of
                dark gray stone. ";
            else "The method by which you would do that is not immediately obvious. ";
        }
    }
;

class OctagonExteriorPassage: Passage 
    vocab = 'arch; gray arched stone; sheet door doorway archway'
    desc = "The archway is surmounted by a nondescript stone carving
    that could depict vegetation --- or something else entirely. <<if blocked>>At the
    moment, passage through the arch is blocked by a sheet of gray stone. "
    blocked = nil
    destination = octagonalRoom
    dobjFor(GoThrough) {
        verify() {}
        check() {
            if (blocked) say (cannotPassMsg);
        }
    }
    cannotPassMsg = 'The archway is blocked by a sheet of gray stone. '
    canTravelerPass(t) { return !blocked; }
    explainTravelBarrier(t) {
        say (cannotPassMsg);
    }
;

// Allow the command 'go ivy door' to invoke GoThrough ivyDoor:

modify VerbRule(GoThrough)
    ('walk' | 'go' ) ('through' | 'thru' | )
        singleDobj
    : ;

//////////////////////////////////////////////////////////////////////////////////////
// And now, the Octagonal Room itself:
//////////////////////////////////////////////////////////////////////////////////////

octagonalRoom: Room 'Octagonal Room'
    "Though devoid of furnishings, this room has been carefully maintained. The inlaid
    wood floor is especially handsome, and the walls, also paneled in wood, are varnished
    to a warm gloss. Speaking of the walls, there are eight of them, all equal in length,
    making the room a perfect octagon.<<tOctagonalRoom.makeFamiliar()>>

    <.p>Two of the walls feature doorways, and these are set not opposite nor adjacent
    to one another but at an oblique angle, with two blank wall segments between them.
    Above one doorway, a twining ivy vine is carved into the stonework; the other
    features a carved rose blossom. The rose door is to the left of the ivy door;
    that is, if you orient to the rose door and then turn clockwise by 135 degrees,
    you'll be facing the ivy door.
    
    At present, the ivy door is << ivyDoor.blocked ? 'blocked' : 'open'>>
    and the rose door is
    <<(roseDoor.blocked && ivyDoor.blocked) ? 'also ' : ''>><<roseDoor.blocked ? 'blocked' : 'open'>>.

    <.p>In the center of the room is <<one of>>an interesting-looking<<or>>a<<stopping>> pedestal
    with some levers protruding from the top. "
    
    currentLevel = 4
    rotation = 1
    floorObj = inlaidFloor
    
    summon() {
        if (!junctionBox.isPowered) {
            "You pull the lever, but nothing happens. ";
            return;
        }
        if ((currentLevel == 4) && (rotation == 1)) {
            "Other than making a little <i>thunk,</i> the lever does nothing. ";
            return;
        }
        currentLevel = 4;
        rotation = 1;
        closeAllEntrances();
        adjustRoseDoor();
        adjustIvyDoor();
        "The tower emits a series of shuddering, grinding noises. When the 
        noise subsides, you find that the arch leading into the tower is open. ";
    }
   
    // moveRoom is called only if the junctionBox is powered -- the pedestal checks that.
    moveRoom (lever, button) {
        local movingUp = nil;
        local movingDown = nil;
        local movingClockwise = nil;
        // It's possible that one of the doors is
        // open -- or, if we're on level 4 and one of the doors is pointing north to the balcony, they're
        // both open. We'd like to describe that as part of the movement description, so we'll store the
        // information.
        local roseWasBlocked = roseDoor.blocked;
        local ivyWasBlocked = ivyDoor.blocked;
        // We know this is safe, since the perimeter conditions have already been trapped:
        if (lever == 'white') { currentLevel += 1; movingUp = true; }
        else { currentLevel -= 1; movingDown = true; }
        // If we're already at the top or bottom, we'll rotate but not change level:
        if (currentLevel > 5) { currentLevel = 5; movingUp = nil; }
        else if (currentLevel < 1) { currentLevel = 1; movingDown = nil; }
        // Next, compute the new rotation:
        if (button == 'red') { rotation += 1; movingClockwise = true; }
        else rotation -= 2; 
        if (rotation > 8) rotation = rotation - 8;
        if (rotation < 1) rotation = rotation + 8;
        // Change the doors' operation:
        closeAllEntrances();
        local roseNowBlocked = adjustRoseDoor();
        local ivyNowBlocked = adjustIvyDoor();
        local spinDir;
        if (movingClockwise == true) spinDir = 1;
        else spinDir = -1;
        "<<one of>>With a deep shuddering and groaning, as of giant gears clashing, the room
        begins to vibrate, at the same time spinning <<saySpin(spinDir)>> in a rather disorienting
        way<<or>>Again comes the
        shuddering and groaning sound and the dizzying sense that the room is
        rotating, this time <<saySpin(spinDir)>><<or>>As before,
        the room groans and rotates <<saySpin(spinDir)>><<stopping>>. ";
        // provide a hint that possibly we're moving up or down:
        if (movingUp) "You feel heavier than normal for a moment, and then lighter than
            normal, before the sense of motion stops. ";
        else if (movingDown) "You feel lighter than normal for a moment, and then heavier
            than normal, before the sense of motion stops. ";
        
        "When the sound and motion subside, you find that ";
        if (roseNowBlocked && ivyNowBlocked) "both of the doors are
            <<if (!roseWasBlocked || !ivyWasBlocked)>>now <<end>>blocked by sheets of dark gray stone. ";
        // Alternatively, there may be an exit:
        else if (!roseNowBlocked && !ivyNowBlocked)
            "both of the doors are now open. ";
        else {
            if (!roseNowBlocked) "the rose door is <<if (roseWasBlocked)>>now open<<else>>still open<<end>>. ";
            else "the ivy door is <<if (ivyWasBlocked)>>now open<<else>>still open<<end>>. ";            
        }
    }
    saySpin(c) {
        if (c == 1) "from left to right";
        else "from right to left";
    }
    // A utility function. We close all of them prior to possibly opening one or two:
    closeAllEntrances() {
        grottoArch.blocked = true;
        cloakRoomArch.blocked = true;
        behindStairsArch.blocked = true;
        fileRoomArch.blocked = true;
        gardenArch.blocked = true;
        secludedArch.blocked = true;
        balconyArch.blocked = true;
        promenadeEastArch.blocked = true;
        narrowLedgeArch.blocked = true;
    }
    
// grottoArch (nw)
// 
// cloakRoomArch (se)
// 
// behindStairsArch (w)
// fileRoomArch (s)
// gardenArch (e)
// 
// secludedArch (se)
// balconyArch (n)
// promenadeEastArch (sw)
//
// narrowLedgeArch (se)
// 
// roseDoor e: rotation 1 (starting point)
// roseDoor se: rotation 2
// roseDoor s: rotation 3
    adjustRoseDoor () {
        roseDoor.blocked = true;
        switch (currentLevel) {
        case 1:
            if (rotation == 6) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = grotto;
                grottoArch.blocked = nil;
            }
            break;
        case 2:
            if (rotation == 2) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = cloakRoom;
                cloakRoomArch.blocked = nil;
            }
            break;
        case 3:
            if (rotation == 5) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = behindStairs;
                behindStairsArch.blocked = nil;
            }
            else if (rotation == 3) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = fileRoom;
                fileRoomArch.blocked = nil;
            }
            else if (rotation == 1) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = untendedGarden;
                gardenArch.blocked = nil;
            }
            break;
        case 4:
            if (rotation == 2) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = secludedLair;
                secludedArch.blocked = nil;
            }
            else if (rotation == 7) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = balcony;
                balconyArch.blocked = nil;
            }
            else if (rotation == 4) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = upperPromenadeEast;
                promenadeEastArch.blocked = nil;
            }
            break;
        case 5:
            if (rotation == 2) {
                roseDoor.blocked = nil;
                roseDoor.trueDestination = narrowLedge;
                narrowLedgeArch.blocked = nil;
            }
        }
        return roseDoor.blocked;
    }
    adjustIvyDoor () {
        ivyDoor.blocked = true;
        switch (currentLevel) {
        case 1:
            if (rotation == 3) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = grotto;
                grottoArch.blocked = nil;
            }
            break;
        case 2:
            if (rotation == 7) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = cloakRoom;
                cloakRoomArch.blocked = nil;
            }
            break;
        case 3:
            if (rotation == 2) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = behindStairs;
                behindStairsArch.blocked = nil;
            }
            else if (rotation == 8) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = fileRoom;
                fileRoomArch.blocked = nil;
            }
            else if (rotation == 6) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = untendedGarden;
                gardenArch.blocked = nil;
            }
            break;
        case 4:
            if (rotation == 7) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = secludedLair;
                secludedArch.blocked = nil;
            }
            else if (rotation == 4) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = balcony;
                balconyArch.blocked = nil;
            }
            else if (rotation == 1) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = upperPromenadeEast;
                promenadeEastArch.blocked = nil;
            }
            break;
        case 5:
            if (rotation == 7) {
                ivyDoor.blocked = nil;
                ivyDoor.trueDestination = narrowLedge;
                narrowLedgeArch.blocked = nil;
            }
        }
        return ivyDoor.blocked;
    }
;

// The doors aren't actually Doors, because there's no point in allowing them to operate in the usual
// manner.

+ roseDoor: OctDoor 'rose door;; blossom doorway rose lintel'
    blocked = true
    plant = 'rose'
    disambigName = 'rose door'
    trueDestination = nil
;

+ ivyDoor: OctDoor 'ivy door; twining; doorway ivy vine lintel'
    blocked = nil
    plant = 'ivy'
    disambigName = 'ivy door'
    trueDestination = upperPromenadeEast
;

+ inlaidFloor: Floor 'inlaid wood floor; pleasing geometrical handsome; pattern'
    "The floor is inlaid with a pleasing geometrical pattern. "
;

//-----------------------------------------------------------------------------------------
// the pedestal:
//-----------------------------------------------------------------------------------------


+ octPedestal: Surface, Fixture 'pedestal; flat wood wooden; podium lectern'
    "The pedestal is about the height and shape of a lectern, but flat rather than slanted.
    It stands in the precise center of the room, where the eight floor segments converge.
    Protruding from the top of the pedestal are two large levers, one white and one black.
    Mounted more or less flush with the upper surface are two buttons,
    one red and one green. "
    dobjFor(LookBehind) {
        verify() {}
        action() {
            "Scribbled in white chalk along an upper edge of the pedestal,
            on the far side as you enter the room and thus easy to miss unless
            you think to look, is a cryptic message: WU BD RCW1 GCCW2. ";
        }
    }
    
    mostRecentButton = 'red'
    receiveButtonPush (b) {
        mostRecentButton = b;
    }
    leverPulledCount = 0
    leverPulled(color) {
        "You pull the <<color>> lever. "; 
        if (!junctionBox.isPowered) {
            leverPulledCount++;
            "Other than a deep <i>ka-chunk</i> sound, your action appears to have had no
            effect. <<if (leverPulledCount == 5)>>Possibly the mechanism needs to receive
            power from an active power source. <<end>>";
            
            
        }
        else {
            octagonalRoom.moveRoom(color, mostRecentButton);
        }
    }
;

++ pedRedButton: Button, Component 'red button'
    "It's an ordinary round red button. "
    color = 'red'
    makePushed() {
        octPedestal.receiveButtonPush(color);
    }
;
++ pedGreenButton: Button, Component 'green button'
    "It's an ordinary round green button. "
    color = 'green'
    makePushed() {
        octPedestal.receiveButtonPush(color);
    }
;

++ pedWhiteLever: Component 'white lever;; slot'
    "The white lever juts up vertically out of the pedestal. It's mounted in a slot that allows
    it to be pulled toward you. "
    vocabLikelihood = 10
    color = 'white'
    dobjFor(Push) {
        verify() {}
        check() {
            "The lever is at the upper end of its travel. It can be pulled, but not pushed. ";
        }
    }
    dobjFor(Pull) {
        verify() {}
        check() {}
        action() {
            octPedestal.leverPulled(color);
        }
    }
;
++ pedBlackLever: Component 'black lever;; slot'
    "The black lever juts up vertically out of the pedestal. It's mounted in a slot that
    allows it to be pulled toward you. "
    color = 'black'
    vocabLikelihoode = 10
    dobjFor(Push) {
        verify() {}
        check() {
            "The lever is at the upper end of its travel. It can be pulled, but not pushed. ";
        }
    }
    dobjFor(Pull) {
        verify() {}
        check() {}
        action() {
            octPedestal.leverPulled(color);
        }
    }
;
        
    