Layout Systems & Objectives

Configure everything a Level Layout controls: spawn areas, objectives, blockers, squad spawns, stash rooms, spectator cameras and extraction zones.

Spawn Areas

Setting up spawns for a Level Layout is extremely simple! In the StartAreas variable, simply specify any areas that you wish to be a valid spawn location for this Level Layout. The system will pick 1 and spawn players there when the Level Layout is loaded.

The Area should have the following registered with it:

  • 4 × TangoPlayerStart_BP (the 4 Spawn points to use for players)
  • 1 × BP_InsertionZone (draws the spawn box on the Planning Screen)
A Spawn Area on the ModSample map.

Objectives

Setting up an Area for Objectives

Setting up an Area Manager to support the spawning of an objective is very simple! Add a BP_ObjectiveSpawner, set its ObjectiveClassto be whatever you are configuring, and then add the Area Manager’s Gameplay Tag to the Objective Spawner.

That’s it! Now, when the Area Manager is called on to spawn an Objective of that class, it will use any available BP_ObjectiveSpawnerwith the same Objective Class specified. You can check what Objective Classes your Area Manager supports by looking at the Area Manager’s Objectives component and seeing what Objective Spawners it has registered with it.

Setting up a Level Layout for Objectives

The following Objective Modes are valid for any RP Standard Level Layout:

  • Bomb
  • Hostage
  • Merc Hunt
  • Interception
  • Laptop

All Level Layouts by default support and use the following Objective Modes: Phone and Intel. (VIP and HVT are unused.)

All Level Layouts have an in-built PhoneComponent and an IntelComponent. This lets you specify which Areas in a level can spawn Merx Phones and Intel, for players to pick up and use as they progress through a campaign.

To configure other Objective Modes for a Level Layout, add the corresponding LayoutObjectiveComponent to that Level Layout — for example, adding a Hostage component to support the Hostage Objective Mode.

Setting up this Level Layout to support the Hostage Objective Mode.

The game/campaign system does not explicitly enforce any convention with what difficulties/Objective Modes should be supported, but here are the rules we generally follow in the stock RP maps:

  • Easy: Merx Hunt and Laptop
  • Medium: Hostage, Bomb and Interception
  • Hard: Hostage, Bomb and Laptop

Within an Objective Component, you can configure a few variables which control the spawning behavior for that Objective Mode. The ObjectiveGroupChances and ObjectiveGroups variables introduce the concept of a Random Group — see Random Roll in Section 02.

The variables within an Objective Component which control the spawning behavior for that Objective Mode.

Custom Objectives

Custom Objectives are used to create something a tiny bit more bespoke and interesting in your Level Layout. Some examples from Rogue Point missions include:

  • Assemble the Rogues at the Elevator on Oilrig
  • Destroy Merx supply caches on all the different levels
  • Find keycards to open special doors on Clinic

They are also used for the Objective Waves on Raid missions.

To create a Custom Objective, place a BP_CustomObjective Actor. The Custom Objective has a TArray of ObjectiveActors. These are Actors for which the Custom Objective will listen for a “completion” signal. Once it receives a completion signal from all of these Actors, the Custom Objective is completed.

It also has a TArray of OnCompletedActors. When the Custom Objective is completed, it will hit each of these Actors with an ISwitchable::TurnOn() event. This is an easily reusable way to have a Custom Objective open things up, unlock things, or achieve any positive effect you want on the level.

You can also pair the Custom Objective with a BP_RallyZone. The Rally Zone is simply a volume that requires all alive players to assemble inside it before it sends a completion signal.

Objective Squad

By default in RP, when an Area Manager spawns an objective, it will always set up and spawn its squad as well. This ensures you don’t get empty areas around an objective. This happens with Intel and Phones too.

Because of this, you can usually populate out an entire level’s worth of enemies, solely by setting up objectives and ensuring they are spread across the map well.

ObjectiveComponents have an additional variable, called InitialMercCounts. When a squad spawns an objective, it will augment the squad with some additional Merx, using the values defined within this variable. This is good because it means that squads by objectives will always be larger, regardless of randomness. For example: if any squad in the level is called on to spawn a Hostage, it will add 1 Soldier to its squad.

For each Laptop objective spawned at an Area by this Level Layout, the associated Squad will have 1 guaranteed Soldier added to its roster.

Merx that are added to the squad as part of this objective spawning pass are also assigned to “guard” the objective, though they will do so VERY loosely. This variable gives you control over how many additional Merx spawn, and the composition of them. By default we just add 1 Soldier per objective, and this is usually sufficient.

Blockers

Depending on how complex your map is, you might want to block off certain sections of it for a given Level Layout. This is controlled by the blockers system, which is handled via the LayoutBlockerComponent on the Level Layout and configured per-area using the AreaBlockerComponent on individual Area Managers.

Any Actor class can be configured to work with the Blocker system by implementing the IRandomizable interface. The event to implement is called RandomizeForGroupType(), and this will be called with an input of ERandomizationGroupType::Blockers.

By default, several Actor classes support being used as blockers:

  • Doors — the door in question will barricade itself (become unopenable)
  • Windows — the window in question will become unbreakable and take an opaque skin
  • Spawners — will spawn itself to block a path
A section of the map blocked off for a given Level Layout.

When the Level Layout tells an area to block itself, it will call out to all its associated blockable actors, and tell them to block themselves. You set this up by specifying the BlockerAreaGroupChances and the BlockerAreaGroups, which tells the Level Layout which Area Managers it should tell to block and how.

You can further filter on which blockers you want an area to call on if desired — for example, asking an Area Manager to block itself, but only calling on blocker actors with the ToRight Manager Group. Any actors owned by that area without that Manager Group will not block themselves.

In this example, we have asked the DarkBlue Area Manager to block itself, but only calling on blocker actors with the ToRight Manager Group.

You can also call on individual Actors to do blocking if you want. In some cases this is easier and more desirable than going via the Area system. For this, use the ActorGroupChances and ActorGroup variables. If the Actor supports blocking, it will do so.

Mesh Spawners

To make your life considerably easier when trying to spawn meshes to block for certain level layouts, we have provided 2 editor scripted actions for converting static meshes + volumes to a single spawner, and then the reverse. These are:

  • MeshesToSpawner
  • MeshSpawnerToActors

You can place down and configure as many static meshes as you want. Then select them all, right-click, and press “MeshesToSpawner”. This will bring up a window asking which class you want to convert the Actors to. These are the valid options (do not pick the other ones, they won’t work properly):

Select your static meshes, right-click, and press MeshesToSpawner.
  • BP_BlockerSpawner: Use this if you want to use the spawner with the blockers system.
  • BP_CoverSpawner: Use this if you want to use the spawner with the cover system.
  • BP_MeshSpawner: A generic mesh spawner, use this if you are trying to spawn a mesh on certain layouts outside of the official systems.
  • BP_StreamBlockerSpawner: Use this if you are using the spawner with the Streaming Level Manager and its associated logic.

Once the spawner has been created, you can give it the Gameplay Tag matching its parent Area and everything should work as-is.

You can also place down BP_BlockingVolume, and have as many of these as you want. This will incorporate the basic box collisions into the created spawner. You can select as many meshes and BP_BlockingVolumes as you need to create your single complex spawner — for example, a simple blocker spawner made from 1 block mesh and a blocking volume that prevents players from climbing/jumping over it.

A very simple blocker spawner, made from 1 single block mesh and a blocking volume that prevents players from climbing/jumping over it.

You can also convert the spawner back by using the “MeshSpawnerToActors” scripted action. This will convert a spawner back to its constituent StaticMeshActors and BP_BlockingVolumes. You can then rearrange/add/remove from these as needed!

Squad Spawns

The SquadGroupChances and SquadGroups variables let you configure areas/squads on the map which will be spawned. As mentioned in Objective Squad, the majority of your Merx will probably be spawned by proxy due to spawning with objectives.

However, this variable lets you go further than that if you want to! We don’t use it too much in stock RP, except where we want to fill out areas in non-objective areas, or to pad the level a bit.

SquadGroupChances and SquadGroups configure which areas/squads on the map will be spawned.

The SetupSquads variable is very rarely used. It is useful for setting up a squad ahead of time if you want to manually call on them to spawn in the level logic later. We only use this once in stock RP.

Stash Rooms

Stash Rooms are reasonably straightforward — but place as many of these in a map as you can! They are our core method for gearing players up within a mission.

To set one up, place a BP_StashRoomManager. A Stash Room Manager is basically just a specialized Area Manager. It behaves largely the same, but is just used slightly differently by the Level Layout.

Give it a Gameplay Tag, the same way as you would for an Area Manager, and then place down the different Station classes you want to associate with the Stash Room, and tag those too. These include:

  • BP_MedicalStation
  • BP_AmmoStation
  • BP_ReviveStation
  • BP_DeadDropStation (and its variants)
  • BP_ArmorStation
  • BP_CashStation (and its variants)

You also must register a BP_StashRoomDoor. A Stash Room can have as many Doors as you want. It will automatically act on all of them if called. There is also a variant of the Stash Room Door called BP_StashRoomDoor_Left, if you want it to open the opposite way. This is annoyingly needed because you cannot mirror a BP_StashRoomDoor — all the texts and widgets become mirrored if you do that.

When you have finished setting up a Stash Room and registering all its Actors, make sure you set up its RoomTypes variable. This lets you select what types of Room you want to support.

When the level is randomized, if the Level Layout selects the Stash Room, it will randomly select one of its RoomTypes and set it as its Chosen Type. It then selects a random cost based on the Chosen Type and locks the doors with the matching Phone requirement. It also activates the Stations associated with its RoomType, leaving everything else alone.

A Stash Room Manager with its registered Stations, Doors and RoomTypes.

Setting up a Level Layout to use a Stash Room is extremely simple. Simply configure the StashRooms variable. The Costs for the different Room Types are contained within BP_StashRoomManager. By default, a random value between Min+Max is chosen, and the difficulty value is added to it.

Setting up a Level Layout to use a Stash Room: configure the StashRooms variable.
The Costs for the different Room Types are contained within BP_StashRoomManager.

If a Stash Room is in the StashRoomsvariable, but it doesn’t get chosen by the Level Layout, the Level Layout will automatically block it so that it is not accessible by players (and this prevents players from leaving the level sometimes too).

Spectator Cameras

To place Spectator Cameras for an area, place a BP_SpectatorCamera and then assign the appropriate Gameplay Tag to register them with their Area Manager.

The Camera should also have its CameraText property set correctly, as this is shown to spectators so they know which camera they are looking through.

An Area’s cameras are “unlocked” by an Area Trigger, which uses the class BP_AreaTrigger.

The SpectatorCameras variable in the Area Manager is one of the few automatically registered variables that you can actually edit. We have set it this way so you can control the ordering if desired. The ordering in this variable is the order that the cameras will be shown to spectators. In RP, we try to keep the number of cameras per area to a minimum, usually about 3 at most.

A Spectator Camera registered to its Area via Gameplay Tag.

In the Level Layout, specify the Areas that you want to use the Spectator Cameras for. As with the SpectatorCameras in the Areas themselves, the ordering of the SpectatorAreas matters. It is the order in which they will be shown to Spectators.

In the Level Layout, specify the Areas that you want to use the Spectator Cameras for — the ordering matters.

For a SpectatorCamera, you can specify the ClampRotation, and a helpful editor visualizer will draw this for you. You can use this to stop the view of spectators clipping into walls/the ceiling. You might also want to configure the default rotation of the camera component so it is angled down slightly.

The ClampRotation visualizer helps you stop spectator views clipping into walls or the ceiling.

There is a second class of Spectator Camera that can be used, BP_SpectatorCamera01a. This camera has a full 360 field of view, so is only used in a few select areas where it makes sense.

BP_SpectatorCamera01a — a full 360 field of view, for the few areas where it makes sense.

Extraction Zones

All Level Layout types end at the Extraction Zone, which is BP_ExtractionZone. You can have multiple Extraction Zones active at once, but players can only extract from one of them.

An Extraction Zone with its Box Component and spline ribbon.

Basic Setup

An Extraction Zone comes with a Box Component, which by default is used to determine whether players are inside the Zone. You can optionally place a TangoExtractionVolumeActor to use a BSP volume with a more complex shape for this purpose. Shape the volume as needed using the BSP tools, and then set the Extraction Zone’s BrushCollision property.

The Box Component is also used to draw the Extraction Zone box on the Planning Screen. Due to technical limitations, the BSP volume cannot be used for this purpose, so even if you have a weirdly shaped BSP volume, try to fit the box in as best you can.

A Spline Component is used to define the ribbon around the edge of the Zone. It is automatically calculated against the bounds of the Box Component. You can untick bAutoSplinePoints to circumvent this behavior and define the spline yourself.

There are several TSet variables: ActivatedActors, PrimedActors & ExtractionBeginActors. These point to Actors in the level. When the Extraction Zone is switched into the corresponding state, it will call the corresponding event via the IExtractionZone interface on these Actors:

  • ExtractionZoneActive: An Extraction Zone is Active when it has been chosen by the Level Layout to be used for this run.
  • ExtractionZonePrimed:This is the state where the Zone is “open” for business, and is waiting for the team to assemble and press the button to begin Extraction. It happens after all the mission objectives are completed.
  • ExtractionBegun: Fairly self-explanatory, this is triggered when the players finally call in an Extraction by pressing the button.

By default, this is only really used with Doors and Stations:

  • For Doors, ExtractionZoneActive will barricade the door. ExtractionBegun will blow it up, allowing Merx through it. You can use this to set up “spawn closets” for them.
  • For Stations, ExtractionZoneActive will configure the Station to display a tablet informing players that it will activate when Extraction is enabled. ExtractionZonePrimed will open the Stations.

Extraction Wave Setup

Extraction Waves are called when players begin the Extraction sequence. They are configured on the Extraction Zone’s ExtractionWaveComponent. Because Extraction Zones can be shared across many different Level Layouts and used in many different ways, they offer some useful presets to allow you to configure them more easily.

Presets are defined in the TMap variable WavePresets. You can add as many named Presets as you want, though you probably don’t want too many, or it might get confusing to work with. A preset can point at:

  • SingleSquad: Does what it says on the tin, just dumbly targets one Squad.
  • RolledSquads: Allows you to define a Random Roll for any number of Squads.
  • CustomAll: If you want to get really granular, you can define a custom Squad Role for every Squad specified using this.

The variables EasyWaves, MediumWaves, and HardWaves let you define the structure of the Extraction Waves per difficulty. By default, when the end of the array of waves is reached, it loops back around to the beginning.

Wave Presets and the per-difficulty EasyWaves / MediumWaves / HardWaves arrays.

You can use the LayoutWaves variable to create a set of Waves for a specific Level Layout, if you want to get that granular.

Extraction Wave Spawning

When the Extraction Waves are being spawned, the game does LOS and proximity checks to exclude any spawners that would be egregious for players. These checks are quite loose, so you can still get bad spawns.

Enemies are spawned in Last Rushmode, so always know the players’ locations and will always run at them.