Table of Contents |
Character Building > Pablo
Cortez
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 takeover scene ends. 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 Diablo's right-hand man,
<<only>> is standing by the main exit, hurrying the passengers off the
plane with the muzzle of his machine-pistol. "
checkAttackMsg = '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 Cortez 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 message that’s otherwise 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. "
checkAttackMsg = '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. "
checkAttackMsg = '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 == gPlayerChar && connector == cockpitDoor)
{
"Cortez looks round at you suspiciously as you head for the cockpit
door. <q>Hey, you, Pond!</q> 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]);
}
else if (traveler == gPlayerChar && connector == planeRear)
{
"Your makeshift disguise won't fool Cortez for long; it's best
to leave the plane as quickly as possible. ";
exit;
}
}
;
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’. Note also that we’ve taken the
opportunity to prevent the player character retreating to the rear of
the plane again once he’s encountered Cortez; this will prevent
potential problems with the AgendaItems we’re about to define next.
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 it 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 it 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
<q>Hey! You!</q> 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 also 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.
adv3Lite Library Tutorial
Table of Contents |
Character Building > Pablo
Cortez