Pablo Cortez — A Man with Several Agendas

The second NPC we'll implement is Pablo Cortez, El Diablo's right-hand man and the man whose threatening presence obliges our protagonist to sneak off the plane pretending to be a cleaner. He only really needs to be present during one scene, but during that scene he does need to be something of a menacing presence.

Cortez needs to be moved on-stage, to the front of the plane, at the start of the takeover scene, and moved off again when the takoever scene happens. During the takeover scene he'll make some remarks that the player character will overhear. If the player character attempts to enter the cockpit, or hangs around too long, while Cortez can see him, Cortez will shoot him.

We start by defining the basic Actor object as before:

cortez: Actor 'Pablo Cortez; evil latinate;man;him'
    "He's really quite a handsome man, in a latinate sort of way; if you met him
    in a different context you might not realize quite what an evil devil he
    actually is. "
    
    actorSpecialDesc = "Pablo Cortez<<first time>>, El Diabo's right-hand man,
        <<only>> is standing by the main exit, hurrying the passengers off the
        plane with muzzle of his machine-pistol. "
    
    shouldNotAttackMsg = 'You know better than to attempt it; he\'s known to be
        quite deadly with that gun. '
        
;

The only novelty here is the use of the <<first time>>...<<only>> construct to ensure that the explanation that Cortex is El Diablo's right-hand man only appears the first time the actorSpecialDesc is displayed.

Since the actorSpecialDesc rather pointedly mentions the gun Cortez is holding, we should implement it as a separate object. To give an Actor possessions that they're notionally carrying, we simply locate the object or objects in question directly in the Actor object, and while we're at it we'll customize the otherwise the message that's shown when the player character attempts to take another actor's possessions to something a bit less bland than the library default:

cortez: Actor 'Pablo Cortez; evil latinate;man;him'
    "He's really quite a handsome man, in a latinate sort of way; if you met him
    in a different context you might not realize quite what an evil devil he
    actually is. "
    
    actorSpecialDesc = "Pablo Cortez<<first time>>, El Diabo's right-hand man,
        <<only>> is standing by the main exit, hurrying the passengers off the
        plane with muzzle of his machine-pistol. "
    
    shouldNotAttackMsg = 'You know better than to attempt it; he\'s known to be
        quite deadly with that gun. '
    
    cannotTakeFromActorMsg(obj)
    {
        return 'Cortez would shoot you dead before your hands got anywhere near
            it. ';
    }
;

+ gun: Thing 'gun; machine 93r beretta; pistol machine-pistol'
    "It's a Beretta 93R, capable of firing at a rate of more than a thousand
    rounds per minute. "
;

To make Cortez shoot the player character if he tries to enter the cockpit we can use a beforeTravel() notification on the Actor object. Although we could use the beforeTravel() method in this case, we'll use actorBeforeTravel(), again for reasons that will become clearer when we come to look at ActorStates:

cortez: Actor 'Pablo Cortez; evil latinate;man;him'
    "He's really quite a handsome man, in a latinate sort of way; if you met him
    in a different context you might not realize quite what an evil devil he
    actually is. "
    
    actorSpecialDesc = "Pablo Cortez<<first time>>, El Diabo's right-hand man,
        <<only>> is standing by the main exit, hurrying the passengers off the
        plane with muzzle of his machine-pistol. "
    
    shouldNotAttackMsg = 'You know better than to attempt it; he\'s known to be
        quite deadly with that gun. '
    
    cannotTakeFromActorMsg(obj)
    {
        return 'Cortez would shoot you dead before your hands got anywhere near
            it. ';
    }
    
    actorBeforeTravel(traveler, connector)
    {
        if(traveler == me && connector == cockpitDoor)
        {
            "Cortez looks round at you suspiciously as you head for the cockpit
            door. Hey, you, Pond! he shouts. As you make a dash for the
            door he opens fire with his machine pistol, riddling your body with
            bullets. ";
            finishGameMsg(ftDeath, [finishOptionUndo]);
        }
    }
;

Note the use of the finishGameMsg(ftDeath,...) to kill the player character. We supply [finishOptionUndo] as the second parameter to allow the player to undo the fatal move. Note too that since we defined the first part of the vocab property as 'Pablo Cortez', with every word starting with a capital letter, the library will recognize it as a proper name and so refer to the actor as 'Pablo Cortez' not 'the Pablo Cortez' or 'a Pablo Cortez'.

The cortez Actor object is beginning to look a bit complicated, but this is as complicated as it needs to get. To implement the rest of Cortez's behaviour we'll use AgendaItems.

An AgendaItem is an object that can be used to define what an Actor does when a certain condition is met. An AgendaItem is considered for execution when its isReady property becomes true. When that happens, its invokeItem() method is called. Its invokeItem() method will continue to be executed every turn until the AgendaItem's isDone property becomes true, so if you want an AgendaItem to execute only once, make sure that it sets isDone = true in its invokeItem() method. But to be considered for execution at all an AgendaItem must be in its actor's agendaList. To put it there you can either call addToAgenda(item) on the actor object, where item is the AgendaItem in question, or define initiallyActive = true on the AgendaItem to have it included in the actor's agendaList at the start of the game.

An AgendaItem is associated with its actor by being located in its actor, usually with the + syntax.

As a first example, we'll use an AgendaItem to move Pablo Cortez to the front of the plane when the takeover scene starts. The following code should be placed immediately after the definition of the gun object:

+ cortezArrivalAgenda: AgendaItem
    initiallyActive = true
    isReady = (takeover.isHappening)
    
    invokeItem()
    {
        isDone = true;
        getActor.moveInto(planeFront);
    }
;

Note the use of getActor within the invokeItem() method to get a reference to the actor this AgendaItem belongs to. We could have written cortez.moveInto(planeFront), but it's better practice to use getActor in case, for example, you later decided to change the name of the cortez object. Note too the use of isDone = true at the start of the invokeItem() method (it could equally well have come at the end, of course) to ensure this AgendaItem only fires once.

You may be thinking it would have been simpler to have moved the cortez object to the front of the plane in the whenStarting() method of the takeover scene. We certainly could have done that way, and it may even have been better. It's a matter of taste and opinion whether it's preferable to keep all the Scene-related code with the Scene, or all the Actor-related code with the Actor. Here we're doing in the latter way mainly to illustrate the use of AgendaItems.

The next thing we want Cortez to do is to make some remarks in the player character's hearing. Again, we can use an AgendaItem to accomplish this, setting its isReady property to become true once the player is in the front of the plane. But we don't want this AgendaItem to fire until Cortez is also in the front of the plane. There are several ways we could arrange this, but the one we'll use here is to hold off adding our second AgendaItem to Cortez's agendaList until the first one is invoked:

+ cortezArrivalAgenda: AgendaItem
    initiallyActive = true
    isReady = (takeover.isHappening)
    
    invokeItem()
    {
        isDone = true;
        getActor.moveInto(planeFront);
        getActor.addToAgenda(cortezTalkingAgenda);
    }
;

+ cortezTalkingAgenda: AgendaItem
    isReady = (me.isIn(planeFront))
    
    invokeItem()
    {
        isDone = true;
        "<q>Hurry up! Get off this plane! El Diablo is not a patient man and he
        needs it for important business!</q> you hear Cortez tell the
        passengers. <q>If the plane is not cleared by the time our pilot arrives
        I shall shoot any of you who are still aboard! Now, move, move!</q> ";
    }
;

Note the use of getActor.addToAgenda(cortezTalkingAgenda) to add the cortezTalkingAgenda AgendaItem to Cortez's agenda.

Let's say that if the player character hangs around for more than another two turns, Cortez will spot him and instantly shoot him. For that we can use a special kind of AgendaItem called a DelayedAgendaItem. To set the delay of a DelayedAgendaItem we can add it to its actor's agenda and call its setDelay() method at the same time as adding to its actor's agendaList with a statement like getActor.addToAgenda(item.setDelay(turns)). In the case of this DelayedAgendaItem we must also make sure that the player is still around to be shot:

+ cortezTalkingAgenda: AgendaItem
    isReady = (me.isIn(planeFront))
    
    invokeItem()
    {
        isDone = true;
        "<q>Hurry up! Get off this plane! El Diablo is not a patient man and he
        needs it for important business!</q> you hear Cortez tell the
        passengers. <q>If the plane is not cleared by the time our pilot arrives
        I shall shoot any of you who are still aboard! Now, move, move!</q> ";
        
        getActor.addToAgenda(cortezShootingAgenda.setDelay(2));
    }
;

+ cortezShootingAgenda: DelayedAgendaItem
    invokeItem()
    {
        isDone = true;
        if(me.isIn(planeFront))
        {
            "Cortez suddenly looks your way. For a split-second he seems frozen
            with astonishment, but only for a split-second.\b
            Hey! You! he cries. A moment later he raises his machine
            pistol and fires into your belly at point-blank range. ";
            finishGameMsg(ftDeath, [finishOptionUndo]);
        }
        else
            getActor.moveInto(nil);                
    }
;

You may be wondering about that getActor.moveInto(nil) in the else clause of cortezShootingAgenda.invokeItem(). Here we're simply saving ourselves the additional AgendaItem that would otherwise be needed to move Cortez off-stage again at the end of the takeover scene. If the player character isn't around to be shot when the cortezShootingAgenda is invoked, that must mean he's left the plane, and since he can't get back aboard the plane again until he's put on the pilot's uniform and so brought the takeover scene to an end, we might as well remove Cortez right away. Although we're moving him offstage altogether, presumably he notionally moves to the rear of the plane to take a seat among his pals and buddies.

You may already be wondering about the lack of an isReady property on cortezShootingAgenda. That's because it's already defined on the DelayedAgendaClass; it's defined so that a DelayedAgendaItem becomes ready when the delay specified in its setDelay() method has passed.

We'll see some more examples of AgendaItems in our implementation of the flight attendant. In the meantime if you want the full story about AgendaItems, you can read about them in the adv3Lite Library Manual.