Population: One Advanced Rules Editor – BigBox VR

Overview

The advanced rules editor is a tool for defining custom game modes in Population: One Sandbox. It is not a full visual programming interface, but it does utilize some basic programming concepts, such as functions, if/else blocks, and variables. Utilizing the example maps BigBox has provided, it should be possible to learn and work in the tool without any prior programming experience.

How to Access the Advanced Editor

In Sandbox builder mode, select Edit Rules on the Play tab. On the Custom Rules edit panel, there is a toggle for enabling advanced mode. When that is ON, the "Event Editor" button appears on the Play tab and will take you to the Advanced Editor.

You also now have the ability to save and load rulesets using the Rules Library. This allows you to transfer rules between maps easily, which is a good way to apply an example game’s rules to your map.

Main Tabs

Events

Events are the heart of the rules system and define everything that will happen in your game. Each event has a trigger type, i.e. OnKillEnemy, which defines when it happens.. Events use a system of selecting an object (or objects) to operate on, such as players, and then running a set of actions for the selected object(s). They support some simple script-like concepts such as conditions with else cases, and functions, which are just events that use a function trigger type.

Variables

This tab is where you can define variables, which allow you to store values you might need to retrieve later. Variables can be numbers, objects (such as players), or lists of objects. There are many predefined variables that the editor provides access to, but you may find you need to track other things in your game, and defining variables is how you would do that.

Roles

Roles are ways of changing the stats/behaviors of a player in your game. For example, if you were making an infected game type, you could define a Zombie role and a Survivor role, and then assign them to players on match setup and as Survivors are killed.

Buffs

Buffs are temporary or permanent boosts to a player’s stats and abilities. There is some overlap with roles, but the usage is different. For example, you could define a buff that gives a 30% speed boost for 30 seconds, and award that on kill to give players a bit of momentum.

Events in Detail

Triggers

Triggers define when your event is going to happen. Each trigger can contain objects and variables you can reference in your actions and conditions, such as a player who caused the trigger to happen, or an item ID of a loot that was collected. Variables from a trigger will be available under Event in the variable source selection field. Some triggers also include a location of where the triggering action happened. Some triggers, like OnMatchSetup would contain none of these things. The actions available in an event will vary depending on the properties of the trigger. Current list of triggers can be found in the appendix section.

Selection

Selection is how you decide what objects are going to be affected by your actions inside of an event. Some selections allow you to select multiple objects (for example, AllPlayers), which will run your actions for each one in a loop. You can also add new Action Groups in the action section of your event to allow you to change the selection and run some actions on a different object. The available actions inside your event will change based on your current selection. Available selection options are detailed in the appendix.

Conditions

Conditions allow you to enter checks that must be passed before actions will be run. Each condition consists of two expressions, and a comparator. You can group multiple conditions together by indenting all but the first one you would like in a group. For example, if you had a complicated condition where you wanted something to happen if (A and B) or (C and D) was true, you would do this by indenting condition B and D.

Comparisons of both numeric values and object values are supported. When checking an object value, you can compare it to null, which is available under the global variables, to check if the value is not set.

Actions

Actions are how you can make things happen in the game. The actions you will have available to you will depend on the currently selected object. The available actions are detailed in the appendix.

Action Groups

An Action Group allows you to change your Selection, and add new conditions around some actions inside of an event. An example of this is when setting up a match, you might want to add all control points to a list, sort that list, and then activate one control point. You could accomplish this by having multiple MatchSetup events with different Selection types (All Control Points, None, Range From List), which will execute from top to bottom in your event list, or you can put them all in one event using None as your first selection, and adding an All Control Points action group, and a Range From List action group. Both methods are viable, but Action Groups can be a nice way to organize your actions into one view. They can be collapsed and labeled with a comment to help keep the view clean as your events become more complicated.

Expressions

An Expression is a concept that can be evaluated to either a numerical value, or a specific object. You will come across the Expression Editor in all Conditions (they all compare one Expression to another), as well as some Actions and Selections. The format in all cases is the same. The types of expressions you can use are as follows:

Variables in Detail

General

Variables provide a way to store and access values. You can define new variables on the Variables tab of the Advanced Editor. There are many predefined properties you can access as variables in Expressions, along with variables you define yourself. You can only modify values of user defined variables with the SetVariable and AddVariable actions.

Scope

Each variable has a scope associated with it, which defines who owns a variable. Variable names will be shown color coded according to their scope.

Type

Variables can be one of 3 types:

Roles in Detail

General

Roles are how you can differentiate players in a game. The common example would be in an infected game type, some players might be Zombies, and others would be Survivors. Roles allow you to override default stats such as health, armor, movement speed, and other player properties.

Avatar

With the avatar selection, you can force a role to use specific skins. In general, you should avoid doing this for most players, as they will want to wear the skin they have selected, but there may be reasons to do this for certain special roles in your game type. Checking the Fallback box next to the avatar will mean that this skin is only used if the skin the player is wearing is in use by another role in your game, to avoid confusion with the special skin.

Perks

Perks are a series of checkboxes you can toggle on for your role. They offer some game changing properties, such as locking a role’s inventory, so they can not drop or pick up items, the ability to see the player’s outline and minimap waypoint for enemies, and others.

Gear

Gear allows you to specify the starting equipment of a role. When a player changes role, via the set role command, their inventory will be cleared, and set to the gear in the role. When specifying a gun, the count value in the gear entry is the ammo they will start with.

Buffs in Detail

General

Buffs are player-focused stat modifiers that can be applied when specific gameplay events are triggered. They can be permanent, meaning they last for the entire match, or on a timer of a set duration. Buffs can also be stackable, meaning if the same buff is applied to a player multiple times, the value of the modifier that the buff sets can be updated with each level. There is a static list of buffs in Game Rules data that are available in any mode, and any buffs created through the advanced rules editor will be available in that specific mode. Buffs can be applied to players by game actions defined on the Events tab of the advanced rules editor using the ApplyBuff action.

Name

This is the name that will appear on the dropdown of available buffs to select on the ApplyBuff action on the Events tab of the advanced rules editor.

Duration

The Duration of a buff defines how many seconds the buff will last before expiring. If this value is set to 0 or a negative number, the buff will be permanent, meaning it will remain in effect until the end of the match.

Max Stack Count

This value defines how many times the buff can stack. The default value is 1, meaning the buff is only ever applied or refreshed as-is. If this value is greater than 1, then there will be multiple value fields present for each buff effect. When the player earns an additional stack of the buff, the value of the effect will be bumped up to the next value in that list. In the case of timed buffs, having the buff re-applied will increment the value and refresh the buff timer.

Permanent

If this toggle is enabled, the buff will have no duration, and will persist for the entire match after it is applied once.

Exclusive

If this toggle is enabled, the buff will remove any other currently active buffs from the player when it is applied. It will also prevent other buffs from being applied on top of it until it expires. If a buff is permanent and exclusive, there is no way to remove it after it has been applied until the end of the match, unless another exclusive buff is applied to the player to replace it.

Icon

This dropdown pulls entries from a static list of buff icons in the game rules data. The option selected will reflect the buff on the in-game UI on the player’s HUD, displayed over the timer.

Icon Color

You can enter a hex color here to tint the icon of the buff UI. The default is white.

Background Color

You can enter a hex color here to tint the timer background behind the icon of the buff UI. For permanent buffs, this will be a solid circle. The default is black.

Type

The type of the buff defines the actual buff behavior, e.g. what effects it has on the player to whom the buff was applied. There are several options on this dropdown, and a buff can have multiple types if additional buff effects are added using the button at the bottom of this tab. See the appendix section for details of the various buff types.

Example Tutorials

These tutorials are a great way to get started using and understanding the Advanced Editor. We recommend going through them in order to get a solid foundation that will allow you to start creating your own unique games in Population: One Sandbox.

Example 1: Hello World (Beginner)

This example will show you how to set up a simple trigger to show a message to a player when they walk through it.

Part 1: Displaying a Toast

To start, make a new map and set the game type to Hangout.

Hangout Mode gives us a blank slate as it starts with no events defined in the rules.

In the scene, place two flight rings. I’ve added a number over them to differentiate them. Select flight ring 1 with the Edit Tool and set the TriggerID to 1 in its properties. Leave the ID for ring 2 set to the default of 0. This will allow us to differentiate between the rings in our events.

Now, bring up the Advanced Editor by selecting Edit Rules on the sandbox Play tab, enabling the Advanced Editor toggle, and hitting the Events button.

This will bring up the Advanced Editor, with an empty event panel. Press the Add Event button to create an event, and this is what you should see.

Click on the newly created event to open the event edit view.

The event will have some default values selected. This default event would trigger when an enemy is killed. It selects the killer, and adds 0 to their score. Not super useful, but we can improve it.

The two things we need to do are:

  1. Change the trigger type from “Kill Enemy” to “Flight Ring Triggered”
  2. Change the Action type from “Add Score” to “Show Toast”.

The Show Toast action allows us to enter a message, so enter “Hello World” in the bottom right field. Ignore the bottom left field for now, we’ll come back to that later.

We can now save our map and test our game from the sandbox play panel.

When we walk through either flight ring we will see this message appear:

Now, let’s use the TriggerID to make flight rings 1 and 2 do different things…

Part 2: Conditions

Back in our event, hit the Add Condition button above our Show Toast action to let us add a check before we show this toast.

The default condition is not what we want, so select the first field to bring up the expression editor.

We want to check the TriggerID from the flight ring, which is available under the event selection in the source dropdown on the left. Once that is selected, close the expression editor.

In our object set up, we set the TriggerID on our first flight ring to 1, so we want to change the comparison value to 1 from the default of 0.

Our final event should look like this. If we enter play mode again, we will now only see the “Hello World” message when we walk through flight ring 1.

Part 3: Hello User

Now, let’s add a second event to show a different message. For this example, I’ll show a different way to trigger an event from a flight ring.

Create a second event, and set it up as follows:

  1. Trigger is TriggerFunction
  2. Name the event “MESSAGE2”
  3. Set the Action to “Show Toast”, and enter “HELLO ##”
    • Tip: Adding the characters ## in your message allows you to display the chosen expression value in the text (we’ll set this up to be the player’s name).

Now set the action expression to “SelectedObject.Object” to get the triggering player’s name.

Test your game again and now when we pass through our two flight rings, we’ll get the following toasts depending on which ring you pass through!

Example 2: Revenge (Intermediate)

In this example, we are going to add a new rule to the existing TDM game type. The mechanic is that when you get killed, we will track the player that last killed you. If you get a kill on the player who last killed you, you will get a Revenge message, and 2 points instead of the usual 1 point.

To start, either create a new TDM map with one of the template sandbox maps, or load an existing map.

You should see these 2 events in the advanced editor if your game is using the deathmatch rules. The first thing we need to do is add a variable to track the player who last killed a player.

To do this, go to the Variables tab, and add a new variable. We need to set the following:

  1. The Scope should be “Individual”, because we want each player in the game to have a copy of the variable so they can independently track their last killer.
  2. The Type should be “Object”, because it needs to contain a single in-game object.
  3. The Object Type is “Player”, because we want the variable to contain a player.
  4. Name your variable LASTKILLER or something similar to convey its purpose.

Now go back to the Events tab, and open the KillEnemy event. By default, it looks like this.

All it does is when an enemy is killed, select the Killer, and add 1 point. We need to add a couple things to this event.

First, add a condition with the +Condition button, to check if the victim is the killer’s LastKiller. It will look like this:

Then:

  1. Change our Action to add 2 points instead of 1.
  2. Click “+ Action” and set the new Action to “Show Toast” to show a revenge message.
  3. Click “+ Action” again to clear the LASTKILLER variable, by setting it to null, which can be found under Global variables in the expression editor. This will prevent you from getting revenge multiple times. It is important to know that the SetVariable action is setting the selected object’s instance of the variable for variables with an Individual scope.

Next, we want an else case to add 1 point in the case that you kill any other player.

Use the +ELSE CASE button, and add an action as follows:

Now, we need to add the action to track your last killer.

To do this, go back to the events panel, and add a new event. We want the trigger to be “KillEnemy”, but this time we want to select the Victim, as we want to set their LASTKILLER variable to track the player that kills them. That event will look like this:

One more thing we can do is set LASTKILLER to null in the suicide event, so you can’t get revenge after a self kill.

Edit the existing suicide event and add a SetVariable action and set the Dead Player’s LASTKILLER to the global value Null.

Now, go back to the sandbox panel and save your game, and on the play tab, you can spawn some bots to test your game with you. You should see that after one kills you, you then get 2 points and a revenge toast when you respawn and kill them.

Example 3: Moving Capture Point (Advanced)

The Headquarters Example map is a good place to look to understand how to manipulate control points, and use list variables. The basics of the game mode are as follows:

We want to make sure that almost all the control points get used before any get reused. We will achieve this by using an object list variable to track control points that have yet to be used, and refill it when it’s down to 1 left.

This example doesn’t go step by step on how to set up this mode, but does go into detail about the events involved, and how they work.

Here’s how you will want to set your control point properties for this mode. The HoldTickRate of 5 will allow us to score for holding a control point every 5 seconds. Turning off AllowRecapture will make the control point deactivate when it is captured a second time. Setting the max active time and max hold time will make the control point deactivate if it isn’t captured for the selected time (max active) or once it has been held for a certain time (max held). Be sure to give each control point a unique ID, starting with A, so they display nicely in the UI.

For game settings, we want a winning score, and a time limit to ensure the game ends in a reasonable amount of time.

In the event editor, we want to make a global ObjectList variable of control points. We will use this to keep track of unused control points to ensure we don’t reactivate previously used ones.

The bulk of the game logic is handled inside a global function event called SelectPoint. This function has 2 steps. First we want to fill the list Points if the size is less than 2. Then we want to select the best control point in the list and activate it. We consider the best control point a random one that doesn’t have a player within a certain distance, and if no points meet that condition, then the one with the greatest distance to the nearest player.

We use an action group for the refill list check because there are actions we want to run after this condition check, regardless of the outcome. If we added conditions to the top level action group, then we can not place actions outside that condition check.

If the list is nearly empty, then we use another nested action group to select all control points and add them to the list.

We need a second action group because we want to change our selection from None to All Control Points. If you put All Control Points in the first selection, where None is, it would run the points.Size check once for every control point, and you would only wind up adding the first 2 points to the list.

The entire action group can be collapsed to avoid clutter, and has the comment Fill If Empty to remind you what the group is doing.

The next thing we want to do is find a control point in the list where there isn’t a player within a certain distance of the point. To do this, we make a new ActionGroup and use the selection ObjectFromList. Specify the count of 1, as we only want one control point, and we add a selection condition, where SelectedObject.ClosestPlayerDistance greater than 20. What this does is look through all the control points in the list Points, find all the ones where the closest player is at least 20 meters away, and then select one of those points randomly.

Now, we need to check if we have a point selected, as it is possible that all the points in the list have a player standing within 20 meters of them. To do this, we add a condition if SelectedObject.Object is not null. This will be true if our selection found a valid control point, and false if not.

If we have a point, then we want to activate it with ActivateControlPoint, and remove it from the list Points, so that it won’t be selected again until the list gets refilled. The value used in ActivateControlPoint, 20 in this case, is a delay time, so the control point will show a visible timer and be capturable in 20 seconds.

Now, we need to add an else case to handle the case where there was no selected control point above. To do this, we are going to sort our Points list by closest player distance descending, so that the highest value is in the front of the list. Then with a new action group, we select the first point in the list using RangeFromList with a start index of 0, and a count of 1, and then do the same ActivateControlPoint and RemoveFromList we did above.

Now, we can take care of the other events we need in our game. On MatchSetup, we want to go through all the control points and add them to the Points list, and deactivate them, so they are not visible or capturable in the world. Then, we want to use CallFunction to call our SelectPoint function to activate the first control point. This is the contents of our MatchSetup event:

When a control point is captured, we want to give the owning team some points. We do this with a ControlPointCaptured event, select the owning team, and use AddScore to give them 10 points.

Similarly, while a control point is held by a team, we want them to earn 5 points each tick, which we set to every 5 seconds in the control point properties.

The last thing we need to do is select a new control point once one becomes inactive. To do this, we use a ControlPointDeactivated event, and simply call our SelectPoint function. ControlPointDeactivated will get called whenever a control point turns off due to having a maxHoldTime or maxActiveTime set.

Tips and Tricks

Score, Time and Rounds: It is important to understand how Population One treats these concepts.

Appendix

Triggers

These are the currently supported event triggers.

Selection

These are the currently supported selection options.

Actions

These are the available actions you can perform in your events.

Buff Types

These are the buff types available in the editor.