#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
#include "AHA.h"

/* 
 *   ChessPlayers.t 
 *
 *   This file contains the code for the NPCs who take part in the chess game.
 */


caiaphas : Person 'jewish joseph high priest/caiaphas*players' 'Caiaphas' 
    @whiteChair
    "He's dressed in the robes of a Jewish High Priest. "
    isHim = true
    isProperName = true
    posture = sitting
    opponent = 'Pilate'
    collectiveGroup = playerGroup
    uselessToAttackMsg = 'He looks like he\'s got troubles enough, without your
        trying to add to them. '
;

+ caiaphasResting: ActorState
    isInitState = true
    afterTravel(traveler, connector)
    {
        getActor.setCurState(caiaphasPlaying);
    }
    specialDesc = ""
;

+ caiaphasPlaying : PlayerPresent, HermitActorState, EventList
    specialDesc = "Caiaphas is sitting in the white chair, facing
        <<getActor.opponent>> across the chess board. "
    noResponse = "Caiaphas is too intent in his game to take any notice of you. "  
    eventList = [
        nil,
        'Caiaphas moves his Temple two squares to the left. ',
        nil,
        'Caiaphas takes Pilate\'s centurion with one of his Zealots. ',
        nil,
        '<q>But you can\'t do that!</q> Caiaphas protests.\b
        <q>I\'m the Emperor; I can do anything!</q> he retorts. '
    ]
    
    beforeTravel(traveler, connector)
    {
        getActor.setCurState(caiaphasResting);
    }
;

unPilate : PresentLater, Unthing 'pontius pilate' 'pontius pilate' @chessRoom
    'The chess piece representing Pontius Pliate disappeared out of sight when
    the Emperor tossed it aside: perhaps, being no longer needed, it has simply
    ceased to exist. In any case you can\'t see it anywhere. '
;


pilate : Person 'roman pontius
    pilate/governor/prefect/praefect/procurator*players'
    'Pontius Pilate' @redChair
    "Pilate is wearing a toga with the thin purple stripe of the Roman
    equestrian order. "
    isHim = true
    isProperName = true
    posture = sitting  
    collectiveGroup = playerGroup
    uselessToAttackMsg = 'Attacking Roman governors is the sort of thing that
        could get a chap crucified, so you think better of it. '
;

+ Decoration 'thin purple stripe/toga' 'toga'
    "<<location.desc>>"
    notImportantMsg = 'Pilate would probably object rather strongly to your
        fiddling with his toga; you\'d best leave it alone. '
;

+ pilateResting: ActorState
    afterTravel(traveler, connector)
    {
        getActor.setCurState(pilatePlaying);
    }
    isInitState = true
    specialDesc = "Pontius Pilate is facing Caiaphas across the chess board. "
;

+ pilatePlaying: PlayerPresent, HermitActorState, EventList
    specialDesc = "Pontius Pilate is sitting in the red chair, playing chess. "
    noResponse = "Pilate scowls at the interruption, motions you to silence
        with an imperious wave of his hand, and turns back to the chess
        board. "
    
    eventList = [
        
        /* 
         *   note the use of the short form anonymous function synyax, {: " 
         *   " }, to include a double-quoted string in an EventList.
         */
        
        {: "Pilate takes Caiaphas\'s Judas Iscariot with his centurion.\b
            <q>Plenty more where he came from,</q> Caiaphas observes drily.\b
            You are momentarily taken aback at the sight of this strange chess
            game -- it was not at all what you were expecting to see after the
            crosses on Skull Mountain. <<gRevealed('chess-screen') ? 'But then
                you recognize it as the game you saw on the monitor. ' :
              ''>> "},
        
        '<.p>As you study the board and the players, you begin to realize what
        the game is about, and what its connection with Skull Mountain is. ',
        
        'Pilate ponders his next move for a moment, then advances his auxiliary
        cohort three squares.\b
        You reflect that Skull Mountain represented the scene of Jesus\'
        crucifixion, which took place around 30 CE, when Pilate was the Roman
        Governor of Judaea and Caiaphas the Jewish High Priest. It looks to you
        as if their chess game is playing out the events that followed. ',
        
        'Pilate scowls deeply, then a slow smile spreads over his face as he
        spots the vulnerability of his adversary\'s Temple.\b
        You note the shock on Caiaphas\'s face, and feel some of it yourself.
        You can see what\'s about to happen: although neither the historical
        Pilate nor the historial Caiaphas was still on the scene as late as the
        Jewish revolt of 66-70 CE, this Pilate is clearly a stand-in for the
        Roman power that crushed that revolt, and he\'s about to deliver the
        final blow. ',
        
        new function {
        "Pilate's hand reaches for his Emperor and picks it up, with the
        evident intention of moving it forward to a tactically advantageous
        position. But before Pilate can place the Emperor, the piece starts
        squirming in his hand, and protests, <q>You do not manipulate me; I
        manipulate you!</q>\b
        So saying the Emperor piece swells rapidly in size, while Pilate
        shrinks, until it is the Emperor who is sitting in the red chair
        clasping a Pilate chess piece in his right hand.\b        
        The Emperor ponders for a moment, then tosses Pilate aside, sending him
        clattering across the floor and out of sight. He then reaches under the
        table and places a new red piece on the board -- the Scarlet Whore of
        Babylon.\b
        That was one hell of a shock too, but as soon as you recover your wits
        you realize that the game is still following a predictable scheme. The
        Roman-Jewish conflict has just moved to a higher, more mythological
        plane: the piece the Emperor has just produced from under the table is
        the Whore of the book of Revelation, and the game is about to become
        apocalyptic. ";
        pilate.moveInto(nil);
        unPilate.makePresent();
        emperor.moveIntoForTravel(redChair);
        emperor.makePosture(sitting);
        emperor.setCurState(emperorPlayingCaiaphas);
        caiaphas.opponent = 'the Emperor';
        gSetSeen(emperor);
        whore.makePresent();
        
    }
        
    ]
    beforeTravel(traveler, connector)
    {
        getActor.setCurState(pilateResting);
    }
;

emperor : Person 'roman julius gaius octavian tiberius nero claudius augustus 
    titus flavius vespasian imperial emperor/caesar/majesty*players' 
    'Emperor'
    "His Imperial Majesty Gaius Julius Tiberius Nero Claudius Octavian Titus
    Flavius Vespasian Caesar Augustus is dressed in a <<isStone ? 'stone' :
      'purple'>> cloak, with a <<isStone ? 'stone' : 'golden'>> laurel wreath
    perched at a rakish angle on his head. For all his Roman patrician
    features, he seems to bear a striking resemblance to Professor
    Wortschlachter. "
    isHim = true
    cannotTakeMsg()
    {
        if(isStone)     
            return 'He\'s turned into a solid stone statue that\'s far too
                heavy to budge. ';
        else
            return 'He\'s hardly likely to let you do that. ';
    }
    checkTakeFromInventory(actor, obj)
    {
        /* don't allow it - show an error and terminate the command */
        if(isStone)
            "In common with the rest of the Emperor, <<obj.theName>> has turned
            to stone and is now part of his statue; there\'s no way {you/he}
            can remove it. ";
        else
            "There\'s no way the Emperor is going to let {you/him} take his 
            <<obj.name>>. ";
        exit;
    }
    
    
    cannotMoveMsg = (cannotTakeMsg)
    cannotPutMsg = (cannotTakeMsg)
    postureDesc() { }
    isStone = (curState == emperorStone)
    feelDesc = "<<isStone ? 'Cold, hard stone' : 'He won\'t take kindly to
        your pawing him'>>. "
    cannotKissActorMsg()
    {
        if(isStone)
            return '{You/he} kiss{es} the cold stone statue. ';
        else
            return 'He probably wouldn\'t regard that as appropriate, and he
                doesn\'t look like the sort of man to get on the wrong side
                of. ';
    }
    uselessToAttackMsg()
    {
        if(isStone)
            return 'Beating your hands against the statue will probably hurt
                them more than it. ';
        else
            return 'He looks stronger than you, so you decide against it. ';
    }
    collectiveGroup = playerGroup
;

class EmperorGarment : CustomImmovable
    
    
;

+ EmperorGarment '(gold) (stone) golden laurel wreath/crown' 'laurel wreath'
    "It's in the form of a laurel wreath, but it's made of <<emperor.curState
      == emperorStone ? 'stone' : 'gold'>>. " 
    dobjFor(TakeFrom)
    {
        verify()
        {
            if(gIobj == nil)
            {
                if(gTentativeIobj.indexWhich({x: x.obj_ == emperor} ))
                    logicalRank(150, 'emperor\'s crown');
            }
            else    
                inherited;
        }  
    }
    
;

+ EmperorGarment 'short purple (stone) cloak' 'cloak'
    "It's a short cloak draped over his shoulders. "
;


+ emperorPlayingCaiaphas: PlayerPresent, HermitActorState, EventList
    
    specialDesc = "The Emperor is seated on the red chair, playing chess. "
    noResponse = "His Imperial Majesty is too engrossed in the game. "
    eventList =
    [
        nil,
        
        new function { 
        "The Emperor takes Caiaphas\'s Temple with his Whore of Babylon.\b
        <q>No temple, no high priest,</q> the emperor observes dryly.\b
        Caiaphas pales in horror, then pales into insignificance, vanishing
        before your eyes.<.p>";
        caiaphas.moveInto(nil);
        "The Emperor looks up at you, then waves at the white chair, <q>Perhaps
        you will prove a worthier opponent,</q> he suggests.<.p>
        You hear a sound behind you, and turn just in time to see the tunnel
        entrance disappear; when you turn back to the Emperor he merely smiles,
        shrugs, and remarks, <q>Your only way out of here is to beat me at this
        game -- otherwise...</q> he shrugs expressively, then adds, <q>be
        seated; I refuse to play with my opponent hovering over me.</q>";
        chessDoor.makeOpen(nil);
        PresentLater.makePresentByKey('chess');
        whore.isListed = true;
        decorationPieces.moveInto(nil);
        emperor.setCurState(emperorPlaying);
        emperor.collectiveGroup = nil;
        challengeManager.setChallenge('The Emperor has just challenged you
            to a game of chess. ');
    }
    ]
;

+ emperorPlaying : PlayerPresent, InConversationState
    specialDesc = "The Emperor is waiting for you to make your move. "
    stateDesc = "He's sitting on the red chair, staring at the chess board,
        waiting for you to make your move. "  
    afterAction()
    {
        if((gActionIs(TakeWith) && gIobj.ofKind(WhiteChessPiece))
           || (gActionIs(Move) && gDobj.ofKind(WhiteChessPiece)))
        {
            redPiece = choosePiece(RedChessPiece);
            whitePiece = choosePiece(WhiteChessPiece);
            
            /* 
             *   If the player has run out of other pieces for the emperor 
             *   to take, then there's only the white soul left, so this is 
             *   taken and the player loses.
             */
            
            playlist.doScript; 
        }
        if(gActionIs(PutOn) && gDobj==chessPiece && gIobj==chessBoard.subSurface)
            "The Emperor frowns in disapproval as you place a new piece on the
            board, and looks as if he's about to protest, so you forestall his
            protest by remarking, <q>Well, <i>you</i> put a new piece on the
            board just now!</q>\b
            <q>This you mean?</q> he points to the Whore seated on the Beast,
            <q>This is simply my avatar, which I'm entitled to have since I'm
            no longer a piece on the board -- but your piece, what is
            that?</q>\b
            <q>It's \^<<chessPiece.pieceName>>!</q> you declare boldly.\b
            <q>\^<<chessPiece.pieceName>>?</q> he sneers, <q>What is
            \^<<chessPiece.pieceName>>? No matter, that will avail you naught,
            I can crucify \^<<chessPiece.pieceName>> ten times before
            breakfast! Play with it if you must, it will make no
            difference!</q>";
    }
    playlist: EventList {
    [
        '<.p>The Emperor moves his Whore forward two squares. ',
        
        new function {
            "<.p>The Emperor takes <<whitePiece.theName>> with
            <<redPiece.theName>>. ";
            whitePiece.moveInto(nil);
        },
        
        new function {
            "<.p>The Emperor moves his Whore on the same square as
            <<whitePiece.theName>>, which the Whore promptly devours. ";
            whitePiece.moveInto(nil);
        },
        
        new function {
            "<.p>The Emperor's Whore of Babylon devours
            <<whitePiece.theName>>. ";
            whitePiece.moveInto(nil);
        },
        
        new function {
            "<.p>The Emperor advances <<redPiece.theName>>";
            if(whitePiece != nil)
            {
                " and takes <<whitePiece.theName>>";
                whitePiece.moveInto(nil);
            }
            ". ";       
        },
        
        new function {
            "<.p>The Emperor moves <<redPiece.theName>> forward. "; 
        },
        
        new function {
            if(whitePiece != nil)
            {
                "<.p>With a satisfied smirk, the Emperor uses
                <<redPiece.theName>> to take <<whitePiece.theName>>. He seems
                to be wiping the board with you. ";
                whitePiece.moveInto(nil);
            }
            else
                "<.p>The Emperor moves <<redPiece.theName>> forward, evidently
                in preparation for an attack on your soul. ";
        },
        
        '<.p>The Emperor advances his Whore towards your Soul; <q>Check!</q> he
        announces. ',
        
        new function {
            "<.p>The Emperor moves his Whore of Babylon three squares
            diagonally and with a triumphant grin announces, <q>Check
            Mate!</q>\b";
            finishGameMsg('YOU HAVE LOST YOUR SOUL', [finishOptionUndo,
                finishOptionRetry, finishOptionFullScore ]);
        } 
    ]
        whitePiece = (lexicalParent.whitePiece)
        redPiece = (lexicalParent.redPiece)
    }
    choosePiece(ptype)
    {
        local lst = new Vector(20);
        foreach(local obj in chessBoard.subSurface.contents)
            if(obj.ofKind(ptype) && obj not in (chessPiece, whiteSoul))
            lst.append(obj);
        
        if(lst.length == 0)
            return nil;
        local i = rand(lst.length) + 1;
        return lst[i];    
    }
    redPiece = nil
    whitePiece = nil
    attentionSpan = nil
    
    endConversation(actor, reason)
    {
        if(reason == endConvBye)
        {
            "<q>You're not going anywhere unless you win this game,</q> 
            the emperor tells you. ";
            return nil;
        }
        return inherited(actor, reason);
    }
;

++ AskTopic, StopEventList @emperor
    [
        '<q>Who are you?</q> you ask.\b
        <q>I am the ruler of this world,</q> he boasts, <q>all authority has
        been given to me, and all power is mine!</q>',
        
        '<q>You make big claims,</q> you remark.\b
        <q>I claim only what is mine!</q> the Emperor tells you. ',
        
        '<q>Why do you rule?</q> you ask him.\b
        <q>Because I am the Lord, and besides me there is no other!</q> the
        Emperor declares. '    
    ]   
;

++ AskTellTopic, StopEventList @tGame
    [
        '<q>What is the purpose of this game?</q> you inquire.\b
        <q>To decide which of us shall survive,</q> he replies. ',
        
        '<q>Why should I agree to play this game with you?</q> you wonder.\b
        <q>Because I command it, and you have no choice,</q> he tells you. ',
        
        '<q>What happens if I refuse to play?</q> you ask.\b
        <q>Then we shall spend the rest of eternity staring at each other,</q>
        he informs you. '
    ]
;

++ DefaultAskTellTopic
    "<q>Don't talk -- play!</q> the Emperor replies. "
;

++ DefaultGiveShowTopic
    "The Emperor is not remotely interested. "
;

++ CommandTopic @TopicActionBase
    "It doesn't make much sense to tell him to do that. "
    isConversational = nil
;


++ DefaultTCommandTopic
    "<q>Your majesty, is there any chance you might <<cmdPhrase>>?</q> you
    enquire.\b
    <q>No, none,</q> he replies coldly, <q>I take orders from no one, even when
    they're thinly disguised as requests.</q>"
;

++ DefaultAskForTopic
    "<q>Your majesty, could you possibly give me...</q> you begin.\b
    <q>No!</q> he growls, <q>You\'re my opponent -- I shall
    give you nothing, nothing at all!</q>"
;

+ emperorStone : HermitActorState
    specialDesc = "A stone statue of the Emperor sits in the red chair. "
    stateDesc = "He has turned to stone. "
    noResponse = "He's turned to stone; he can no longer hear you, and
        would be utterly unable to respond if he could. "
;

/* 
 *   The PlayerPresent is defined as a mix-in class for use with ActorState 
 *   objects to make takeTurn run only when the PC is present
 */  

class PlayerPresent : object
    takeTurn()
    {
        if(getActor.canSee(gPlayerChar))
            inherited;
    }
;

  /* 
   *   Normally the TADS 3 library allows the player to address only one NPC 
   *   at a time. During the chess game scene there are two NPCs present; the
   *   playerGroup CollectiveGroup is designed to allow both of them to be 
   *   addressed at once, with commands like:
   *
   *   >ASK CHESS PLAYERS ABOUT GAME
   *
   */


playerGroup: CollectiveGroup 'chess *players' 'players'
    isCollectiveAction(action, whichObj)
    {         
        return (action.baseActionClass is in (TalkToAction, AskAboutAction,
                                              TellAboutAction, AskForAction,  
                                              GiveToAction, ShowToAction));             
    }
    
    dobjFor(TalkTo)
    {
        verify() { }
        action() {
            foreach(local cur in players)
                if(gActor.canTalkTo(cur))
                nestedAction(TalkTo, cur);
        }
    }
    dobjFor(AskAbout)
    {
        preCond = []
        verify() { }
        action() {
            handleConversation(gActor, gTopic, askAboutConvType);
        }
    }  
    dobjFor(TellAbout)
    {
        preCond = []
        verify() { }
        action() {
            handleConversation(gActor, gTopic, tellAboutConvType);
        }
    }  
    dobjFor(AskFor)
    {
        preCond = []
        verify() { }
        action() {
            handleConversation(gActor, gTopic, askForConvType);
        }
    } 
    iobjFor(GiveTo)
    {
        preCond = []
        verify() { }
        action() {
            handleConversation(gActor, gTopic, giveConvType);
        }
    } 
    iobjFor(ShowTo)
    {
        preCond = []
        verify() { }
        action() {
            handleConversation(gActor, gTopic, showConvType);
        }
    } 
    canBeTalkedTo(talker, sense, info)
    {
        return players.indexWhich({x: talker.canTalkTo(x)}) != nil;
    }
    canSee(obj)
    {
        return players.indexWhich({x: x.canSee(obj)}) != nil;
    }
    communicationSenses = [sound]
    curState = self
    handleConversation(actor, topic, convType)
    {
        foreach(local cur in players)
        {
            if(gActor.canTalkTo(cur))
                cur.curState.handleConversation(actor, topic, convType);
        }
    }
    players { return getVisibleIndividuals(gActor.visibleInfoTable()); }
;