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

// The nouns for this class are given bullshit plurals, so that when the player
// enters 'guards' or 'guys, it will go to the CollectiveGroup.

class SecurityGuard: Actor, Fixture
    vocab = 'security guard{xxxqqq};; guy{qqqxxx} man{xqxqxq}'
    actorSpecialDesc = ''
    isHim = true
   attentionSpan = nil
;

/* 
 *   The idea of the guards' actorstates is that they have independent
 *   actorstates for purposes of stateDesc and so that individual conversation
 *   topics can be attached to them (if nothing else, so we can write 'ask frank
 *   about ray' and 'ask ray about frank'. But ALL of the specialDesc entries
 *   for the two guards will be handled by Franklin's actorstates.
 */

// We'll let Frank stop you if you try the Push action.

//----------------------------------------------------
// franklin
//----------------------------------------------------

franklin: SecurityGuard '+; young younger hefty amiable black; frank franklin; him' @securityOffice
    "Frank is a hefty African-American man with a broad, amiable face. He's
    wearing a gray uniform with a nametag that says (obviously) <q>Franklin,</q>
    but the odds are good he'd answer to <q>Frank.</q> "
    vocabLikelihood = 15
    disambigName = 'hefty black guy'
    shouldNotKissMsg = 'That would only make Ray jealous. '
    cannotEatMsg = 'Cannibalism? Really? '
    shouldNotAttackMsg = 'Do you really want to spend the night in jail? '
    globalParamName = 'frank'
    makeProper() {
        addVocab('Frank;; franklin');
        proper = true;
    }
    beforeAction() {
        if (gActionIs(Push)) {
            "As your finger drifts toward the button, one of guards shakes his head
            at you. <q>That's a security installation, ma'am, not a video game.</q> ";
            exit;
        }
    }
    hasBeer = nil
    hasPizza = nil
;

+ frankStairwellClue: DelayedAgendaItem
    isReady = (gPlayerChar.getOutermostRoom() == securityOffice)
    initiallyActive = true
    invokeItem() {
        "As you enter the Security Office, the two guards are in the 
        midst of a discussion. <q>All I\'m saying,</q> one of them says,
        <q>is that we ought to be able to keep an eye on the leather
        goods shop.</q> He gestures at the big monitor screen. <q>We
        can see just about every other shop, the ones we need to see,
        anyhow.</q>
        <.p><q>Ah, it doesn\'t matter,</q> the other guard says. <q>It\'s
        not like anybody is going to come around here with their pants
        falling down and need to steal a belt.</q> ";
        isDone = true;
    }
;

+ AskTopic @ray
    "<q>Great guy, Raymond,</q> he replies, giving his fellow guard a friendly slap on
    the back. <q>Him and me got no problems, do we, Ray?</q> ";
;

+ franklinOnBreak: ActorState
    stateDesc = "He's sitting at a table, munching microwaved pizza and washing
        it down with swigs of cold beer. "
    specialDesc = "The security guards are taking their afternoon break. "
;

++ DefaultAnyTopic
    "They're taking their afternoon break. Best not to disturb them. "
;

//----------------------------------------------------
// franklin's main ActorState: franklinLounging
//----------------------------------------------------

+ franklinLounging: ActorState
    stateDesc = "At the moment, he's standing in the Security Office,
        waiting to see if you have anything interesting to say. "
    specialDesc = "Two uniformed security guards are standing here. "
    isInitState = true
;

//----------------------------------------------------
// franklin's conversation topics in franklinLounging
//----------------------------------------------------

++ AskTellTopic @tJoe
    "<q>I saw a man out in back of the shopping center,</q> you tell the guard. <q>I
    think he's homeless.</q>
    <.p><q>Oh, yeah, him. He's harmless. Never hurts anybody. Maybe if he had some
    shoes he\'d go wander off someplace else.</q> "
;

++ AskTellTopic @tParade
    "<q>I guess most of the shops are closed on account of the parade,</q> you comment.
    <.p><q>You got that right,</q> he replies. <q>The state championship! That\'s a
    very big deal.</q> "
;

++ AskTopic @tPower
    "<q>You mean the electrical power?</q> The guard chuckles. <q>They shut off the power
    to a bunch of the equipment when nobody\'s around. The octagonal room, the diorama,
    that thing up on the roof --- they even shut off the power to the HVAC unit down in
    the utility room, which doesn\'t make much sense to me, but whatever. We still got power
    for our video monitor system, though. Can\'t do without that.</q> "
;

++ AskTellTopic @flatPanelMonitor
    "<q>Latest technology,</q> the guard says. <q>We use that to keep tabs on what's
    going on in the shops. Like if there's shoplifting, or breaking and entering.</q>
    <.p><q>Trouble is,</q> the other guard comments, <q>it ought to let us view <i>all</i>
    of the shops, but it don\'t. The coverage is kinda spotty. Flogg and Grabby cuttin'
    corners as usual, if you ask me.</q> "
;

++ AskTellTopic @woodenIndian
    "<q>I noticed the wooden Indian outside,</q> you comment.
    <.p><q>Yeah, that thing,</q> one of the guards says. <q>Sometimes I think it's
    haunted. I swear it winked at me one time. And it's not the only thing around here that
    moves when it's not supposed to. There's a mannequin downstairs....</q> He pauses
    to glare at his partner. <q>Don't look at me like that. I never seen it move, but
    I heard about it from a customer. From two different customers. All I'm sayin' is,
    things around here can get a little weird sometimes.</q> "
;

++ AskTellTopic @breakRoom
    "<q>Do you guys ever take a break?</q> you ask.
    <.p><q>Yeah, usually sometime along about now,</q> the black guard answers. <q>We
    sit down and have a snack in the break room there. Trouble is, my genius partner
    here forgot to bring the grub today. So we got nothin' to do but stay on the job
    and look sharp.</q> He gestures at the monitor screen. "
;

++ AskTellTopic, StopEventList @tPromDress
    [
        '<q>I came here to get a replacement dress for my daughter, for the senior
        prom,</q> you tell him. <q>But it looks like the boutique is closed.</q>
        <.p><q>Yeah, on account of the parade downtown. Wish we could go see the
        parade, but somebody\'s gotta keep an eye on things.</q> ',
        
        '<q>Do you think you might be able to help me get into the boutique?</q>
        you ask, knowing it\'s a long shot. <q>So I could buy the dress, I mean.
        I\'m not planning to steal it!</q>
        <.p><q>Against regulations, ma\'am. Sorry about that.</q> ',
        
        'It\'s clear the guards are not going to be able to help you. Hinder, yes.
        Help, no. '
    ]
;

++ AskTellTopic @tBetsy
    "<q>Can you tell me anything about the hairdresser?</q> you ask.
    <.p><q><<if (betsy.getOutermostRoom == securityOffice)>>Oh, she's
    a swell gal, you know. Real friendly. Hey, Betsy, you still sneakin' a
    cigarette when nobody's lookin'?</q><.p><q>Absolutely not,</q> she
    replies stiffly.<<else>>She likes to sneak
    a smoke whenever she can,</q> the guard says. <q>I
    saw her dump a whole ashtray full of butts in the potted palm outside.</q><<end>> "
;

++ AskTellTopic, StopEventList @masterKey
    [
        '<q>Is that the master key to the shops?</q> you ask, innocently pointing
        at the key.
        <.p><q>Yeah, that\'s what it is,</q> the guard says. <q>We always gotta keep an eye on it. Can\'t
        have anybody just walk off with it, you know. You\'d be amazed how sneaky
        some people are.</q> ',
        
        '<q>I don\'t suppose I could, like, borrow it for a minute,</q> you say. The
        guards laugh. '
    ]
;

+++ AltTopic
    "Mentioning the master key to them would be a big mistake. They don't seem to
    have noticed that it's missing! "
    isActive = masterKey.moved
;

++ GiveShowTopic [aPizza, aSixPack]
    topicResponse {
        "<q>Hey, thanks! It's time for our afternoon break.</q> ";
        if (gDobj == aPizza) franklin.hasPizza = true;
        else if (gDobj == aSixPack) franklin.hasBeer = true;
        gDobj.moveInto(nil);
        if (((gDobj == aPizza) && (franklin.hasBeer)) ||
                ((gDobj == aSixPack) && (franklin.hasPizza))) {
            guardsGroup.goOnBreak();
            return;
        }
        "Frank scratches his chin. <q>You wouldn't happen to have
        any <<if (gDobj == aPizza)>>beer<<else>>pizza<<end>>, would you?</q> ";
    }
;

++ AskTopic @lostAndFoundBox
    "<q>That? We put stuff in it if we find it lyin\' around, that\'s all.</q> "
;

++ AskTopic [flatPanelMonitor, videoGrid, monitorControlPanel]
    "<q>That thing? That's how we keep an eye on what's going on around here. If
    there's a crime taking place, like breaking and entering, we spot it pretty
    quick.</q>
    <.p>His partner adds, <q>Trouble is, the owners are pretty cheap. There's only
    sixteen video feeds, so some of the stores don't have coverage.</q>
    <.p><q>Don't be givin' away our trade secrets, Ray. Not that we don't
    trust you, lady. I'm sure you wouldn't get up to no mischief.</q> ";

++ AskTellTopic, StopEventList [ollie, octopusTank]
    [
        '<q>I saw an octopus in the tank downstairs,</q> you say.<.p>
        <q>Oh, yeah,</q> Frank replies. <q>That\'s some kind of weird P.R.\ stunt.</q> ',
        '<q>Do you think it\'s safe,</q> you ask, <q>having such a large octopus
        here in the shopping center?</q>
        <.p><q>Long as he don\'t get loose,</q> Frank
        replies with a shrug. <q>But that lid\'s pretty heavy. I don\'t guess he could knock it
        off by himself.</q> ',
        'Franklin only shrugs. Evidently you\'ve exhausted the topic of the octopus for the
        time being. '
    ]
    isConversational = nil
;

+++ AltTopic
    "<q>I\'m afraid the octopus has escaped from its tank,</q> you say meekly, carefully not mentioning
    your own culpability.
    <.p>Exclamations of annoyance flying thick and fast, the guards bolt from
    the room.<<guardsGroup.moveDownstairs>> "
    isActive = (ollie.released && !ollie.recaptured)
    isConversational = nil
;

+++ AltTopic
    "<q>Did you catch the octopus?</q> you ask.
    <.p><q>Took care of it,</q> Frank replies. <q>Dunno how the damn thing got loose.</q> "
    isActive = (ollie.recaptured)
;

+++ AltTopic
    "<q>I see you\'re chasing the octopus,</q> you say --- but not surprisingly, the guards
    are too busy chasing the octopus to respond. "
    isActive = (franklin.isIn(lowerConcourseSouth))
;

++ DefaultGiveShowTopic
    "<q>I hope you bought that,</q> he says. <q>You don't <i>look</i> like a shoplifter, but
    I been fooled before.</q> "
;

++ DefaultAskTellTopic, ShuffledEventList
    [
        'The guard shrugs elaborately. <q>Search me,</q> he replies. ',
        
        '<q>Can\'t help you with that,</q> he says. <q>Sorry.</q> ',
        
        '<q>Wish we had an information booth around here, but we don\'t,</q> he replies. ',
        
        '<q>Danged if I know,</q> he says. ',
        
        '<q>Maybe ask the bartender,</q> the guard suggests. <q>He loves to gab.</q> '
    ]
    
;


//----------------------------------------------------
// franklin's downstairs ActorState: franklinPursuing
//----------------------------------------------------

+ franklinPursuing: ActorState
    stateDesc = "At the moment, he\'s trotting around the lower concourse, trying (with
        Ray\'s help) to corner Ollie the Octopus. "
    specialDesc = "Frank and Ray are falling all over themselves trying to catch Ollie the Octopus. "
;

//----------------------------------------------------
// ray
//----------------------------------------------------

ray: SecurityGuard '+; older old bearded white; ray raymond; him' @securityOffice
    "<<makeProper()>>Ray is an older white guy with a patchy red Chuck Norris beard and a spreading
    waistline. He's wearing
    a gray uniform with a nametag that says (obviously) <q>Ray.</q> "
    shouldNotKissMsg = 'The danger is, he might think you meant it. '
    cannotEatMsg = 'Even broiled on a rotisserie he wouldn\'t be very appetizing. '
    shouldNotAttackMsg = 'Those karate classes were twenty years ago. You\'d stand no chance at all. '
    disambigName = 'older white guy'
    globalParamName = 'ray'
    makeProper() {
        addVocab('Ray');
        proper = true;
    }
;

//+ ImpHelloTopic
//    "<q>Excuse me,</q> you say. "
//;

+ GiveTopic [aPizza, aSixPack]
    topicResponse {
        "<q>Hey, thanks! It's time for our afternoon break.</q> ";
        if (gDobj == aPizza) franklin.hasPizza = true;
        else if (gDobj == aSixPack) franklin.hasBeer = true;
        gDobj.moveInto(nil);
        if (((gDobj == aPizza) && (franklin.hasBeer)) ||
                ((gDobj == aSixPack) && (franklin.hasPizza))) {
            guardsGroup.goOnBreak();
            return;
        }
        "Ray scratches his chin. <q>You wouldn't happen to have
        any <<if (gDobj == aPizza)>>beer<<else>>pizza<<end>>, would you?</q> ";
    }
;

+ AskTopic @franklin
    "<q>Great guy, Frank,</q> he replies, giving his fellow guard a friendly slap on
    the back. ";
;

+ DefaultAnyTopic, StopEventList
    [
        'Ray shrugs. <q>I got kind of a headache,</q> he says, and jerks a thumb at Frank.
        <q>Talk to him.</q> ',
        '<q>I told you already,</q> Ray says. <q>I\'m not feelin\' real chatty this
        afternoon. You want to talk, talk to Frank.</q> ',
        'Ray has already suggested that you direct your conversation to Frank. '
    ]
;

//----------------------------------------------------
// ray's main ActorState: rayLounging
//----------------------------------------------------

+ rayLounging: ActorState
    stateDesc = "At the moment, he\'s standing in the Security Office,
        looking at you with mild curiosity. "
    isInitState = true
;

// Ray does, however, need to react if you happen to tell HIM about Ollie:
+ AskTellTopic @ollie
    "<q>I\'m afraid the octopus has escaped from its tank,</q> you say meekly,
    carefully not mentioning your own culpability.
    <.p>Exclamations of annoyance flying thick and fast, the guards bolt from
    the room.<<guardsGroup.moveDownstairs>> "
    isActive = (ollie.released && !ollie.recaptured)
;

//----------------------------------------------------
// ray's downstairs ActorState: rayPursuing
//----------------------------------------------------

+ rayPursuing: ActorState
    stateDesc = "At the moment, he\'s trotting around the lower concourse, trying (with
        Frank\'s help) to corner Ollie the Octopus. "
    specialDesc = nil // "Ray is, likewise, in hot pursuit of Ollie. "
;

+ rayOnBreak: ActorState
    stateDesc = "He's sitting at a table, munching microwaved pizza and washing
        it down with swigs of cold beer. "
;

//----------------------------------------------------
// the CollectiveGroup
//----------------------------------------------------

guardsGroup: CollectiveGroup 'security guards; uniformed; men; them' @securityOffice
    desc {
        ray.makeProper();
        franklin.makeProper();
        if (isIn(securityOffice)) "The guards (if their nametags are to be believed) are named Frank and Ray.
            Ray is white and bearded; Frank is black (or actually, sort of medium brown). They look
            friendly but businesslike. ";
        else if (isIn(breakRoom))
            "The guards are sitting at a table, munching pizza and shooting the breeze. ";
        else "The guards are dashing around the lower concourse in pursuit of Ollie the Octopus. Ollie
            is proving to be more agile than they are, or perhaps more cunning. ";
    }
    isListed = true
    specialDesc = ""
    myObjects = [franklin, ray]
    collectiveActions = [Examine, Attack, Kiss, TellAbout, AskAbout, AskFor]

    cannotTakeMsg = 'One under each arm? I don\'t think the guards would like that. '
    cannotEatMsg = 'Cannibalism? Really? '
    cannotAttackMsg = 'Do you really want to spend the night in jail? '
    dobjFor(Kiss) {
        check () { "But you're happily married! "; }
    }
    
    surveillanceDaemonID = nil
    startSurveillance() {
        if (!surveillanceDaemonID) {
            surveillanceDaemonID = new Daemon (self, &surveillance, 3);
        }
    }
    stopSurveillance() {
        if (surveillanceDaemonID) {
            surveillanceDaemonID.removeEvent();
            surveillanceDaemonID = nil;
            youreSafeNow = true;
        }
    }
    youreSafeNow = nil
    // This code allows the player a partial solution. She can
    // enter the office repeatedly and adjust the monitor so that the
    // next place she wants to go is safe. The guards only turnAllOn if
    // they have all been turned off. And even in that case, it's possible
    // for the player who has not been spotted to re-enter the office and
    // mess with the control panel some more.
    surveillance() {
        // We don't want this daemon switching all of the monitor cells
        // back to active status when you've just now switched them all
        // to inactive!
        if (gPlayerChar.getOutermostRoom() == securityOffice)
            return;
        local rooms = [];
        rooms = flatPanelMonitor.listActiveCells();
        local len = rooms.length();
        // What if there's nothing to surveill, and the panel
        // can't be used?
        if ((len == 0) && (monitorControlPanel.frozen)) {
            stopSurveillance();
            return;
        }
        // But the panel may not be frozen!
        else if (len == 0) {
            flatPanelMonitor.turnAllOn();
            // repopulate the list:
            rooms = flatPanelMonitor.listActiveCells();
            len = rooms.length();
        }
        if (len != 0) {
            for (local i = 1; i <= len; i++) {
            if (gPlayerChar.getOutermostRoom() == rooms[i])
                handcuffs();
            }
        }
    }
    handcuffs() {
        "As you're <<one of>>poking<<or>>gazing<<or>>wandering<<at random>> around,
        wondering <<one of>>what to do next<<or>>if there\'s anything
        here that you could use<<or>>if this room is worth exploring<<or>>whether
        it\'s safe to spend a few minutes looking around<<at random>>, behind you you hear
        a <<one of>>triumphant<<or>>male voice cry<<at random>>, <q>Aha! There she is!</q>
        <.p>One of the guards claps a heavy
        hand on your shoulder. <q>What did you think you were doin', anyhow? Breaking
        and entering, it looks like to me. You'd better come with us.</q> A pair of
        handcuffs is produced, your arms are dragged behind your back, the handcuffs
        are snapped on you, and you're led away to the security office, where the guards
        call the police. ";
        finishGameMsg ('You have failed in your quest.', [finishOptionUndo]);
    }
    
    goOnBreak() {
        // Will need ActorStates for both guards.
        "The guards trundle off into their break room bearing the pizza and beer. ";
        franklin.moveInto(breakRoom);
        ray.moveInto(breakRoom);
        guardsGroup.moveInto(breakRoom);
        franklin.setState(franklinOnBreak);
        ray.setState(rayOnBreak);
    }

    moveDownstairs {
        franklin.moveInto(lowerConcourseSouth);
        franklin.setState(franklinPursuing);
        ray.moveInto(lowerConcourseSouth);
        ray.setState(rayPursuing);
        moveInto(lowerConcourseSouth);
    }
    
    returnToOffice {
        franklin.moveInto(securityOffice);
        franklin.setState(franklinLounging);
        ray.moveInto(securityOffice);
        ray.setState(rayLounging);
        moveInto(securityOffice);
        ollie.moveInto(octopusTank.remapIn);
        tankLid.moveInto(octopusTank.remapOn);
        ollie.recaptured = true;
    }
    
    // Note: We can add AskAbout and other conversational actions here, by including them in
    // isCollectiveAction, above. But we'll need to think carefully about whether the guards
    // will ever drop into a ConversationReadyState and need to be greeted. This is perhaps
    // even more significant with TalkTo, which is likely to trigger greeting protocols.
    dobjFor(AskAbout) asDobjFor(TellAbout)
    dobjFor(TellAbout) {
        verify() {}
        check() {
            if (ray.curState == rayOnBreak)
                "They\'re on their afternoon break. Best not to disturb them. ";
        }
        action() {
            // The parser seems to prefer the sign to the octopus, so we'll test for that too:
            if (gTopic && gTopic.getBestMatch not in (ollie, octopusSign))
                "The guards glance at one another, and {the ray} says, <q>You talk to her.</q><.p> ";
            doInstead (TellAbout, franklin, gTopic);
        }
    }
    iobjFor(ShowTo) asIobjFor(GiveTo)
    iobjFor(GiveTo) {
        verify() {}
        check() {
            if (ray.curState == rayOnBreak)
                "They\'re on their afternoon break. Best not to disturb them. ";
            else if ((gDobj != aPizza) && (gDobj != aSixPack))
                "<q>I guess you must shop here a lot,</q> Frank says. <q>I'm supposed to
                ask to see a sales receipt, but whatever.</q> ";
        }
        action() {
            doInstead(GiveTo, gDobj, franklin);
        }
    }
    dobjFor(TalkTo) {
        verify() {}
        check() {
            if (ray.curState == rayOnBreak)
                "They\'re on their afternoon break. Best not to disturb them. ";
            else
                "Rather than talk to them as a pair, you may find it more practical to address one
                or the other as an individual. ";
        }
    }
;
