Trigger regions
Omni-Bot_Map_Scripting | 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 );
}
}
}
},
},