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

// Not yet implemented: The guards' ability to scan active cells and detect if the player
// is in any of those locations.

// Question: Can the player manipulate the monitors while the guards are in the room?

//-------------------------------------------------------------------------------
// Utility commands:
//-------------------------------------------------------------------------------

modify Parser
    autoSpell = (!gPlayerChar.isIn(securityOffice))
;

DefineIAction(Video)
    execAction (cmd) {
        if (gPlayerChar.getOutermostRoom != securityOffice) {
            "That command is not useful here. ";
            exit;
        }
        "The video monitor displays a 4x4 grid of images. The images represented by
        the letters 'OO' show what appear to be the interiors of shops within Stufftown. The images
        represented by '**', however, are showing reruns of the popular TV series <i>Law & Order</i>
        or one of its many spinoffs.
        
        <.p>To see exactly what an individual image is showing, you can refer to it
        by a letter (for the row) and a number (for the column). For instance, the
        command 'examine a4' (or 'x a4') will show you what's being displayed in the
        location in the upper right corner (row a, column 4).
        
        <.p>To view just the current contents of the image grid, use the command 'x grid'
        or 'x images'.
        
        <.p>To manipulate the contents of the display, press any of the buttons on the control
        panel mounted beneath it. (You'll need to be alone in the room to do that.)
        
        <.p>To reset the entire grid to its initial configuration so as to try solving
        the puzzle anew, simply press the white button and then the gray button.
        
        <.p>The choice of whether a grid cell displays a nearby location or
        a rerun of <i>Law & Order</i> can be manipulated.
        The manner in which this is accomplished is for you to discover. ";
    }
;
VerbRule(Video)
    'video'
    : VerbProduction
    action = Video
    verbPhrase = 'display/displaying help for the video monitor'
;

/////////////////////////////////////////////////////////////////////////////////////////
// The monitor itself:
/////////////////////////////////////////////////////////////////////////////////////////

flatPanelMonitor: Fixture
    'video monitor; flat-panel; display'
    @securityOffice
    "The flat-panel video monitor is affixed to the wall. It displays a 4x4 grid of
    video images. Mounted below the monitor is what appears to be a control
    panel with five buttons. At the moment,
    the video display looks like this: <.p><<showGrid>>
    
    <.p>[Note: For help understanding the meanings of the symbols in the text display
    depicting the video monitor, enter the command 'video', or consult the built-in help system.] "
    
    showGrid() {
        local surv = 'OO';
        local lawn = '**';
        
        if (me.visual) {
            // Note: the <pre> tag was working yesterday, but today it's not working.
            // So we'll try something different.
            "<font face='TADS-Typewriter'>";
            if (cellA1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellA2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellA3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellA4.active) "<<surv>>"; else "<<lawn>>";
            "\b";
            if (cellB1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellB2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellB3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellB4.active) "<<surv>>"; else "<<lawn>>";
            "\b";
            if (cellC1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellC2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellC3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellC4.active) "<<surv>>"; else "<<lawn>>";
            "\b";
            if (cellD1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellD2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellD3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ \ ";
            if (cellD4.active) "<<surv>>"; else "<<lawn>>";
            "</font>";
        }
        // else this is for the visually impaired:
        else {
            surv = 'surveillance';
            lawn = 'rerun';
            "Top row, left to right:\b ";
            if (cellA1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellA2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellA3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellA4.active) "<<surv>>"; else "<<lawn>>";
            "\bSecond row, left to right:\b ";
            if (cellB1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellB2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellB3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellB4.active) "<<surv>>"; else "<<lawn>>";
            "\bThird row:\b ";
            if (cellC1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellC2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellC3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellC4.active) "<<surv>>"; else "<<lawn>>";
            "\bBottom row:\b";
            if (cellD1.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellD2.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellD3.active) "<<surv>>"; else "<<lawn>>";
            "\ \ ";
            if (cellD4.active) "<<surv>>"; else "<<lawn>>";
        }
    }
//    gSoriginal = [['S', 'L', 'S', 'L'], ['S', 'S', 'S', 'S'], ['S', 'L', 'S', 'L'], ['S', 'S', 'S', 'S']]
//    gDoriginal = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
//        
//    gS = [['S', 'L', 'S', 'L'], ['S', 'S', 'S', 'S'], ['S', 'L', 'S', 'L'], ['S', 'S', 'S', 'S']]
//    gD = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]
    
    listActiveCells() {
        local cells = [];
//    1. bookstore -- rareBookShop
        if (cellA1.active) cells = cells.append(rareBookShop);
//    2. wine shop -- grapeNotion
        if (cellA2.active) cells = cells.append(grapeNotion);
//    3. travel agency -- travelAgency
        if (cellA3.active) cells = cells.append(travelAgency);
//    4. no longer sporting goods -- racquetScience
        if (cellA4.active) cells = cells.append(sportingGoods);
//    5. antique furniture -- grandmasDrawers
        if (cellB1.active) cells = cells.append(grandmasDrawers);
//    6. leather goods shop -- asteroidBelt
        if (cellB2.active) cells = cells.append(chartreuseCaboose);
//    7. pet store -- petShop
        if (cellB3.active) cells = cells.append(petShop);
//    8. fashion boutique -- hotRags
        if (cellB4.active) cells = cells.append(hotRags);
//    9. shipping department -- shippingDepartment
        if (cellC1.active) cells = cells.append(shippingDepartment);
//    10. lamp store -- lightFantastic
        if (cellC2.active) cells = cells.append(lightFantastic);
//    11. recruiting office -- marchingOff
        if (cellC3.active) cells = cells.append(marchingOff);
//    12. plant store -- greenFriends
        if (cellC4.active) cells = cells.append(greenFriends);
//    13. dentist office -- fillingStation
        if (cellD1.active) cells = cells.append(fillingStation);
//    14. toy store -- toyShop
        if (cellD2.active) cells = cells.append(toyShop);
//    15. optician's shop -- lookingAtYou
        if (cellD3.active) cells = cells.append(lookingAtYou);
//    16. scrimshaw shop -- scrumptiousScrimshaw
        if (cellD4.active) cells = cells.append(scrumptiousScrimshaw);
        
        if (cells.length == 0) monitorAch.awardPointsOnce();
        
        return cells;
    }
    
    turnAllOn() {
        cellA1.active = true;
        cellA2.active = true;
        cellA3.active = true;
        cellA4.active = true;
        cellB1.active = true;
        cellB2.active = true;
        cellB3.active = true;
        cellB4.active = true;
        cellC1.active = true;
        cellC2.active = true;
        cellC3.active = true;
        cellC4.active = true;
        cellD1.active = true;
        cellD2.active = true;
        cellD3.active = true;
        cellD4.active = true;
    }
    
    toggleSquare() {
        cellA2.toggle();
        cellA4.toggle();
        cellC2.toggle();
        cellC4.toggle();
    }
    
    advanceRight {
        local temp = nil;

        temp = cellA4.active;
        cellA4.active = cellA3.active;
        cellA3.active = cellA2.active;
        cellA2.active = cellA1.active;
        cellA1.active = temp;

        
        temp = cellB4.active;
        cellB4.active = cellB3.active;
        cellB3.active = cellB2.active;
        cellB2.active = cellB1.active;
        cellB1.active = temp;
        
        temp = cellC4.active;
        cellC4.active = cellC3.active;
        cellC3.active = cellC2.active;
        cellC2.active = cellC1.active;
        cellC1.active = temp;
        
        temp = cellD4.active;
        cellD4.active = cellD3.active;
        cellD3.active = cellD2.active;
        cellD2.active = cellD1.active;
        cellD1.active = temp;
    }
    
    rotateCW {
        // First, store some data:
        local temp1 = cellB2.active;
        local temp2 = cellA2.active;
        local temp3 = cellA3.active;
        local temp4 = cellA1.active;
        // Next, rotate the outer edges:
        // Copy the left edge onto the upper edge:
        cellA3.active = cellB1.active;
        cellA2.active = cellC1.active;
        cellA1.active = cellD1.active;
        // Now the bottom edge onto the left edge:
        cellB1.active = cellD2.active;
        cellC1.active = cellD3.active;
        cellD1.active = cellD4.active;
        // Now the right edge onto the bottom edge:
        cellD2.active = cellC4.active;
        cellD3.active = cellB4.active;
        cellD4.active = cellA4.active;
        // And now the top edge onto the right edge:
        cellA4.active = temp4;
        cellB4.active = temp2;
        cellC4.active = temp3;
        // Now copy the center four:
        cellB2.active = cellC2.active;
        cellC2.active = cellC3.active;
        cellC3.active = cellB3.active;
        cellB3.active = temp1;
    }
    
    toggleFour {
        cellD1.toggle();
        cellC2.toggle();
        cellC3.toggle();
        cellB4.toggle();
    }
    
//    The locations:
//    1. bookstore -- rareBookShop
//    2. wine shop -- grapeNotion
//    3. travel agency -- travelAgency
//    4. no longer sporting goods -- sportingGoods
//    5. antique furniture -- grandmasDrawers
//    6. leather goods shop -- asteroidBelt
//    7. pet store -- petShop
//    8. fashion boutique -- hotRags
//    10. lamp store -- lightFantastic
//    9. shipping department -- shippingDepartment
//    11. recruiting office -- marchingOff
//    12. plant store -- greenFriends
//    13. dentist office -- fillingStation
//    14. toy store -- toyShop
//    15. optician's shop -- lookingAtYou
//    16. scrimshaw shop -- scrumptiousScrimshaw
    
    getImage (num) {
        switch(num) {
        case 1:
            "a shop crammed with bookshelves";
            break;
        case 2:
            "a purple-tinted shop with racks of bottles";
            break;
        case 3:
            "a shop with posters on the walls and a big blue box like an opaque phone booth";
            break;
        case 4:
            "a room that seems to be empty except for some miscellaneous construction equipment";
            break;
        case 5:
            "a shop filled with antique furniture";
            break;
        case 6:
            "a night club, with a dance floor and a bandstand";
            break;
        case 7:
            "a shop lined with animal cages large and small";
            break;
        case 8:
            "a shop with mannequins dressed in fashionable attire and striking dramatic lifelike poses";
            break;
        case 9:
            "a large room with a rollup door to one side and a large crate in the middle of the floor";
            break;
        case 10:
            "a shop filled to bursting with lamps";
            break;
        case 11:
            "a shop where a man in uniform is standing very, very still";
            break;
        case 12:
            "a shop that looks more like a jungle owing to the profusion of green plants";
            break;
        case 13:
            "a small and rather antiseptic-looking shop with a heavy reclining chair";
            break;
        case 14:
            "a shop full of toys, where a large but rather blurry purple thing is wandering around";
            break;
        case 15:
            "a shop with a broad display of glasses frames and other optical gear";
            break;
        case 16:
            "a shop whose shelves display exotic ivory carvings";
            break;
        default:
            "Error -- this should never print. ";
        }
    }
    
    getCaption (num) {
        switch(num) {
        case 1:
            "INKWELL";
            break;
        case 2:
            "SOMETIMES";
            break;
        case 3:
            "COLOSSAL";
            break;
        case 4:
            "RACQUET";
            break;
        case 5:
            "GRANDMA'S";
            break;
        case 6:
            "CABOOSE";
            break;
        case 7:
            "FEATHERS";
            break;
        case 8:
            "HOT RAGS";
            break;
        case 9:
            "SHIPPING";
            break;
        case 10:
            "FANTASTIC";
            break;
        case 11:
            "MARCHING";
            break;
        case 12:
            "FRIENDS";
            break;
        case 13:
            "FILLING";
            break;
        case 14:
            "PLAY";
            break;
        case 15:
            "LOOKING";
            break;
        case 16:
            "SCRUMPTIOUS";
            break;
        default:
            "Error -- this should never print. ";
        }
    }
;

+ videoGrid: Component 'grid;; cells images'
    desc {
        "\b";
        flatPanelMonitor.showGrid();
    }
;

class VideoCell: Component
    // Here, we store the list of cells in a simple linear list rather
    // than in a two-dimensional array, and we let each cell keep track
    // of whether it's active in surveillance.
    number = 1
    active = nil
    toggle() {
        if (active) active = nil;
        else active = true;
    }
    desc {
        "In <<name>> you can see ";
        if (active) {
            flatPanelMonitor.getImage(number);
            ", beneath which is the caption ";
            flatPanelMonitor.getCaption(number);
        }
        else {
            "a rerun of <i>Law & Order</i>";
            local num = rand(10);
            if (num > 6) " --- hey, look! There's
                <<one of>>Lenny Briscoe<<or>>Bobby Goren<<or>>Olivia Benson<<or>>Elliot Stabler<<or>>one of
                those improbably sexy assistant D.A.'s<<or>>Adam Schiff<<or>>Fin Tutuola<<at random>>";
        }
        ". ";
    }
;

+ cellA1: VideoCell 'cell a1'
    number = 1
    active = true
;
+ cellA2: VideoCell 'cell a2'
    number = 2
    active = nil
;
+ cellA3: VideoCell 'cell a3'
    number = 3
    active = true
;
+ cellA4: VideoCell 'cell a4'
    number = 4
    active = nil
;

+ cellB1: VideoCell 'cell b1'
    number = 5
    active = true
;
+ cellB2: VideoCell 'cell b2'
    number = 6
    active = true
;
+ cellB3: VideoCell 'cell b3'
    number = 7
    active = true
;
+ cellB4: VideoCell 'cell b4'
    number = 8
    active = true
;

+ cellC1: VideoCell 'cell c1'
    number = 9
    active = true
;
+ cellC2: VideoCell 'cell c2'
    number = 10
    active = nil
;
+ cellC3: VideoCell 'cell c3'
    number = 11
    active = true
;
+ cellC4: VideoCell 'cell c4'
    number = 12
    active = nil
;

+ cellD1: VideoCell 'cell d1'
    number = 13
    active = true
;
+ cellD2: VideoCell 'cell d2'
    number = 14
    active = true
;
+ cellD3: VideoCell 'cell d3'
    number = 15
    active = true
;
+ cellD4: VideoCell 'cell d4'
    number = 16
    active = true
;

// One solution is: blue, green, red, blue, green, blue, red, blue

+ monitorControlPanel: Component 'control panel; (monitor) (screen); controls'
    "The control panel <<if frozen>>(now covered by a layer of clear nail polish) <<end>>has
    five buttons on its face --- one each of the white, red, green, blue,
    and gray persuasions. The white button has a star on it, the green button a right-pointing
    arrow, the red button an arrow that curves in a circular way, the blue button a somewhat
    wiggly diagonal slash mark, and the gray button a pattern of four dots in a square. "
    frozen = nil
    iobjFor(PutOn) {
        verify() {}
        check() {
            if (gDobj != nailPolishBottle) "The control panel is not a surface onto
                which you can set various objects. ";
        }
        action() {
            doInstead (PourOnto, nailPolishBottle, self);
        }
    }
    // Note that this is a trap for the unwary player, as you CAN freeze the panel before
    // you solve the puzzle. This is a way to make the game unwinnable.
    iobjFor(PourOnto) {
        verify() { logical; }
        check() {
            if (gDobj != nailPolishBottle) "That would only make a mess. ";
            else if (frozen) "There's already a layer of clear nail polish on the panel. ";
            else if (ray.curState != rayOnBreak)
                "Not a bad idea, but there may be something else you'll want to do first. ";
        }
        action() {
            frozen = true;
            nailPolishBottle.stillNeeded = nil;
            polishAch.awardPointsOnce();
            "You dump a nice thick coat of clear nail polish onto the control panel. It
            dries almost instantly. ";
        }
    }
;

// white to reset everything to surveillance:
++ whiteMRButton: Component, Button 'white button; star'
    "It's a small white button with a star on its face. "
    dobjFor(Push) {
        check() {
            if (betsy.getOutermostRoom() == securityOffice)
                "{The betsy} waggles an admonishing finger. <q>You really shouldn't
                be messing with that, should you?</q> ";
            else if (monitorControlPanel.frozen)
                "You're unable to press the button, as it's covered by a layer of clear nail polish. ";
        }
        action() {
            flatPanelMonitor.turnAllOn();
            // The test of whether the player is in the room is based on the obsolete idea
            // that the buttons are on a portable remote.
            if (gPlayerChar.getOutermostRoom == securityOffice) {
                "The video monitor display flickers briefly. It now looks like this:\b";
                flatPanelMonitor.showGrid();
            }
        }
    }
;

// gray to cause the square four to toggle:
++ grayMRButton: Component, Button 'gray button; four dots square grey'
    "It's a small gray button with a pattern of four dots arranged in a square. "
    dobjFor(Push) {
    check() {
            if (betsy.getOutermostRoom() == securityOffice)
                "{The betsy} waggles an admonishing finger. <q>You really shouldn't
                be messing with that, should you?</q> ";
            else if (monitorControlPanel.frozen)
                "You're unable to press the button, as it's covered by a layer of clear nail polish. ";
        }
        action() {
            flatPanelMonitor.toggleSquare();
            if (gPlayerChar.getOutermostRoom == securityOffice) {
                "The video monitor display flickers briefly. It now looks like this:\b";
                flatPanelMonitor.showGrid();
            }
        }
    }
;

// green to advance right:
++ greenMRButton: Component, Button 'green button; right arrow right-pointing'
    "It's a small green button with a right-pointing arrow on it. "
    dobjFor(Push) {
        check() {
            if (betsy.getOutermostRoom() == securityOffice)
                "{The betsy} waggles an admonishing finger. <q>You really shouldn't
                be messing with that, should you?</q> ";
            else if (monitorControlPanel.frozen)
                "You're unable to press the button, as it's covered by a layer of clear nail polish. ";
        }
        action() {
            flatPanelMonitor.advanceRight();
            if (gPlayerChar.getOutermostRoom == securityOffice) {
                "The video monitor display flickers briefly. It now looks like this:\b";
                flatPanelMonitor.showGrid();
            }
        }
    }
;
// red to rotate clockwise:
++ redMRButton: Component, Button 'red button; circular arrow'
    "It's a small red button with a circular arrow on its face. "
    dobjFor(Push) {
        check() {
            if (betsy.getOutermostRoom() == securityOffice)
                "{The betsy} waggles an admonishing finger. <q>You really shouldn't
                be messing with that, should you?</q> ";
            else if (monitorControlPanel.frozen)
                "You're unable to press the button, as it's covered by a layer of clear nail polish. ";
        }
        action() {
            flatPanelMonitor.rotateCW();
            if (gPlayerChar.getOutermostRoom == securityOffice) {
                "The video monitor display flickers briefly. It now looks like this:\b";
                flatPanelMonitor.showGrid();
            }
        }
    }
;
// blue to toggle four cells:
++ blueMRButton: Component, Button 'blue button; diagonal slash mark'
    "It's a small blue button with a diagonal slash mark on it. "
    dobjFor(Push) {
        check() {
            if (betsy.getOutermostRoom() == securityOffice)
                "{The betsy} waggles an admonishing finger. <q>You really shouldn't
                be messing with that, should you?</q> ";
            else if (monitorControlPanel.frozen)
                "You're unable to press the button, as it's covered by a layer of clear nail polish. ";
        }
        action() {
            flatPanelMonitor.toggleFour();
            if (gPlayerChar.getOutermostRoom == securityOffice) {
                "The video monitor display flickers briefly. It now looks like this:\b";
                flatPanelMonitor.showGrid();
            }
        }
    }
;
