Charlie storm a rooftop

Vulture team pulling back onto a rooftop

With covering fire from a teammate a bot scales a drainpipe


Hosted by:
Bot Epidemic
and
TeleFragged

Visitor #: 01928

Latest news on CGFThe CGF conceptTechnical CGF information [AI and design]Got a CGF question? Read this firstHow to script CGF missions yourselfGet your CGF files and missions hereLinks to related sites [such as AQ2 or AI sites]



CGF Mission Scripting
Last update: March 12, 2000, by William. List of changes here .

In CGF, missions scripts are the way to define and start a customized battle. These mission scripts (.cgf files) define the forces and teams in the battle, their initial positions and plans, and the objectives.

Below, you'll find explained the idea, structure and commands of a CGF mission. Everything is explained using the urban_hitman_1.cgf mission as an example.

(Note that you don't need to craft missions yourself to use CGF: there are already plenty of downloadable missions present on the internet (see the links page).
In addition, simple changes to a mission, such as the changing the skill levels, can be done 'automatically' using a CGF mission launcher (see the downloads page).

Mission Structure
A mission basically consists of five mandatory parts, in the following order:
  1. mission header
  2. map description
  3. force definition
  4. mission objectives and mission chaining
  5. team plans
  6. editing locations
Mission Header
The purpose of the mission header is to provide the player (both in the bot launcher and in game) with summary information about the mission (in the following order):
  • title (the mission stated in a couple of words, for example "urban hitman")
    the title should start with a character from [a-zA-Z0-9_.,'() /\-\\!:?] and continue with characters from [a-zA-Z0-9_.,'() /\-\\!:?+=#@\^|%&]
    the title need not be unique (missions are identified by their file name)

  • author (the author(s) name(s))
    the authors will appear in game on the console in future versions if you edit the mission, make sure you change or modify the author(s) to include your name

  • description (the mission in a couple of lines)
    this description appears in-game in the first 5 seconds, and when the player presses the help key
    make sure that the description fits on 512x384 screens - not every gamer has high end hardware
    you can direct the text over multiple lines by using the '\n' characters where you want a new line
    the description should start with a character from [a-zA-Z0-9_.,'() /\-\\!:?] and continue with characters from [a-zA-Z0-9_.,'() /\-\\!:?+=#@\^|%&]

  • rules (defines specific restrictions for the mission)
    currently, the rules solely define the respawn behavior (to be: none)
    in future versions, expect to be able to fight missions exactly according AQ2 TP restrictions, or with slightly rules for weapon load out etc.
    again, currently, the only (mandatory) rule (and value) are: respawn = none;
For example, the urban_hitman_1.cgf mission header looks like:
 
  // comments are preceded by '//' such as this line,
  // or included between '/*' and '*/'

mission "urban hitman"
{

  author
    "William van der Sterren";

  description
    "\nyou're the hitman!\neliminate Sabotage\nhe might be protected :)";

  rules
  {
    respawn = none;
  };
  
 

If you edit a mission, you should definitely edit the header to include a new mission title, description and author name.

Map Description
The purpose of the map description is to enable the mission objectives and team plans to refer to locations and areas. The map description also provides some hints to the CGF AI on the type of terrain.
In addition, it is a good habit to include some kind of drawing for documentation purposes.

Consequently, the map description consists of the following parts (in the following order):

  • map name (the bsp file's name without '.bsp', for example: actcity2)
    CGF needs this to load the required map (and the bot launcher uses this name to check whether you can run the mission)

  • map style (optional hints for the AI)
    You can tell the CGF AI more about the map using a combination of the styles 'open', 'indoor', 'dark' and 'urban'.
    The actcity2 map would be described as "style = open, dark, urban;"
    whereas museum would be best described as "style = indoor, dark;"
    in the future versions of CGF, the AI will adapt its default weapon selection and patrol characteristics using this info. (I probably could write the algorithm to extract these characteristics from the route file but prefer to improve other parts of CGF first).

  • map annotation (optional ascii art drawing of the map)
    In my experience, it's hard to provide meaningful names (or labels) to grid locations in a map unless you can refer to directions (North, East, South, West) and areas or buildings. Therefor, I just make up the directions and draw a ascii art map of the bsp file.
    This annotation helps other mission developers a lot when they want to modify your mission script
    The drawing should start with a character from [a-zA-Z0-9_.,'() /\-\\!:?] and continue with characters from [a-zA-Z0-9_.,'() /\-\\!:?+=#@\^|%&]

  • map locations (list of location definitions, providing meaningful labels to locations in the map)
    Because most team instructions (and the map areas) refer to locations, it is important to record the locations here with recognizable names. Locations refer to absolute Quake2 coordinates, and are independent of the route file in use (provided the route file contains a nearby way point for the coordinate).
    You define a location by defining it's label and the corresponding x, y and z coordinates as follows:
      location locationname = < x, y , z>;
    where locationname is a string (starting with a letter, and containing solely letters, the underscore _, and digits).
    You can obtain the coordinates for a specific location by loading up the respective map, moving to the appropriate location, and typing 'coords' on the console.
    Make sure you copy the correct coordinates from the console. CGF doesn't like locations that have no way point nearby.

  • map areas (list of areas definitions, providing meaningful labels to patrol locations, additional information for future AI extensions, and for mission objectives)
    Patrolling is done by visiting map areas (instead of locations). Patrolling areas instead of locations makes the patrolling less predictable (the team only needs check out the area, instead of visiting the same location again and again).

    Areas were also introduced to make up for a lack of environmental description in Quake2. The AI has troubles recognizing area structure (entrances, exits, windows) at run-time (too expensive). Areas can provide the additional information.

    Areas also are used to define 'occupation' mission objectives: to meet such an objective, a team member should be within the area and have been in the area for a specific amount of time without threats engaging the team in that area or threats visiting that area.

    Areas are given a name (just like locations). This area name is used when you want to have teams patrol a specific list of areas. It's not required but a good habit to start area names with 'area_'.
    You can tell the CGF AI more about the area using one of the area styles 'open' (outdoor open area), 'closed' (indoor or enclosed area, having a few narrow entrances, exits and/or windows, or 'roof'. Combinations of area styles are not allowed.
    An area needs to contain at least one location.
    The size of an area (that is, the way point included in the area) is determined at run-time using a nifty flood-fill like algorithm. You just need to tell CGF when to stop flood-filling. You do that either by specifying a:

    • radius (a max distance to any of the defined locations)
    • using the height cut-off property for roofs (the flood-fill won't include way points that are located much higher or lower), or
    • (not for newbies) specifying exactly the entrances, exits and windows

    Though this may sound complex, you whip up simple area definitions as follows:
      area area_E_UnderBridge // under 'bridge' area at urban
        { style = open;
          locations = E_UnderBridge;
          radius = 100; // max distance to listed locations
       };

    or

      area area_NW_SniperRoom // sniper room near parking lot
        { style = roof;
          locations = NW_SniperRoom_Rooftop
          // use automatic height cut off instead of radius
       };

    More complex area definitions won't be documented until used by the AI.
    To have a team patrol, you need to have at least two areas defined.
    To use 'occupy' mission objectives, you need to have an area defined.

For example, the map description of the urban_hitman_1.cgf mission looks like:

 
  // map description is preceded by the header

  map "urban"
  { 
    style = open, dark, urban;

    annotation = "

    ^N
  W     E            map by Gerbil!
     S

 +----------+-----+=============----+------+----+--------------------------+
 |  low     |@@   |         |   .   +------+    |                          |
 | buildings|@@   |         |   .   |##    |    +                          |

   [removed part of drawing for brevity]

 |  @@      @@    +------------HH---+------|                       |       |
 |                                 #|     #| south east high roof  |       |  
 +----------------------------------+--------------------------------------+
 "; 

    /*
    locations
    */ 

    // sniper room locations (north west)
    location NW_SniperRoom_Rooftop         = <-1346,   634,  280>;
    location NW_SniperRoom                 = <-1273,   879,  316>;
    location NW_SniperRoomCorner           = <-1391,   800,  316>;

    // parking
    location W_Parking_TopFloor            = <-1337,   268,  432>;
    location W_Parking_SndFloor            = <-1406,   210,  296>;

    // removed a number of locations for brevity

    /*
    areas (for patrol purposes)
    */ 
    area area_NW_SniperRoom
    { style     = roof; // combine using open, closed, roof
      locations = NW_SniperRoom_Rooftop;
      // use height cut off instead of radius
    };

    area area_E_UnderBridge
      { style     = open; // combine using open, closed, roof
        locations = E_UnderBridge;
        radius    = 100;  // max distance to listed locations
      };

    // removed a number of areas for brevity

  };


  // map description is followed by force definitions
  
 
Force Definition
The purpose of force definitions is to define the opposing forces (how many, their names, and their composition (teams and members)). Human players (if participating in the mission) need to be part of a force (and a team within that force).
Mission objectives typically refer to forces, teams and members. Therefor it's important to provide meaningful names to those forces, teams and members.

To overcome the (default) ActionQuake2 limit of only two opposing teams, a CGF script defines as many (opposing) forces as required. Each member of a force will regard members of other forces as threats (and happily take them out). Thus, you can set up fights between, for example, two, three, four, etc. opposing forces.

CGF also removes the limitation on a single model or skin per AQ2 team. For each force member, you're free to pick whatever model and skin combination you want (since the bots determine between friend and foe on force membership, not on skin or mode). The AQ2 damage model has been changed to solely look at force membership as well.
This should enable you to construct scripts depicting movie scenes, with various models and skins for the different 'actors'.

A CGF force is composed of one or more teams. A CGF team is not similar to 'standard' AQ2 team (that would be the CGF force), but instead the smallest unit to act and fight cohesively according to the script. (Apologies for the confusion - CGF itself started before AQ2 started, and I never fixed this).

A (CGF force) team is either composed of humans (labeled 'players') or bots (labeled 'npc' from 'non-player character). Mixed teams are not supported.

The urban_hitman_1.cgf mission forces, for example, are composed as follows:

force team type member (model/skin)
Warez Dudes Clandestine Management npc Sabotage
(male/sabotage)
Warez Dudes High Precision npc Precision-1
(terror/swatsnipe)
Warez Dudes Protection Copy npc Protection-1
(terror/terror)
Warez Dudes ProtectionCopy npc Protection-2
(terror/terror)
Warez Dudes Protection Copy npc Protection-3
(terror/terror)
Warez Dudes Protection Copy npc Protection-4
(terror/terror)
Local Law Sidekick npc Joe Automatic
(male/adidas)
Local Law Hitman player dah player
(male/reservoir)

In this case, the mission consists of (solely) two opposing forces. Force 'Warez Dudes' contains three teams and uses two models and three skins. Force 'Local Law' contains two teams (one for the npc, and another for the player because they need to be in separate teams). 'Local Law' uses a single model but two different skins.
The mission hosts seven bots (or npc) and a single player. You would add multiple players (in the case of co-op multi-player against the bots) in the same Hitman team.

A team hosts up to eight npc-s or players.

To define a (new) force, you need to write the following (after the map definitions, and before mission objectives):

  force "forcename" {
    // team definitions
  };

To define a (new) team within a force, you need to write the following (between the '{' and '}' of the corresponding force definition):

    team "teamname" {
      // member definitions
    };

A team defines each members as follows:

  • member type (either 'npc' or 'player')
    'npc' members will be played by bots. 'player' members might be played by humans (or left 'vacant' in the case of co-op multi-player with insufficient players).
    Note that you cannot mix npc and player members within a single team.
    Though you can define skill settings for a player (this makes changing player to npc and v.v. easier), a skill setting for a player does not affect the player at all.
    Current beta's do not support co-op multi-player against bots.

  • name (name valid during the mission only)
    This name is used to specify mission objectives (elimination of a certain player or npc might accomplish the mission).
    The name defined in the mission doesn't change your AQ2 netname.

  • modelname/skinname (model and skin only valid during mission)
    This defines the looks of bots and players during the mission. It doesn't affect damage (AQ2 settings for teamplay by skin/model are ignored, and damage is based on force membership).
    The model/skin defined in the mission doesn't change your AQ2 defaults.

  • 'load out', that is, the weapons, ammo and items to start with
    Instead of the (handy) AQ2 weapon/item selection menu, the script defines the load out for you. (You can use future versions of the bot launcher to modify the load out without seeing the script itself).

    Currently, CGF allows you to severely violate the AQ2 TP restrictions on load out: if you want to equip bots or players with lots of special weapons, huge amounts of ammo, and almost all items, you can do so.
    However, (in the current beta versions) during the mission, you won't be able to pick up other special weapons or items if you already have one.

    You issue a weapon to a team member as follows (between the '{' and '}' of the member definition):
      weapon "weaponname"; // weaponname should match AQ2 name

    A weapon comes with the TP default amount of ammo (ignoring the presence of any bandolier)
    You can issue additional ammo as follows (between the '{' and '}' of the member definition):
      ammo "ammoname" = count; // ammoname should match AQ2 name
    Depending on the corresponding weapon type, you'll receive ammo as individual pieces (shotguns / knifes / sniper bullets), or as complete clips.

    You can dress up the team member with items as follows (between the '{' and '}' of the member definition)
      item "itemname"; // itemname should match AQ2 name

    An example of loadout, illustrating all available weapons, ammo and items, looks like:

    
          npc "Sabotage" "male/sabotage" 
            { 
              // basic AQ2 weapons + ammo
              ammo   "Pistol Clip" = 1;
              weapon "Dual MK23 Pistols";
              ammo   "Machinegun Magazine" = 2;                    
              weapon "MP5/10 Submachinegun";
              ammo   "M4 Clip" = 2;
              weapon "M4 Assault Rifle";
              ammo   "12 Gauge Shells" = 7;
              weapon "M3 Super 90 Assault Shotgun";
              weapon "Handcannon";
              ammo   "AP Sniper Ammo" = 20;
              weapon "Sniper Rifle";
    
              // items        
              item   "Bandolier";
              item   "Kevlar Vest";
              item   "Lasersight";
              item   "Silencer";
              item   "Stealth Slippers";
    
              // optional pistol
              weapon ""Beretta 92F Pistol";
              // optional submachineguns
              weapon "AK97 Submachinegun";
              weapon "MAC-10 Submachinegun";
              weapon "UMP45 Submachinegun";
              weapon "UZI Submachinegun";
              // optional assault rifles
              weapon "AK47 Assault Rifle";
              weapon "Tommygun";
              // optional assault shotgun
              weapon "Ithaca Model37 Assault Shotgun";
              // optional cannon
              weapon "Old-style Cannon";          
              // optional sniper rifles
              weapon "Barrett M82 Sniper Rifle";          
              weapon "Dragunov Sniper Rifle";
    
              // skill (from 1..5, ignored for 'player')
              skill  = 3;
            };
    Note that all load out definitions shall precede the skill definition. Grenades and knives are not yet supported.

  • skill, range [1.0 = weak ... 5.0 = strong] affects npc team members
    The skill setting doesn't affect the player member (skill settings for the player are allowed but ignored), but for the npc, the skill affects:
    • aiming accuracy
    • turning speed (higher skill bots turn faster)
    • M4 muzzle climb handling (higher skill bots compensate better)
    • vision threshold (amount of time needed to acquire a new threat (partially) in the bot's field of vision; higher skill bots acquire faster)
    Note that the skill setting should be last line in the member definition and is mandatory for npc members.
For example, the map description of the urban_hitman_1.cgf mission looks like:
 
  // force definition is preceded by map description

  force "Warez Dudes"
  {
    team "Clandestine Management"
    { 
      npc "Sabotage" "male/sabotage" 
        { 
          ammo   "Pistol Clip" = 1;
          weapon "Dual MK23 Pistols";
          item   "Kevlar Vest";
          skill  = 3;
        };
    };

    team "High Precision"
    { 
      npc "Precision-1" "terror/swatsnipe" // sniper team
        { 
          ammo   "AP Sniper Ammo" = 10;
          weapon "Sniper Rifle";
          skill  = 2;
        };
    };

    team "Protection Copy"
    { 
      npc "Protection-1" "terror/terror" 
        { 
          ammo   "Machinegun Magazine" = 2;                    
          weapon "MP5/10 Submachinegun";
          item   "Kevlar Vest";
          item   "Lasersight";

          skill  = 2;
        };
      npc "Protection-2" "terror/terror" 
        { 
          weapon "M3 Super 90 Assault Shotgun";
          ammo   "12 Gauge Shells" = 7;
          item   "Kevlar Vest";

          skill  = 2;
        };
      // two members removed part for brevity
    };

  };

  force "Local Law"
  {
    team "Hitman"
    { 
      player "dah player" "male/reservoir" 
        { 
          weapon "M3 Super 90 Assault Shotgun";
          ammo   "12 Gauge Shells" = 7;

          item   "Kevlar Vest";
        };
    };

    team "Sidekick"
    { 
      npc "Joe Automatic" "male/adidas" 
        { 
          weapon "M4 Assault Rifle";
          ammo   "M4 Clip" = 2;
          skill  = 2.5;
        };
    };
  };


  // force composition is followed by objective definitions
  
 
Mission Objectives & Mission Chaining
The mission objectives define when a mission will be completed (and the result of the mission in terms of messages to the player).
Each objective also defines one or more candidate successor missions. The next mission is automatically selected (at random) from the list of candidate missions defined by the first objective achieved.

Using these objectives, one can define a ladder of missions: when the player fails a mission, he is given an easier mission, when the player completes a mission, he is given a harder mission.
Likewise, one can define a 'campaign' of chained missions.

The CGF mission objectives replace AQ2 TP timelimits and fraglimits.

An objective is achieved as its condition (or logical combination ('and' / 'or' / 'not') of conditions are met. The first objective met signals the end of the mission, displays post-mission feedback messages for the players, and selects the subsequent mission.

Three different kinds of conditions are provided (in addition to the logical combinations):

  • time-out
    A time-out condition is met when the mission duration (in seconds) exceeds the specified time. A time-out condition looks like:
      timeout(duration) // duration in seconds

    Because the bots might get stuck (and therefor might take forever to complete the mission), it's a good thing to always define a time-out objective.

  • eliminated
    An eliminated condition is met when the specified force, team or team member has been eliminated for longer than a time-out of 7.5 seconds. (Thus the mission does not end immediately after eliminating that force, team, or team member).
    A team member is eliminated when he is killed (either by opponents, suicide or other wounds). A team is eliminated when all its members have been eliminated. A force is eliminated when all its teams have been eliminated.
    An eliminated condition looks like:
      eliminated("forceteammembername") // force/team/member name

    To be able to specify elimination conditions unambiguously, make sure that force names, team names and members names are all distinct from each other.

  • occupied (not yet supported)
    An occupied condition is met when the specified force has been occupying the specified area for more than the specified time, by:
    • having at least one (living) force member being present in the area during that period
    • not having any (living) opposing force member being present in the area during that period
    • not being engaged in that area by opposing forces during that period
    An occupied condition looks like:
      occupied("forcename", areaname, duration)

    Again, the occupied condition is not yet available in the current beta.

  • 'and' combination of two conditions: (condition1 && condition2)
    An and condition is met when both its sub conditions are met. The C-style 'and' symbol '&&' is used, and the syntax looks complicated (due the additional required parenthesis), but nevertheless it is not that hard to specify a combination of two objectives:
      (eliminated("force1") && eliminated("force2"))
    or a combination of three objectives:
      (eliminated("tm1") && (eliminated("tm2") && timeout(200)))

    Note that and-, or- and not- conditions can be mixed.

  • 'or' combination of two conditions: (condition1 || condition2)
    An or condition is met when one or more of its sub conditions are met. The C-style 'or' symbol '||' is used, and the syntax looks complicated (due the additional required parenthesis), but nevertheless it is not that hard to specify a combination of two objectives:
      (eliminated("force1") || eliminated("force2"))
    or a combination of three objectives:
      (eliminated("tm1") || (eliminated("tm2") || timeout(200)))

    Note that and-, or- and not- conditions can be mixed.

  • 'not' inversion of another conditions: !(condition1)
    An not condition is met as long as its sub conditions is not met. The C-style 'not' symbol '!' is used, and the syntax requires a paier of parenthesis.
    The not condition is mainly useful in combination with other conditions, for example, when you want to inform the player about the fact that team1 was eliminated but not team2. but nevertheless it is not that hard to specify a combination of two objectives:
      (eliminated("team1") && !(eliminated("team2")))

    Note (as shown above) that and-, or- and not-conditions can be mixed.

A CGF objective is composed as follows:

  • objective type
    There are two types of objectives ('success' and 'failure'). The main difference between the types objectives is the sound file played upon achieving the objective (completing respectively failing the mission), and the default message presented to players among the other forces. Note that it only makes sense to define objectives for forces that contain a player.

  • force to which objective applies
    The objective applies to a specific force (and typically one containing a player). This force is specified by the force name.

  • message to be displayed when objective is met
    When objective is met (more precisely: is the first objective to be met), it's message will appear in the post-mission texts for the players. Typically, this text expresses encouragement (for success objectives) or disappointment (for failure objectives), and some explanation about the specific objective achieve: "you successfully took out Sabotage", or "too slow again!".
    Make sure that the message fits on 512x384 screens - not every gamer has high end hardware.
    You can direct the text over multiple lines by using the '\n' characters where you want a new line.
    The description should start with a character from [a-zA-Z0-9_.,'() /\-\\!:?] and continue with characters from [a-zA-Z0-9_.,'() /\-\\!:?+=#@\^|%&]

  • objective condition(see above)
    This condition defines when the objective is met. The conditions have been explained in detail above.

  • list of successor missions (in case objective is met)
    This list contains candidate successor missions (actually, the file names of the script, including the extension .cgf). When the objective is the first objective to be met, it will determine the next mission. This next mission is selected at random from the list of successor mission files.
    The list may include the mission itself. The list may include missions for other maps (but changing maps typically causes a longer delay). A mission file might be included more than once to increase its chances to be selected.
    The list looks like this:
      -> {"urban_hitman_1.cgf", "urban_hitman_2.cgf"};
    Note: it is possible to launch a .cfg configuration script instead of a (.cgf) mission. This allows mission designers to play cut-scenes (demo's) or sound, or perform other required actions.
For example, the map description of the urban_hitman_1.cgf mission looks like:
 
  // objective definition is preceded by force definition

  objectives
  {
    failure
      ( "Local Law",
        "\nYOU are supposed to be THE hitman!"
      )
    = eliminated("Local Law")
      -> {"urban_hitman_1.cgf", "urban_hitman_2.cgf", 
          "urban_hitman_3.cgf", "urban_hitman_4.cgf"
        };

    success
      ( "Local Law",
        "\nwell done!\nyou sure are da HITMAN!"
      )
    = eliminated("Sabotage")
      -> {"urban_hitman_1.cgf", "urban_hitman_2.cgf", 
          "urban_hitman_3.cgf", "urban_hitman_4.cgf"
        };

    failure
      ( "Local Law",
        "\nyawn...\nthis is taking way too long"
      )
    = timeout(300)
      -> {"urban_hitman_1.cgf", "urban_hitman_2.cgf", 
          "urban_hitman_3.cgf", "urban_hitman_4.cgf"
        };
  };

  // objective definitions are followed by team plans
  
 
Note the current beta's contain a bug that allows a later completed objective to redefine the post-mission message.
Team Plans
The team plans provide instructions and behavior for the forces' teams. The team plans heavily use locations and areas defined in the map section of the script.

Being probably hardest-to-learn part of CGF scripting, I'll provide some more background info.

High level scripting
The team plans thus provide the 'real' scripted behavior of CGF. Note that the type of scripting is totally different from Half-Life, Sin, Unreal or SpecOps scripting: here you issue a number of instructions to teams - not to individual bots or entities. (Probably the planning stage of Rainbow Six comes close, but though the RB6 operatives execute the plan with nifty close quarter formations, they seem unable to divert from the plan in unexpected situations).

As a result, you'll gain the advantage of being able to change team sizes at will: the script doesn't deal with the individual members, instead the CGF AI does so.
Another advantage is that you now can instruct teams to do fancy procedures such as bounding overwatch pull back (with suppression fire). Those maneuvers would be almost impossible to write in the above mentioned scripting systems (with the exception of RB6).
This level of scripting offers me the advantage of improving the AI and team tactics independently from the scripts. Older scripts will benefit automatically from AI improvements.
The last advantage is that because the CGF AI deals (dynamically) with combat situations and selects appropriate team tactics, the combat and missions outcome become less predictable. The combat is only "sketched", not scripted in detail. Mission scripts gain replayability.

The main disadvantage is that you lose control over individual members. You won't be able to do nifty Half-Life style 'tentacle grabs scientist' or 'grunt opens door, throws detpack, closes door, and ignites detpack' animations (actually, in the last case, the player is able to kill the grunt early but still the 'rigid script' has him close the door and ignite the detpack :) ).

Scripting 'Commands'
A team's plan consists of a rather simple sequence of commands, optionally with some commands how to prepare for exceptional cases (contact with enemy forces). The plan's commands are issued to the team in sequence. Issuing an instruction takes a Quake2 server frame, that is, 0.1 second. However, it might take the team much longer to execute an instruction.

To deal with duration differences between issuing a command and having the team execute it, a lot of wait command are used. That prevents the team from receiving the new command before it completes the current command. For example (the commands themselves will be explained later in detail), in the following plan (for Sabotage, the target in the hitman mission), almost half the commands are a kind of 'wait' command:

plan "Clandestine Management"
  {
     insert at SE_HighBuildingSniperRoom using "column";
     wait until ready;

     spread towards SE_HighBuildingRoofTopCenter within 1.5; 
     wait until ready;

   // phase
   phase "wait for business";     
     on (contact)
       {
         abort;
         defend towards SE_HighBuildingRoofTopCenter 
           from SE_HighBuildingSniperRoom;
         wait until ready;
         continue with phase "wait for business";
       };
     wait forever;
  };
Even the insert command (putting the Clandestine Management team, consisting solely of Sabotage, into the game) takes some time (especially for larger teams). It is essential to wait until the team is ready (has completed insertion) before issuing the next command.

There are a few exceptions to the sequential issuing of commands to a team. You can define specify 'what-to-do-when-something-happens' behavior early in the plan. When (and only when) that something happens, the team will be issued those special commands instead.
In the example above, as soon as Sabotage is in position, he is told to react specially to any enemy contact. The 'special' commands (following 'on (contact)' and between accolades '{' and '}' are not issued immediately, but only when Sabotage gets in touch with his attackers.
Instead, after Sabotage learns how to deal with contacts, he is not executing that behavior but instead receives the next command: he's going to wait forever (until something exceptional happens).

When something special happens, it is important not to wait for the team to complete the current command. Instead, it often is an issue of life and death to abort the current activity and instead act upon the threat. Therefor, the special 'on contact' sub plan issues an 'abort' command immediately. Upon receiving an abort command, Sabotage will stop executing his current command, and will be ready for new commands: some real defensive action.

A final exception to sequential issuing (and execution) of commands is are phases with a plan and the 'continue' command. When a team should repeatedly receive a series of commands, or when you want the team to continue again with normal activity (after dealing with exceptions), you can define a phase in the plan (and label it with a useful name), and instruct the team to continue with that phase again.
In the example above, Sabotage is issued to continue with phase "wait for business" when he has completed defending himself. When continuing with that phase, Sabotage is instructed to deal with contact again, and then waits again 'forever' for 'business'.

Team Behavior
Because a team plan contains commands for the team, it's important to fully understand how the team in general behaves.

The team members act like very well trained pro's. That means, you need not expect individual team members to become afraid and stop acting as a reliable team mate. They've learned to follow orders, and are prepared to risk their life in combat to have their team prevail. (The team, however, might judge it wiser to pull back during a combat situation, but, again, individual members won't pullback on their own).
Because of their training, they don't need a specific leader to guide them. Any member is as capable of directing his fellow team members when called for. Depending on member positions, the most appropriate member takes the lead to execute a command.

You can think of the team members as either:

  • being a group of LAN players within the same room, excitedly shouting info (threats, bandaging, etc.) towards their teammates, or
  • being a group of well trained operatives expensively equipped with earplugs and throat microphones, thus in constant and rapid communication with each other.
They will rapidly communicate the fact that a threat is spotted, and act upon that while taking into account their positions, spread, tactical advantages, etc.

There's no problem when a team become eliminated: all plan commands for that team are ignored.

Basic Plan Types
The 'Clandestine Management' / Sabotage plan listed above is actually a quite detailed and complex plan. Two simpler categories of team plans exist. Thus, there are three kinds of plans:

  1. player team plans
    This simple plan does just one thing: it inserts the team (containing one or more players) at a specific location. Such a plan looks like:
      plan "Hitman" // player
      {
         insert at NW_FarCornerOnsRoofTop using "column";
         wait until ready;
      };
    That doesn't look to hard to write, does it?

  2. patrol / snipe team plans
    Another category of simple plan is for teams that 'just' patrol or snipe. Because the patrol and snipe commands themselves contain permission to engage at will, there is no need to define any exceptional behavior. And because the team can spend the complete mission patrolling or sniping, there's no need for additional commands. Thus, such a plan looks like:
      plan "Protection Copy" // team of patrolling bots
      {
         insert at S_SouthCenterUnderneathRamp using "column";
         wait until ready;
         
         patrol (area_S_SouthCenterUnderneathRamp, 
                 area_W_Parking_SndFloor, area_E_AtBridge);
      };
    Only three commands for many minutes of action!

  3. detailed plans
    Detailed plans typically insert the team, define how to deal with exceptions, and then instruct the team to perform normal business (wait, move around).
    In dealing with exceptions, the script writer has a bit more control over the team's behavior: attack, defend, advance or pullback upon contact.

    The above plan is a good example of a detailed plan. Of course, you might be able to construct even more detailed and complex plan. However, there is the proverb that "no plan survives first contact".

Different kinds of commands
To construct scripts, you have different kinds of commands at your disposal. These commands are discussed in more detail below this list:

insert command
Purpose:
Insert team into map. The format listed after 'using' denotes the formation - column should be used.

Example:
  insert at S_SouthCenterUnderneathRamp using "column";

Problems and Hints:
Team need not necessarily be inserted at the start of the mission.
Without being inserted a team cannot receive any instructions (except for wait).
Inserting a team too large to fit the selected location (a small room) crashes CGF.

patrol command
Purpose:
Have team patrol all or a selected list of areas on the map. The team will patrol continuously for the remainder of the mission (unless given an 'abort' command).
In their patrol, the team will select visit all (specified) areas in a efficient but varying way. The team will take care to visit the areas in an order that allows them to visit many areas in a limited time. However, the order is partially random.

To patrol, the team will spread out and move along walls/thru dark areas (where possible) from area to area. Occasionally, the point man will wait for the team to assemble again, typically in a cover position. The tail man will check his 'six'.
The patrolling team is prepared to engage threats immediately (and suspend patrolling for the time of the engagement). Various team tactics are at the team's disposal. After the engagement (because the team took out the threats, or lost sight of the tracks), the patrol will tend to the visit the engagement location during their subsequent patrolling activity.
Examples:
  patrol (area_S_SouthCenterUnderneathRamp, area_E_AtBridge);

  patrol;

Problems and Hints:
Script should define at least two areas.
Explicit area list should contain at least two areas.
Team should be able to reach each area to be patrolled (bad route files crash CGF here). If the map has areas in unreachable sections, you need to specify explicitly which areas to patrol.
In current version, the patrolling team will tend to engage even in unfavorable cases (for example, being outgunned 5 to 1). This will change in future versions.

snipe command
Purpose:
Have team snipe from a specific location towards another location. AI will determine the snipers and spotters in the team (the team will always have at least as many snipers as spotters). Snipers engage at will and change tactics to normal combat when faced with nearby threats. Snipers typically move among a couple of useful (AI determined) sniper positions and cover positions. Spotters spot, briefly engage threats (and communicate threat position to sniper), and hide.

Examples:
  snipe from SE_HighBuildingRoofTopEdge
        towards S_SouthCenterBuildingTop;

Problems and Hints:
Sniper 'from' location should provide line of sight to 'towards' location.
Currently, snipe AI doesn't deal with nearby threats (by changing tactics).
Spotter likely to move around to silly locations.

attack command
Purpose:
Have team fight offensively against any threats. Team will engage, advance and pursuit threats when applicable (various team tactics are at the team's disposal). Team won't pullback. After losing contact, the team will regroup (perform the required (p)reloading and bandaging) and then is ready for new commands.

Examples:
  attack towards SE_HighBuildingRoofTopCenter;

Problems and Hints:
The 'towards' location is often ignored.
Currently, attack does not execute bounding overwatch advance automatically.

defend command
Purpose:
Have team fight defensively against any threats. Team will engage threats, and pullback from threats when applicable (various team tactics are at the team's disposal). Team won't pursuit threats. After losing contact, the team will regroup (perform the required (p)reloading and bandaging) and then is ready for new commands.

Examples:
  defend towards SE_HighBuildingRoofTopCenter
          from SE_HighBuildingSniperRoom;

Problems and Hints:
If the team pulls back, it will be towards the 'from' location.
Currently, defend does not change into pullback automatically.

advance command
Purpose:
Have team fight move up to a location employing bounding overwatch. In the presence of threats, front most members will adjust their path to benefit from cover from enemy fire, whereas tailing members will provide suppression fire.
When the team meets threats too close to their position and path, the team will suspend their maneuver to fully engage the targets, and continue the maneuver afterwards.
Upon arriving at the destination, the team will assemble in formation (the one specified after 'using' - typically "column") and then is ready for new commands.

Examples:
  advance towards parkingtopsniper using "column";

Problems and Hints:
CGF crashes when the destination location does not provide sufficient space to assemble in (in the specified formation).
The AI still has problems due to members blocking each other. The chances of blocking increase for larger team sizes. Basically, advance works best for teams of 3 to 5 members.
The current beta contains a silly bug that prevents members from discovering decent stop positions near edges.

pullback command
Purpose:
Have team fight pullback to a location employing bounding overwatch. In the presence of threats, tailing members will provide suppression / cover fire.
Upon arriving at the destination, the team will assemble in formation (the one specified after 'using' - typically "column") and then is ready for new commands.

Examples:
  pullback to parkingtopsniper using "column";

Problems and Hints:
Pullback is a command typically used in an 'on (contact)' situation, when you are sure about the current location of the team (they are not close to the destination).
CGF crashes when the destination location does not provide sufficient space to assemble in (in the specified formation).
The current beta contains a silly bug that prevents members from discovering decent stop positions near edges.

moveup command
Purpose:
Have team move up to a location in a fast, no frills way. Upon arrival, the team assembles in the specified formation (typically "column"). The team then is ready for new commands.
Note that the team doesn't respond to threats unless you specify so in the script (using an 'on (contact)').

Examples:
  moveup to parkingtopsniper using "column";

Problems and Hints:
CGF crashes when the destination location does not provide sufficient space to assemble in (in the specified formation).

spread command
Purpose:
Have team members take up dispersed defensive positions towards a specified location. Typically used immediately after a team has been inserted or has assembled. As soon as all members have taken up the defensive positions, the team is ready for new commands.
The 'within' duration provides an limit to the 'spread': it specifies the distance (in travel time) from the original location in which is searched for good defensive locations. Small durations of two seconds or less work best.
Note that the team doesn't respond to threats unless you specify so in the script (using an 'on (contact)').

Examples (Sabotage in urban_hitman_8.cgf):
  insert at C_RoomCorner using "column";
  wait until ready;
  spread towards C_RoomDoorEntrance within 0.5;
  // ... further on-contact behavior etc.

Problems and Hints:
Current beta doesn't provide completely predictable results.
Doesn't work well for large durations.

assemble command
Purpose:
Have team members regroup in specified formation at specified location. Team members move to the formation in a fast, no frills, way. Assemble won't be used that often; it makes solely sense to reassemble a team when you need to have the complete team take up defensive positions (using the 'spread' command).
Note that the team doesn't respond to threats unless you specify so in the script (using an 'on (contact)').

Examples:
  assemble at parkingtopsniper using "column";

Problems and Hints:
CGF crashes when the destination location does not provide sufficient space to assemble in (in the specified formation).

radio command
Purpose:
Have team send radio (actually: teamplay chat) message to all the members (actually: players) in the team's force (thus the message will reach members in other teams as well).

Examples:
  radio "a message to all force members";

Problems and Hints:
The radio command is special in that it can be executed while the team is execution another command. For example, you can have the team send radio commands while it is executing a defend command.

signal code command
Purpose:
Have team issue some 'go' code to other teams in the force (whether they are waiting for that code or not). This can be used to synchronize actions (often: attacks) between multiple teams in a force.

Examples:
  signal code "Red";

Problems and Hints:
From CGF 0.90 onwards, the player will be able to issue go-codes as well (a command bound to one of his keys). To reduce the amount of key binding necessary, it makes sense to restrict the actual codes used to the following: 'Red', 'Blue', 'Green' and 'Yellow'.
See the 'on (code)' and 'wait for code' commands on how to respond to signalled codes.

on (contact) { ... } command
Purpose:
Instruct the team in advance on how to deal with the exceptional 'enemy contact' situation. After being instructed, the team can continue performing other activities. As soon as the 'contact' is made, the team will start executing the 'on contact' specified commands.

Note that as soon as the team has executed the 'on contact' instructions, the team needs to be instructed again with the same or other instructions to deal with contact. You'll typically define a phase before the 'on contact' behavior, and instruct the team to continue with that phase again (see the example below).
Note also that you typically want the team to respond immediately to contact, no matter what the team was doing at the time of contact. Therefor, you need to have the team abort it's current activity. You use the 'abort' command for that (see the example).
Each time you define 'on contact' behavior, the previous definition (if any) is forgotten.

Examples (from Sabotage in urban_hitman_1.cgf):

     spread towards SE_HighBuildingRoofTopCenter within 1.5; 
     wait until ready;

   // phase
   phase "wait for business";     
     on (contact)
       {
         abort;
         defend towards SE_HighBuildingRoofTopCenter 
           from SE_HighBuildingSniperRoom;
         wait until ready;

         // make sure to reinstruct team before 
         // finishing dealing with the exception
         continue with phase "wait for business"; 
       };

     wait forever; // wait for contact

Problems and Hints:
There is no need to define on contact behavior for teams that patrol or snipe (though you can do so).

on (code "Code") { ... } command
Purpose:
Instruct the team in advance on how to act when upon receiving the specified go-code. After being instructed, the team can continue performing other activities. As soon as the go-code is received is made, the team will start executing the 'on code' specified commands.

Typically, a team is only issued a go-code once, and subsequently, there is little need to re-instruct the team.

The code itself is issued by another team using the 'signal code' command.

Examples:
  on (code "Red")
    {
      abort;
      // ... activity ...
    };

Problems and Hints:
If the team won't execute any other commands but instead is solely waiting for the go code, it's better to just use the 'wait for code' command.

abort command
Purpose:
Have team abort any current execution of a command (if any), and be ready for new commands. Typically used to respond to exceptions (enemy contact, reception of a go-code).


Examples:
  on (contact)
    {
      abort; // stop executing current command
      // ... new commands ...
    };

Problems and Hints:
There is no use in issueing the abort command unless dealing with on contact / on code exceptions.

phase (definition) command
Purpose:
Define a specific phase in the team's plan, so they can (at some time) continue with that phase (again).
A team aborts sequential execution of the commands upon receiving a 'continue with phase' command. The team will then start executing the commands listed immediately below the specified phase.

A phase command is not really executed. A team can continue with a phase without having already 'executed' that phase definition.

Examples (from Sabotage in urban_hitman_1.cgf):

     spread towards SE_HighBuildingRoofTopCenter within 1.5; 
     wait until ready;

   // phase
   phase "wait for business";     
     on (contact)
       {
         abort;
         // combat actions ...

         // make sure to reinstruct team before 
         // finishing dealing with the exception
         continue with phase "wait for business"; 
       };

     wait forever; // wait for contact


Problems and Hints:
It helps to provide useful names for the phase.

continue with phase command
Purpose:
Instruct the team to continue with the commands immediately following the phase definition as the next commands to execute.
See the 'phase' command above for more info.

wait command
Purpose:
Force a specific delay before issueing the next command. You might even use the delay command to postpone insertion of the team.
The delay is specified in seconds, with 0.1 second precision.

Examples:
  wait 10;

  wait 0.5;

Problems and Hints:
Use 'wait forever' if you want to wait for a long time.

wait forever command
Purpose:
Force a 'infinite' delay before issueing the next command (that command won't be issued, actually).
You typically use a wait forever when you want to have a team 'camp' after having positioned and instructed that team to deal with contact.

Examples:
  wait forever;

Problems and Hints:
Nope. (Actual waiting time is about 20,000 seconds :) ).

wait until ready command
Purpose:
Delay issueing the next command to the team until the team has completed its current command.
Because the issueing of a command takes 0.1 second and the execution of a command takes much longer (in general), you want to wait issueing another command.

Examples (Sabotage in urban_hitman_8.cgf):
  insert at C_RoomCorner using "column";
  wait until ready; // wait until team has been fully inserted
  spread towards C_RoomDoorEntrance within 0.5;

Problems and Hints:
Not issueing the appropriate wait until ready is likely to crash CGF.

wait until code command
Purpose:
Delay issueing the next command to the team until the team has received a specified go-code.
The go-code will be issued by another team using the signal code command.

If you need the team to execute other commands while 'waiting' for the go-code, use the on (code) command.

Examples:
  insert at C_RoomCorner using "column";
  wait until ready; // wait until team has been fully inserted

  // upon receiving code Red, start advance
  wait until code("Red");
  advance towards parkingtopsniper using "column";

Problems and Hints:
See signal code command for more info.



Editing Mission Locations
When writing or editing missions, a important part of the time is spent on defining locations, and getting the appropriate coordinates for them (see here).

To speed up mission development, CGF 0.81 and later versions allow you to define, view and add locations in-game for both new and existing missions.
You can do so as follows:

  1. load up AQ2/CGF with a map for which a terrain file (<mapname>.srp, in action/terrain) is available, but don't run/load a mission!

  2. (only if you want to add locations to an existing mission)
    load the mission (for example, actcity2_survival1.cgf) by typing on the console:

      mission read actcity2_survival1.cgf

  3. just walk to the spot where you need a location, and type (on the console):

      location alocationname

    And repeat! You can pick any locationname you want (as long as don't contain exotic symbols), but please make sure the name is unique.

  4. you can display the locations already created in the map as follows:

      terrain show locations

    Each location will be highlighted by a stack of three blue balls. These blue balls will be present for some 120 seconds.

  5. when you're done adding locations, you can write the modified mission (if you've read a mission), or mission skeleton (if you started from scratch) to a file (for example, actcity2_newmission.cgf) in the action/missions directory:

      mission write actcity2_newmission.cgf

    After saving the mission, you can edit the mission file with your favorite mission editor.



CGF Scripting Documentation Change Log
date D
description (incl. link)
Mar 12, 2000 o
documented how to create/edit mission locations in-game
Nov 26, 1999 o
new list (CGF0.80)of maximal load-out
'successor script' option when meeting objectives
Aug 19, 1999 o
fixed area style documentation (combinations of styles not allowed)
Aug 16, 1999 o
minor grammar and html fixes
Aug 14, 1999 +

+
+
added 'not'(!) condition in mission objectives
(forgotten to mention this one initially)
added more information on team AI behavior
added change log
Aug 7, 1999 +
initial version



Questions? Comments? Suggestions? Send them here
CGF is written by William van der Sterren. All content is © William van der Sterren unless otherwise stated.
Action Quake2 is written by, and ©, the A-Team
CGF website designed by Cube, © 1999. Best viewed @ 800x600 HiColor in a version 4 browser.
And yes, a large number of bots were hurt during the photo sessions (but they fell in the line of duty).

This site uses the PNG (Portable Network Graphics) image format.
If your browser cannot display this image format please go to this site to download a plug-in.