Trigger regions

## Introduction

 Trigger Regions were introduced in Omni-bot version 0.7 as a method to allow for scripting when specific entities enter and leave user defined regions. The functionality effectively reduces the bots dependency on map events. Map scripts can be set up to enable or disable goals based on a movers position or if a client enters a defined region for example.

There are two types of Trigger Regions; Vector3 and AABB (axis aligned bounding box). Vector3 regions are defined by map position and radius while AABB regions are obviously defined by an AABB. Vector3 regions are spherical while AABB triggers are boxes. The following picture shows both types of trigger regions as rendered with the command **/bot drawtriggers**. Vector3 is on the left and AABB is on the right:

Vector3 region triggers are activated when center point of entity is inside the sphere. The center point is sometimes not same as entity origin.

AABB region triggers are activated when bounding box of entity intersects the region. The bounding box can be bigger than entity.

## Defining the Regions

The OnTriggerRegion function is used to define the trigger region. The parameters for the function differ depending on the type of region trigger being set up:

```
 vectorTrigger = OnTriggerRegion(<Vector3>,<radius>,<infotable>);
 aabbTrigger = OnTriggerRegion(<AABB>,<infotable>);

```

### Vector3

The syntax for setting up a Vector3 Region Trigger:

```
 triggerInfo =
 {
 Name="TestTrigger",
 TriggerOnClass=CLASS.ANYPLAYER,
 OnEnter = function(ent)
 {
 Util.MapDebugPrint(GetEntName(ent) + " entered vector3 trigger", true);
 },
 OnExit = function(ent)
 {
 Util.MapDebugPrint(GetEntName(ent) + " exited vector3 trigger", true);
 },
 };
 OnTriggerRegion(Vector3(0,0,0),256,triggerInfo);

```

### AABB

The syntax for setting up an AABB Region Trigger:

```
 triggerInfo =
 {
 Name="TestTrigger",
 TriggerOnClass=CLASS.ANYPLAYER,
 OnEnter = function(ent)
 {
 Util.MapDebugPrint(GetEntName(ent) + " entered aabb trigger", true);
 },
 OnExit = function(ent)
 {
 Util.MapDebugPrint(GetEntName(ent) + " exited aabb trigger", true);
 },
 };
 OnTriggerRegion(AABB(0,0,0,0,0,0),triggerInfo);

```

#### Finding the AABB

The command **/bot trigger\_bounds** can be used to easily find an AABB. Issue the command at the location you want to start, then move around to expand the region:

When finished sizing the AABB, issue the command **/bot trigger\_bounds** again. This will create a temporary AABB Region Trigger and give the value in console. Copy the value of the AABB from the console to your OnTriggerRegion function call.

#### AABB in 0.8x

A new feature in 0.8 was added where the actual AABB values can be saved into a file rather then having to copy the values from the console.

To get the value you need to add a name parameter to the command. The name you use can be anything you want but it is advisable that you use something sensible such as *tankbarrier1* of *trigger1*

For this example we are going to use the name *trigger1*

The command **/bot trigger\_bounds trigger1** is used at the location you want to start, then move around to expand the region and use the same command again **/bot trigger\_bounds trigger1** to save the value.

The 1st time you use this command a new file will be created in the user folder for example *~omni-bot\et\user* (change et to whatever game you are using like rtcw)

Look in your user folder and look for the map name followed by \_regiontriggers.gm so if you were doing the oasis map it would be oasis\_regiontriggers.gm

Open the new file and you will see something like this:

```
OnTriggerRegion(AABB(1230.363,2206.532,230.125,1368.292,2328.765,304.125),Map.Trigger1);
OnTriggerRegion(AABB(5876.540,-2018.874,597.152,5916.129,-1857.128,671.152),Map.Trigger2);
OnTriggerRegion(AABB(8062.165,-2018.873,597.125,8101.741,-1857.126,671.125),Map.Trigger3);

```

This example shows where 3 AABB trigger values have been saved where the name parameter has been changed each time.

## OnEnter, OnExit

OnEnter is called when an entity enters the region. OnExit is called when an entity exits the region, when an entity was deleted, when a player disconnected or when a player is in limbo. OnExit is optional. You don't have to define empty OnExit function.

You can use function Util.IsBot(ent) to test if the player is a bot.

Never use functions GetEntTeam or GetEntClass inside OnExit because players can change team or class between OnEnter and OnExit.

## Example

Bots lack the ability to see the way a player with an object has gone. To enable a better defense you can set up 2 or more trigger regions that will detect when a player with an object goes a certain way so the bots can focus on the best defense strategy.

```
global Map =
{
 YourTrigger =
 {
 Name = "YourTrigger",
 TriggerOnClass = CLASS.ANYPLAYER,
 OnEnter = function(ent)
 {
 if( GetEntTeam(ent) == TEAM.ALLIES && GetEntFlags( ent, ENTFLAG.CARRYINGGOAL ) )
 {
 SetAvailableMapGoals( TEAM.ALLIES, true, "ATTACK\_SomeGoal" );
 SetAvailableMapGoals( TEAM.AXIS, true, "DEFEND\_SomeGoal" );
 }
 },
 },
};

global OnMapLoad = function()
{
 OnTriggerRegion(AABB(1,2,3,4,5,6), Map.YourTrigger);
};

```

## How to set bot roles

You can assign a role to bots that are inside the region. Then you can use function Util.SetRoleForTable to enable some goals only for bots that are inside the region.

```
 Bunker\_Region =
 {
 Name = "Bunker\_Region",
 TriggerOnClass = CLASS.ANYPLAYER,
 OnEnter = function(ent)
 {
 bot = Util.IsBot(ent);
 if (bot && bot.GetTeam() == TEAM.AXIS )
 {
 bot.SetRoles(ROLE.AMBUSHER);
 }
 },
 OnExit = function(ent)
 {
 bot = Util.IsBot(ent);
 if (bot)
 {
 bot.ClearRoles(ROLE.AMBUSHER);
 }
 },
 },

```

## How to count players in a region

It is necessary to define a table for all players that are inside the region. Then you can use **tableCount** function to get number of those players.

```
 DepotRoof =
 {
 Name = "DepotRoof",
 TriggerOnClass = CLASS.ANYPLAYER,
 playerList = {},
 OnEnter = function(ent)
 {
 if ( GetEntTeam(ent) == TEAM.ALLIES )
 {
 list = Map.DepotRoof.playerList;
 if (list[ent])
 {
 //overlapping regions
 list[ent] += 1;
 }
 else
 {
 list[ent] = 1;
 if ( tableCount(list) == 1 ) {
 // enable CAMP goals if there are any allied players on the roof
 Util.EnableGroup( "depotroof", TEAM.AXIS );
 }
 }
 }
 },
 OnExit = function(ent)
 {
 list = Map.DepotRoof.playerList;
 if (list[ent])
 {
 if (list[ent] > 1)
 {
 //overlapping regions
 list[ent] -= 1;
 }
 else
 {
 list[ent] = null;
 if ( tableCount(list) == 0 ) {
 // the roof is clear
 Util.DisableGroup( "depotroof", TEAM.AXIS );
 }
 }
 }
 },
 },

```