Workshop.codes
Create
Abort Abort If Abort If Condition Is False Abort If Condition Is True Add Health Pool To Player Allow Button Apply Impulse Attach Players Big Message Break Call Subroutine Cancel Primary Action Chase Global Variable At Rate Chase Global Variable Over Time Chase Player Variable At Rate Chase Player Variable Over Time Clear Status Communicate Continue Create Beam Effect Create Dummy Bot Create Effect Create HUD Text Create Homing Projectile Create Icon Create In-World Text Create Progress Bar HUD Text Create Progress Bar In-World Text Create Projectile Create Projectile Effect Damage Declare Match Draw Declare Player Victory Declare Round Draw Declare Round Victory Declare Team Victory Destroy All Dummy Bots Destroy All Effects Destroy All HUD Text Destroy All Icons Destroy All In-World Text Destroy All Progress Bar HUD Text Destroy All Progress Bar In-World Text Destroy Dummy Bot Destroy Effect Destroy HUD Text Destroy Icon Destroy In-World Text Destroy Progress Bar HUD Text Destroy Progress Bar In-World Text Detach Players Disable Built-In Game Mode Announcer Disable Built-In Game Mode Completion Disable Built-In Game Mode Music Disable Built-In Game Mode Respawning Disable Built-In Game Mode Scoring Disable Death Spectate All Players Disable Death Spectate Target HUD Disable Game Mode HUD Disable Game Mode In-World UI Disable Hero HUD Disable Inspector Recording Disable Kill Feed Disable Messages Disable Movement Collision With Environment Disable Movement Collision With Players Disable Nameplates Disable Scoreboard Disable Text Chat Disable Voice Chat Disallow Button Else Else If Enable Built-In Game Mode Announcer Enable Built-In Game Mode Completion Enable Built-In Game Mode Music Enable Built-In Game Mode Respawning Enable Built-In Game Mode Scoring Enable Death Spectate All Players Enable Death Spectate Target HUD Enable Game Mode HUD Enable Game Mode In-World UI Enable Hero HUD Enable Inspector Recording Enable Kill Feed Enable Messages Enable Movement Collision With Environment Enable Movement Collision With Players Enable Nameplates Enable Scoreboard Enable Text Chat Enable Voice Chat End For Global Variable For Player Variable Go To Assemble Heroes Heal If Kill Log To Inspector Loop Loop If Loop If Condition Is False Loop If Condition Is True Modify Global Variable Modify Global Variable At Index Modify Player Score Modify Player Variable Modify Player Variable At Index Modify Team Score Move Player To Team Pause Match Time Play Effect Preload Hero Press Button Remove All Health Pools From Player Remove Health Pool From Player Remove Player Reset Player Hero Availability Respawn Restart Match Resurrect Return To Lobby Set Ability 1 Enabled Set Ability 2 Enabled Set Ability Charge Set Ability Cooldown Set Ability Resource Set Aim Speed Set Ammo Set Crouch Enabled Set Damage Dealt Set Damage Received Set Environment Credit Player Set Facing Set Global Variable Set Global Variable At Index Set Gravity Set Healing Dealt Set Healing Received Set Invisible Set Jump Enabled Set Jump Vertical Speed Set Knockback Dealt Set Knockback Received Set Match Time Set Max Ammo Set Max Health Set Melee Enabled Set Move Speed Set Objective Description Set Player Allowed Heroes Set Player Health Set Player Score Set Player Variable Set Player Variable At Index Set Primary Fire Enabled Set Projectile Gravity Set Projectile Speed Set Reload Enabled Set Respawn Max Time Set Secondary Fire Enabled Set Slow Motion Set Status Set Team Score Set Ultimate Ability Enabled Set Ultimate Charge Set Weapon Skip Skip If Small Message Start Accelerating Start Assist Start Camera Start Damage Modification Start Damage Over Time Start Facing Start Forcing Dummy Bot Name Start Forcing Player Outlines Start Forcing Player Position Start Forcing Player To Be Hero Start Forcing Spawn Room Start Forcing Throttle Start Game Mode Start Heal Over Time Start Healing Modification Start Holding Button Start Modifying Hero Voice Lines Start Rule Start Scaling Barriers Start Scaling Player Start Throttle In Direction Start Transforming Throttle Stop Accelerating Stop All Assists Stop All Damage Modifications Stop All Damage Over Time Stop All Heal Over Time Stop All Healing Modifications Stop Assist Stop Camera Stop Chasing Global Variable Stop Chasing Player Variable Stop Damage Modification Stop Damage Over Time Stop Facing Stop Forcing Dummy Bot Name Stop Forcing Player Outlines Stop Forcing Player Position Stop Forcing Player To Be Hero Stop Forcing Spawn Room Stop Forcing Throttle Stop Heal Over Time Stop Healing Modification Stop Holding Button Stop Modifying Hero Voice Lines Stop Scaling Barriers Stop Scaling Player Stop Throttle In Direction Stop Transforming Throttle Teleport Unpause Match Time Wait Wait Until While
Ability Charge Ability Cooldown Ability Icon String Ability Resource Absolute Value Add All Damage Heroes All Dead Players All Heroes All Living Players All Players All Players Not On Objective All Players On Objective All Support Heroes All Tank Heroes Allowed Heroes Altitude Of Ammo And Angle Between Vectors Angle Difference Append To Array Arccosine In Degrees Arccosine In Radians Arcsine In Degrees Arcsine In Radians Arctangent In Degrees Arctangent In Radians Array Array Contains Array Slice Assist Count Attacker Backward Button Char In String Closest Player To Color Compare Control Mode Scoring Percentage Control Mode Scoring Team Cosine From Degrees Cosine From Radians Count Of Cross Product Current Array Element Current Array Index Current Game Mode Current Map Custom Color Custom String Damage Modification Count Damage Over Time Count Direction From Angles Direction Towards Distance Between Divide Dot Product Down Empty Array Entity Count Entity Exists Evaluate Once Event Ability Event Damage Event Direction Event Healing Event Player Event Was Critical Hit Event Was Environment Event Was Health Pack Eye Position Facing Direction Of False Farthest Player From Filtered Array First Of Flag Position Forward Game Mode Global Global Variable Has Spawned Has Status Heal Over Time Count Healee Healer Healing Modification Count Health Health Of Type Hero Hero Being Duplicated Hero Icon String Hero Of Horizontal Angle From Direction Horizontal Angle Towards Horizontal Facing Angle Of Horizontal Speed Of Host Player Icon String If-Then-Else Index Of Array Value Index Of String Char Input Binding String Is Alive Is Assembling Heroes Is Between Rounds Is Button Held Is CTF Mode In Sudden Death Is Communicating Is Communicating Any Is Communicating Any Emote Is Communicating Any Spray Is Communicating Any Voice line Is Control Mode Point Locked Is Crouching Is Dead Is Dummy Bot Is Duplicating Is Firing Primary Is Firing Secondary Is Flag At Base Is Flag Being Carried Is Game In Progress Is Hero Being Played Is In Air Is In Alternate Form Is In Line of Sight Is In Setup Is In Spawn Room Is In View Angle Is Jumping Is Match Complete Is Meleeing Is Moving Is Objective Complete Is On Ground Is On Objective Is On Wall Is Portrait On Fire Is Reloading Is Standing Is Team On Defense Is Team On Offense Is True For All Is True For Any Is Using Ability 1 Is Using Ability 2 Is Using Ultimate Is Waiting For Players Last Assist ID Last Created Entity Last Created Health Pool Last Damage Modification ID Last Damage Over Time ID Last Heal Over Time ID Last Healing Modification ID Last Of Last Text ID Left Local Player Local Vector Of Magnitude Of Map Mapped Array Match Round Match Time Max Max Ammo Max Health Max Health of Type Min Modulo Multiply Nearest Walkable Position Normalize Normalized Health Not Null Number of Dead Players Number of Deaths Number of Eliminations Number of Final Blows Number of Heroes Number of Living Players Number of Players Number of Players On Objective Number of Slots Objective Index Objective Position Opposite Team Of Or Payload Position Payload Progress Percentage Player Carrying Flag Player Closest To Reticle Player Hero Stat Player Stat Player Variable Players In Slot Players On Hero Players Within Radius Players in View Angle Point Capture Percentage Position Of Raise To Power Random Integer Random Real Random Value In Array Randomized Array Ray Cast Hit Normal Ray Cast Hit Player Ray Cast Hit Position Remove From Array Right Round To Integer Score Of Server Load Server Load Average Server Load Peak Sine From Degrees Sine From Radians Slot Of Sorted Array Spawn Points Speed Of Speed Of In Direction Square Root String String Contains String Length String Replace String Slice String Split Subtract Tangent From Degrees Tangent From Radians Team Of Team Score Text Count Throttle Of Total Time Elapsed True Ultimate Charge Percent Up Update Every Frame Value In Array Vector Vector Towards Velocity Of Vertical Angle From Direction Vertical Angle Towards Vertical Facing Angle Of Vertical Speed Of Victim Weapon Workshop Setting Combo Workshop Setting Hero Workshop Setting Integer Workshop Setting Real Workshop Setting Toggle World Vector Of X Component Of Y Component Of Z Component Of

How to make an Assault Capture Point Last updated November 26, 2024

Table Of Contents

  1. Lobby Setup
  2. Variables
  3. Initial Setup
  4. Tracking Number of Players
  5. Capturing
  6. Ticks
  7. HUD and Effects

Capture Point Demo import code: XRHDH

Lobby Setup

For the purposes of this walkthrough, we will be hard-coding the location of the capture point along with its other properties such as size and capture rate. As a result, we'll also need to restrict the lobby to only ever load one map. Here, I've chosen Workshop Island.

Note: The following code should 100% be built upon and improved. It is only a demo

Variables

For this demo, we will be using 7 global variables:

Variable What it does
CP_POSITION A vector that stores center of the capture point
CP_SETTINGS An array that stores workshop settings that customize the capture point (radius, capture rate)
CP_PROGRESS The capture percentage for the current tick
CP_RATES An array that stores the capture rates for 0, 1, 2 and >3 players)
CPTICKLOWER The lower bound of the current tick (0, 33, 66, or 99 in this demo)
CPTICKUPPER The upper bound of the current tick (33, 66, 99, 100 in this demo)
STEP A variable to be used in for loops

Initial Setup

To start, we need a few basic components. We need the center position, the radius of the point, and a ring effect so we can visually show where our point is.

Here, I've gone ahead and also initialized the workshop settings variable to hold the point radius and capture speed

variables
{
    global:
        26: CP_POSITION
        27: CP_SETTINGS
}

actions
{
    "Workshop Settings to easily customize your capture point"
    Global.CP_SETTINGS = Array(Workshop Setting Integer(Custom String("Capture Point Customization"), Custom String("Radius"), 15, 5,
        20, 0), Workshop Setting Real(Custom String("Capture Point Customization"), Custom String("Capture Rate Multiplier"), 1, 1,
        10, 1));

    "Change this vector to change the capture point position"
    Global.CP_POSITION = Vector(0, 0, 0);

    "Create a ring effect to visibly show the size and location of the capture point to all players"
    Create Effect(All Players(All Teams), Ring, Color(Team 1), Global.CP_POSITION, First Of(Global.CP_SETTINGS),
        Visible To Position and Radius);
}

Now that we can see the point, let's add some functionality. We'll start by initializing capture progress and the starting progress bounds. Since this demo is based off the Assault mode, we will be using 3 ticks with each tick being at intervals of 33.

variables
{
    global:
        28: CP_PROGRESS
        30: CP_TICK_LOWER
        31: CP_TICK_UPPER
}

actions
{
    "Next, progress bar setup to display capture percentage to attacking team"
    Global.CP_PROGRESS = 0;

    "This variable will store the current target tick (33 > 66 > 100)"
    Global.CP_TICK_UPPER = 33;

    "This variable will hold the previous tick (0 > 33 > 66)"
    Global.CP_TICK_LOWER = 0;
}

Then, we need the rate at which attackers will capture the point. Here, we'll use an array(0, 4.125, 6.6, 8.25). These numbers were obtained by dividing the value for one tick (33) by the capture rate for 1, 2 and >3 players repectively.

Using the STEP variable in a for loop, I've also multiplied each value in the capture rates array by the capture rate modifier constant from the workshop settings we created previously

variables
{
    global:
        27: CP_SETTINGS
        29: CP_RATES
        32: STEP
}

actions
{
    "Objective capture rates * cap speed multiplier"
    Global.CP_RATES = Array(0, 4.125, 6.600, 8.250);

    For Global Variable(STEP, 0, 4, 1);
        Global.CP_RATES[Global.STEP] *= Global.CP_SETTINGS[1];
    End;
}

Tracking Number of Players

Before continuing to the capturing, we need to be able to count the number of living players on the capture point. This can be done by using Count Of(), Filtered Array(), and Players Within Radius():

Note: Here we are using a set radius of 15

variables
{
    global:
        0: playersOnPoint
        26: CP_POSITION
}

actions
{
    Global.playersOnPoint = Count Of(Filtered Array(Players Within Radius(Global.CP_POSITION, 15, All Teams, Off), Is Alive(
        Current Array Element)));
}

Capturing

We have all the moving parts, now we need to put it together. In the demo, the capture progress is crammed into one Chase Global Variable At Rate action while the tick logic is handled by a separate rule. For understanding, let's address this by parts.

Yes, this is just one action. Works, but could be simplified

variables
{
    global:
        26: CP_POSITION
        27: CP_SETTINGS
        28: CP_PROGRESS
        29: CP_RATES
        30: CP_TICK_LOWER
        31: CP_TICK_UPPER
}

actions
{
    "Main capture logic (capture rate scales with players, destination updates each tick, stops capture progress when contesting)"
    Chase Global Variable At Rate(CP_PROGRESS, (Count Of(Filtered Array(Players Within Radius(Global.CP_POSITION, First Of(
        Global.CP_SETTINGS), Team 1, Off), Is Alive(Current Array Element))) > 0 && Count Of(Filtered Array(Players Within Radius(
        Global.CP_POSITION, First Of(Global.CP_SETTINGS), Team 2, Off), Is Alive(Current Array Element))) == 0) || (Count Of(
        Filtered Array(Players Within Radius(Global.CP_POSITION, First Of(Global.CP_SETTINGS), Team 2, Off), Is Alive(
        Current Array Element))) == 0) ? Global.CP_TICK_LOWER : Global.CP_TICK_UPPER, Count Of(Filtered Array(Players Within Radius(
        Global.CP_POSITION, First Of(Global.CP_SETTINGS), Team 1, Off), Is Alive(Current Array Element))) > 0 && Count Of(
        Filtered Array(Players Within Radius(Global.CP_POSITION, First Of(Global.CP_SETTINGS), Team 2, Off), Is Alive(
        Current Array Element))) > 0 ? 0 : (Count Of(Filtered Array(Players Within Radius(Global.CP_POSITION, First Of(
        Global.CP_SETTINGS), Team 2, Off), Is Alive(Current Array Element))) == 0 ? 6 : (Count Of(Filtered Array(Players Within Radius(
        Global.CP_POSITION, First Of(Global.CP_SETTINGS), Team 2, Off), Is Alive(Current Array Element))) >= 3 ? Last Of(
        Global.CP_RATES) : Global.CP_RATES[Count Of(Filtered Array(Players Within Radius(Global.CP_POSITION, First Of(
        Global.CP_SETTINGS), Team 2, Off), Is Alive(Current Array Element)))])), Destination and Rate);
}

The logic behind this is as follows:

If there is at least one living player on the attacking team on point and there are no living players on point from the defending team, increase capture progress at a certain rate. Else, if there is at least one living player from bother the attacking and defending team on point, hold current capture progress. If neither of the previous are true,decrease capture progress.

  • The rate is dependent on the count of attacking players on point and corresponds to a value in the capture rates array.
  • The increase and decrease in capture progress is capped by the upper and lower tick bounds

Ticks

In the demo, we're using 3 ticks; each tick being 33 units for a total of 99 units for a full capture. In Capture, we established the conditions for which the capture progress can increase. Now, we can add triggers corresponding to each tick. In this case, we will be incrementing the upper and lower bounds of capture progress to mimic the ticks from Assault mode.

variables
{
    global:
        26: CP_POSITION
        27: CP_SETTINGS
        28: CP_PROGRESS
        30: CP_TICK_LOWER
        31: CP_TICK_UPPER
        32: STEP
}

rule("Ticks and capture triggers")
{
    event
    {
        Ongoing - Global;
    }

    conditions
    {
        Global.CP_PROGRESS == Global.CP_TICK_UPPER;
    }

    actions
    {
        If(Global.CP_PROGRESS == 99);
            Global.CP_TICK_UPPER = 100;
            Global.CP_TICK_LOWER = 99;
        Else If(Global.CP_PROGRESS == 100);
            Global.CP_TICK_LOWER = 100;
            For Global Variable(STEP, 0, 6, 1);
                Play Effect(All Players(Team 2), Ring Explosion, Color(Team 1), Global.CP_POSITION, First Of(Global.CP_SETTINGS) * 2);
                Wait(0.050, Ignore Condition);
            End;
            Big Message(All Players(Team 1), Custom String("Objective Lost!"));
            Big Message(All Players(Team 2), Custom String("Objective Captured!"));
            Play Effect(All Players(Team 2), Buff Impact Sound, Color(White), Players Within Radius(Global.CP_POSITION, First Of(
                Global.CP_SETTINGS), Team 2, Off), 75);
            Play Effect(All Players(Team 1), Explosion Sound, Color(White), Players Within Radius(Global.CP_POSITION, First Of(
                Global.CP_SETTINGS), Team 1, Off), 75);
            Wait(0.500, Ignore Condition);
            "Reset capture progress variables"
            Global.CP_PROGRESS = 0;
            Global.CP_TICK_UPPER = 33;
            Global.CP_TICK_LOWER = 0;
            "This is where you would trigger any events you want to happen when objective is fully captured. In this case, I'm just moving the objective below the map"
            Global.CP_POSITION = Vector(0, -100, 0);
        Else;
            Play Effect(All Players(Team 2), Buff Impact Sound, Color(White), Players Within Radius(Global.CP_POSITION, First Of(
                Global.CP_SETTINGS), Team 2, Off), 75);
            Global.CP_TICK_LOWER += 33;
            Global.CP_TICK_UPPER += 33;
        End;
        Wait(0.100, Ignore Condition);
        Loop If Condition Is True;
    }
}

Here we have a rule with the conditon Global.CP_PROGRESS == Global.CP_TICK_UPPER which triggers when the capture progress reaches the upper bound of the current tick. The general action for this condition is to increase the bounds by 33. The main special action here is when the capture progress reaches 100. This is the trigger for any actions you want to happen once the point is captured. It also resets the capture point progress.

HUD and Effects

With a working capture point, players might want to have some more information on their screen regarding capture progress, opponents on point, or simply the location of the point.

See the demo for the player hud, in-world text, and icons

Workshop.codes
Join the Workshop.codes Discord