Cutscenes Part 5: Somewhere Above the City

From The DarkMod Wiki
Jump to navigationJump to search

Somewhere Above the City

I (Grayman) created SATC for the 2010 Summer Vertical Contest. Since it involved traversing a very long vertical distance up, I didn't want to ask the player to climb all the way back down. Instead, once the player has satisfied all objectives, a cutscene wraps up the storyline and ends the mission.

The Scene

The scene takes place in the Builder church, with two actors: a guard and a bishop discussing the outcome of the previous night's events. Without giving too much away, let's just say that a defrocked priest named Penshawk stirred up some trouble, and the mission was to deal with it.

Download and extract it into your Doom 3 folder. What you're getting is the set for the cutscene, the vocals, and a script to run everything. The map comes prebuilt, so you can run it out of the box.

Open in Dark Radiant.

The Opening

Dead or Alive?

Two Choices

There are two possible conversations in this cutscene. One if the player killed Penshawk, and another if the player knocked out Penshawk. SATC started the cutscene once the player had satisfied all objectives, and the decision as to which conversation to play was based on a check of Penshawk's health. Since Penshawk doesn't exist in Vault, the player decides which path to take at the start, by stepping on one of two floorpads. The one on the left plays the scene that goes with Penshawk's death. The one on the right plays the scene that goes with Penshawk's being knocked out.

Since both scenes are the same except for a few lines, we'll discuss the Dead scene. You can review the Alive scene afterward to see the differences.

Opening Shot

When you step on the leftmost floorpad, the script function playCutsceneDead() is called:

void playCutsceneDead()
   penshawkHealth = 0;

This sets a flag that says Penshawk is dead. SATC determined this at runtime using:

   penshawkHealth = $Penshawk2.getHealth(); // is Penshawk dead or unconscious?

This flag is checked later to pick the correct conversation.

playCutsceneDead() calls playCutscene(), so let's look at the latter's first few lines:

void playCutscene()
   // Fade to black, then fade back in

   $VaultTeleport4.activate($player1); // Move the player to the start of the vault cutscene
FadeOut and FadeIn

FadeOut and FadeIn are trigger_fade entities, and VaultTeleport4 is a func_teleporter.

So the screen fades out, waits 2 seconds, then fades in. When the screen is dark, you're teleported to where you can properly hear the sounds in the upcoming shot.

Let's look at the next set of lines, where we start the bishop--who's been waiting on a path_waitfortrigger, start the camera (VaultCamera3) and mover (anchor3) along their spline (spline3), and begin tracking a target_null sitting on the bishop's shoulders.

   // Camera3 - priest walking down hall, away from camera

   sys.trigger($VaultBishop); // get the Bishop started
   $VaultCamera3.activate($player1); // The camera takes over the view
   $anchor3.time(7);        // How many seconds it will take to move along the spline
   $anchor3.accelTime(0.1); // How long it takes to get up to speed
   $anchor3.decelTime(0.1); // How long it takes to decelerate
   $anchor3.disableSplineAngles(); // Allow the camera to point in different directions as it follows the spline
   $anchor3.startSpline($spline3); // Start the func_mover $anchor3 moving along the spline
   thread update_camera4();  // Call the function update_camera4() as a thread so it can run in parallel
                             // to update the camera's focal point each frame. We need to start this thread
                             // here, even before camera4 is active, because the target_null it's focused on
                             // will be moving when the priest starts walking. If we don't, then there's a
                             // hitch at the start of camera4's frames when it changes focus from where
                             // the target_null spawned, and where the priest has taken it.
   sys.waitFor($anchor3);    // Wait for $anchor3 to finish its movement

This presents an opening dolly shot rising from the floor as the bishop walks by, bound ... where? The picture shows VaultCamera3, with anchor3 and spline3 below it. Right behind it is VaultTeleport4, where we place the player.

The script line thread update_camera4() starts a separate thread (discussed in Roll Camera 6 in Part 2) to track the target_null attached to the bishop. We don't need that for VaultCamera3's shot, but we'll need it in the next shot. We have to kick it off early, otherwise the camera that points at it will have an abrupt hitch at the start of its view because the bishop has traversed almost all of the hall by then.

So the bishop walks by. Light streams from the windows, indicating it's daytime, and the city has survived to see another day. Barking dogs give a hint of life beyond the windows.

Turning Into the Archway


It's time to switch to the next camera, for a better view of the bishop turning into the archway. The picture shows, from top to bottom, target_setkeyval_4, VaultCamera4, anchor4, and spline4. VaultCamera4 is bound to anchor4, and we've already seen that target_setkeyval_4 was told to track the movement of target_null_4, attached to the bishop.

Here's the script that switches control to VaultCamera4:

   // Camera4 - priest turning into small doorway

   $VaultTeleport2.activate($player1); // Move the player so he can hear the priest's footsteps
   $VaultCamera4.activate($player1);   // Switch views
   $anchor4.time(2.5);                 // How many seconds it will take to move along the spline
   $anchor4.accelTime(0.1);            // How long it takes to get up to speed
   $anchor4.decelTime(0.1);            // How long it takes to decelerate
   $anchor4.disableSplineAngles();     // Allow the camera to point in different directions as it follows the spline
   $anchor4.startSpline($spline4);     // Start the func_mover $anchor4 moving along the spline
   sys.waitFor($anchor4);              // Wait for $anchor4 to finish its movement
   sys.killthread("aim_loop4");        // Kill the thread "aim_loop4"
   sys.wait(2.5);		       // No camera movement

The first thing that happens is we move the player to VaultTeleport2, which is closer to the action. This lets the player hear the bishop's footsteps as he passes from left to right.

Then VaultCamera4 takes over, and anchor4 is sent on its way along spline4's path. VaultCamera4 dollies from left to right, following the bishop into the archway, tracking his head as he walks.

Dolly for 2.5 seconds, then stop. Kill the "aim_loop4" thread (responsible for updating VaultCamera4 with target_null_4's position). Allow the camera to film for 2.5 more seconds w/o dollying.

The bishop walks off to the right.

The Staircase


Since the bishop left the previous shot to the right, we want to see him coming into the next shot from the left. He'll descend a staircase, left to right, filmed by a stationary camera above him, looking down.

The picture shows, from top to bottom, VaultCamera5, VaultTeleport3, and target_null_5.

Here's the small bit of script that controls this camera:

   // Camera5 - The priest on the stairs

   $VaultTeleport3.activate( $player1 ); // Move the player so he can hear the priest's footsteps
   $VaultCamera5.activate( $player1 );   // Switch views

The player moves to VaultTeleport3, where he'll hear the bishop moving left to right.

VaultCamera5 takes over and shoots for 8 seconds.

The Vault

This is the most complicated set of shots, involving the guard setting up the vault room by lighting candles, awaiting the bishop's arrival, and then talking with the bishop.

Lighting the Candles

A dollying camera shows the guard lighting two candles in anticipation of the bishop's arrival. There are two main actions occurring in this shot: the moving camera, and the guard following a path.


The picture shows, from left to right, target_setkeyval_6, VaultCamera6, anchor6, and spline6 (coincident with anchor6).


Here's the script that controls this camera:

   // Camera6 - the Guard

   sys.trigger($VaultGuard);           // get the guard moving
   $VaultTeleport1.activate($player1); // Move the player to the vault so he can hear the conversation
   $VaultCamera6.activate( $player1 ); // Switch views
   $anchor6.time(13);                  // How many seconds it will take to move along the spline
   $anchor6.accelTime(0.1);            // How long it takes to get up to speed
   $anchor6.decelTime(0.1);            // How long it takes to decelerate
   $anchor6.disableSplineAngles();     // Allow the camera to point in different directions as it follows the spline
   $anchor6.startSpline($spline6);     // Start the func_mover $anchor6 moving along the spline
   thread update_camera6();            // Call the function update_camera6() as a thread so it can run in parallel
   sys.wait(9.5);                      // guard lights candles

The first thing that happens is we trigger the guard to start him on his way. We want him moving when VaultCamera6 starts to film, so give him a second to get started.

Move the player to VaultTeleport1, directly over the lightning artifact in the alcove. This lets the player hear the conversation with the correct sound orientation.

Then VaultCamera6 takes over, and anchor6 is sent on its way along spline6's path. VaultCamera6 dollies from right to left, targetting the stationary target_null_6. Even though target_null_6 is not moving, we have to use a separate thread (update_camera6()) to reorient the camera each frame.

Though we've told anchor6 to travel for 13 seconds, we only show 9.5 seconds of VaultCamera6's view. This was determined through trial-and-error, stopping the shot at the moment the guard turns away from the rightmost candle.

The Guard

Lighting the Middle Candle

There are three candles at the front of the vault room, one on each wall to the left and right, and one in the middle. As this shot begins, the left candle is lit and the guard is walking to the middle candle.

The highlighted entities in the picture control the first half of the guard's actions. They are, from left to right:

  • path_corner_2 (where the guard waits to start the scene)
  • path_waitfortrigger_2 (telling the guard to wait)
  • trigger_once_entityname_4 (keyed to the guard, this calls the script function LightCandleMiddle())
  • path_corner_8 (where the guard stands and interacts with the middle candle)
  • path_interact_2 (tells the guard to play an interaction animation angled toward the middle candle)
  • path_wait_3 (provides a slight delay after lighting the candle before continuing on)

Not shown:

  • CandleMiddle (a light_candleflame_unlit that lights when frob-ignited)

We find LightCandleMiddle() in the script file:

void LightCandleMiddle()
   light_moving_ext lightObj = $CandleMiddle;

There are different ways of turning different types of lights on and off. This particular sequence works with the type of light used for the middle candle.

What we see when the guard starts on his path is:

  • He walks to a spot in front of the middle candle.
  • He turns and reaches out to the candle.
  • The candle lights up.
  • The guard retracts his hand and pauses.
Lighting the Right Candle

The entities (shown in the picture) for lighting the right candle are identical:

  • CandleRight (another light_candleflame_unlit)
  • trigger_once_entityname_3 (calls the script function LightCandleRight())
  • path_corner_7 (where the guard stands and interacts with the candle)
  • path_interact_3 (tells the guard to play an interaction animation angled toward the candle)
  • path_wait_1 (provides a slight delay after lighting the candle before continuing on)

After lighting the right candle and pausing, the guard steps to path_corner_3, where he awaits the bishop's arrival.

The Conversation

It's time to end the script and let the conversation take over. The remaining lines in the script are:

   // Start appropriate conversation in vault

   if (penshawkHealth <= 0)
      sys.trigger($atdm_target_startconversation_1); // dead
      sys.trigger($atdm_target_startconversation_2); // knocked out

   // Camera1 - at this point, the conversation takes control

   $VaultCamera1.activate($player1); // Camera1 - frontal shot of Guard and Bishop
   sys.killthread("aim_loop6");      // Kill the thread "aim_loop6"

The script:

  • checks Penshawk's health and (for this discussion) triggers atdm_target_startconversation_1, the "Dead" conversation
  • hands control to VaultCamera1
  • kills the "aim_loop6" thread, which was updating VaultCamera6 while the guard was busy with the lights

Several entities important to the conversation are in a small room off the back of the vault room.

The picture shows, from left to right (ignoring the light and the chest):

  • atdm_conversation_info_3 (holds the "KO" conversation)
  • atdm_conversation_info_2, (holds the "Dead" conversation)
  • atdm_target_startconversation_2, (starts the "KO" conversation)
  • atdm_target_startconversation_1, (starts the "Dead" conversation)
  • EndMission (a target_setobjective_state that satisfies the final objective to end the mission)
  • BishopLeaves (path_corner the bishop walks to after the conversation)
  • path_corner_1 (the final stop on the bishop's opening walk; he waits here until the conversation brings him into the vault room)

At this point, since we've covered the anatomy of a conversation in the previous discussions, you can bring up the Conversation Editor in the map and examine atdm_conversation_info_2's "Vault Conversation" to see the sequence of actions. Here is a set of pictures showing the cameras used, and their target_nulls. All entities previously discussed have been hidden to de-clutter the view.

  • VaultCamera1 is the main camera showing both actors
  • VaultCamera9 is a stationary shot of the lightning artifact
  • VaultCamera7 is a medium shot of the guard
  • VaultCamera8 is a medium shot of the bishop
  • VaultCamera10 is a shot of the bishop from behind the guard's shoulder
  • VaultCamera11 is a shot of the guard from across the bishop's chest
  • VaultCamera2 is the cutscene's final shot: a dolly shot closing in on the artifact
VaultCamera1 and target_null_1
VaultCamera9 and target_null_9
VaultCamera7 and target_null_7
VaultCamera8 and target_null_8
VaultCamera10 and target_null_8
VaultCamera11 and target_null_7
VaultCamera2 and target_null_2

Ending the Mission

The dialogue is complete. The bishop is leaving the room. The final camera shot is closing in on the returned artifact, representing closure, since the loss of this item triggered the mission.

The last instruction in the conversation is to trigger EndMission, which sets the final objective as "satisfied". In the case of this tutorial, this is the only objective. In SATC, it was the last in a series.

And, with that, we're finished.


In Part 5, we broke down the cutscene from the ending of Somewhere Above the City. Hopefully it provided a look at how to build a complex cutscene involving multiple cameras and a detailed conversation.

As was mentioned in the title page of this tutorial, you can leave comments and questions here.