Mods and Rulesets

Getting Started (7.1)

Under construction! Come back later!

Getting Started

This section assumes basic knowledge of the Army Men RTS scripting language learned in Section 5: Creating a Single Player Mission, and it is highly recommended you read through that section before proceeding.

Scripting and making rulesets for multiplayer has quite a few differences than single player, and involves thinking from every player's viewpoint rather than an individual team's. In SP, most of your scripts explicitly call a team by their name, which, while possible in MP, is not recommended and usually leads to making separate configs for each team. Instead, you should be calling teams using Relation() and @.engine.name, two things we'll discuss below. Another difference in SP vs. MP is compatibility with allies. This involves using the Relation() tag quite a bit, as well as making sure the scripts, especially triggers, work correctly for ALL allies. These will all be covered in this document.

It is recommended you unpack (using Dr Packer) a ruleset, such as King of the Hill (koth.x), and look at the files as we go along.

How Scripts Run

As mentioned earlier, SP and MP scripting differs quite a bit. SP is much more focused on specific teams, while an MP script must be duplicated for every team that is playing, and thus the way you use variables, Team(), Relation(), and a few other things is a bit different. StartActionAvailable() is used to define what variables and objectives are given to the available players. These objectives are located in whatever types file you have defined.

Multilanguage tools & rulesets

In all of AMRTS's rulesets and SP missions, you will find messages like #game.message.whatever. These are references to a Multilanguage file, called "[language].cfg" where language is what language it is in (such as English.cfg). The purpose of this is to make all of AMRTS have no references to one language. This file is the only file that should not be modified, and not have a special version in a ruleset's directory. You should just write in plain text, and have somebody help convert your mod to other languages if necessary.

File Structure

Before you begin making your ruleset, you should have a good idea of how the files are laid out, so that you know what is available to you. Rulesets are broken down into four different config file types:

Mod.cfg
The mod.cfg file contains the basic information about the ruleset, as well as what variables are needed by the players, the system, and what files to include in the ruleset.

Types file
Generally named after the ruleset, such as 'protect_types.cfg', the types file can contain all the objectives of the particular ruleset, as well as special object configs, particle configs, etc, that you don't want to store in another file. It's basically the Jack-of-all-trades file. You can include many types files if you feel the need to organize them that way (for instance, an objects file, a particles file, etc.)

Exec file
Exec files are used for manipulating variables, interface controls, keybindings, and other functions not in the types file.

AI file
If necessary, you may include AI files into the game. This is mostly used in Personalities, but can be used in rulesets as well.

Mod.cfg Breakdown

Here is a quick overview of the mod.cfg file:

Description("#mods.ruleset.protecthq.title");
Description is to give your ruleset a name when selecting it. Unfortunately, you cannot use the Multilanguage tool to put in your description, so you just have to type in the name here.

Author("Army Men RTS Team");
Self Explanatory. Put your name in here.

Homepage("http://www.pandemicstudios.com");
Another easy one - if you have a homepage, put it here.

Private(1);
A holdover from Dark Reign 2, where you could potentially choose a ruleset to play a map with. Setting this to 1 would restrict this ruleset to only maps that require it. Since rulesets always work this way now, you can use any value, or just drop this line entirely.

Files("Type")
This includes all Type files into the ruleset. Type files are things that appear ingame, most often objectives and objects.

Files("Type")
{
  Add("koth_types.cfg");
  Add("koth_countdown.cfg");
}

Files("Exec")
This includes any exec files into the ruleset. Exec files are interface elements, or commands to execute, such as binding keys.

Files("Exec")
{
  Add("koth_exec.cfg");
}

Files("AI")
This includes any AI settings you want. AI files are specifically things used by AI logic, meaning formations, scripts, recruit types. Personalities use them, but rulesets mostly don't.

Files("AI")
{
  Add("assault_AI.cfg");
}

StartActionClient()
Action given to the client team, used for global mission variables. This StartAction only gets created once. Notice Global variables have a ~. In front of them instead of @.

StartActionClient()
{
  CreateVarFloat("~.koth.pretimerh", 300);
  CreateVarInteger("~.koth.preminutesh", 4);

  CreateVarFloat("~.koth.timerh", 240);
  CreateVarInteger("~.koth.minutesh", 4);
}

StartActionTeam("Team")
Action given to a team based on name (used to specify a particular team to get objectives). Generally this is used to specify special teams that are not controlled by a player.

StartActionTeam("worship")
{
  NewObjective("assault.countdown");
  NewObjective("assault.counttimer");
}

StartActionAvailable()
Action given to a team based on the 'Available To Players' button pressed in the team setup.

StartActionAvailable()
{
  CreateVarFloat("@.timeleft", 180);
  NewObjective("protecthq.check");
  NewObjective("common.killallenemy");
  NewObjective("common.aivictory");
  NewObjective("common.eliminate");
}

StartActionAll()
Action given to all teams.

StartActionAll()
{
  NewObjective("koth.objective");
  NewObjective("koth.prebuild");
  NewObjective("common.eliminate");
  NewObjective("common.aivictory");
  NewObjective("common.killallenemy");
}

StartActionSide("Side")
Action given to a team based on side. Mostly useless in Army Men RTS, even if you create a custom side.

Standard Rulesets vs. Map Specific Rulesets

One of the first things to decide when making a Ruleset is if you want it to work on ANY map or only maps that are made specifically for it. Map Specific rulesets give you much more flexibility to create, but you sacrifice having many maps to play on. There are quite a few ways of using different map features work well with a ruleset:

Regions
These are probably used the most in Map Specific Rulesets. Using the InRegion() function, you can trigger events when any specific type of unit, enemy, ally or self, moves in a region. You can also spawn units in regions. For an example of a complex InRegion() check, look at King of the Hill's koth_types.cfg file.

Tags
Tags are useful for attaching to units or other assets that you want to control later on in your mod. To create them, see Section 4: Creating a Multiplayer Map - Making Good MP Maps.

Assets
Using certain assets can help in any part of a ruleset. For instance, King of the Hill has picket fences blocking the hill that get deleted after five minutes.

Strategies & Design
See Section 4: Creating a Multiplayer Map - Making Good MP Maps.

Files that can be in a ruleset

Just about any file can be placed in a ruleset's directory, from textures, configs and audio clips to 3d objects and more. If you want to override specific files the game uses, naming files the same name and placing them in the ruleset directory should work perfectly.

Variables

Variables are covered a bit in SP, but are used much more in MP. They're really essential to rulesets and let you do just about everything

Global Variables
A global variable is something that every player's objectives can affect and see. Defining a global variables is done on StartActionClient(). For instance, in King of the Hill, four global variables are set, two for both timers. All other teams can see these four variables, and if a team takes the hill, the objective tracks that team's remaining hill time into the variable. These are the best way to get each team's scripts to communicate with one another. (Ex: ~.koth.timerh)

Local Variables
Local variables are variables only seen by the one team running a script. All other teams cannot see what one team's local variables are. These are used mostly for triggers, timers and the like. (Ex: @.timeleft)

Special Variables
If you want a team's specific name, listen up: @.engine.name gives the name of the team. All maps currently have teams named 'TeamX' where X is a number 1-8, except for assault, which has the team 'assault.' This variable can come in handy in all sorts of situations, such as Control Freak, which gives @.engine.name to a global variable, and checks to see if all five global variables for each control point are controlled by allies. In Assault, @.engine.name is used for the regions which a Dezigner piece is spawned.

CreateVarInteger
This creates an integer variable that stores whole numbers.

CreateVarFloat
This creates a floating-point variable, that can store any number or decimal.

CreateVarString
This creates a string variable that you can store text and/or numbers in.

NOTE: Variables can only have TWO periods in them, no more. (i.e. no @.ab.bc.cd, but @.ab.bc-cd will work)

More Information on variables is available in Section 5: Creating a Single Player Mission - Variables.

Common Objectives

Army Men RTS has a few common functions that you can call using NewObjective(). These are all defined in types_common.cfg (in case you want to look at them directly.) They are as follows:

common.timer.win
Win condition (triggers end of game). This gives a 3 second delay between satisfying the victory conditions and getting the win condition (delay is there to allow for self destruction of units and other win condition objectives you want completed, such as earthquakes or whatnot.)

common.timer.lose
Lose condition (triggers end of game). This also has a 3 second delay. If you feel it's easier to have teams lose than have the other team(s) win, you can use this. Keep in mind that this will end the game for ALL players, not just those who lost!

common.timer.eliminate
This eliminates a specific player (and thus their team), but allows the game to continue. 4 second delay.

common.eliminate
This checks to see if a player's units have been destroyed, at which point that player will get common.timer.eliminate.

common.killallenemy
This checks to see if all other enemy player's have been destroyed. If so, player gets common.timer.win.

common.aivictory
This checks to see if an AI player has won, and if so, triggers common.timer.win. An AI "wins" if it has no living human opponents left, so if two humans are playing with two computer allies each, the first player to die will trigger this objective, ending the game entirely.

Logging Types (cash, kills, etc)

In some rulesets, a condition known as 'Tally' will allow you to load up a variable with information about how many units a player constructed, destroyed, etc, how much taelon they collected, etc. These can be very useful not only for simple rulesets using one of these as a win condition, but for advanced ruleset/map combinations that involve a series of tallies to trigger actions.

  Condition("Tally")
  {
    Statistic("KillsSelf");
    Amount(10);
    Operator(">=");
    Var("@.self");
  }

Radio Events & Objective Text

An important part in a ruleset is to make sure players know what they are supposed to do, and if they've done something right or wrong. Combining messages seen in the console and at the top of the screen with Objective Text in pause menu will let you get your message across clearly.

Two types of Radio Events exist, Location Messages and Game Messages. You can attach a variable to a message if you need.

Often times the naming convention of messages usually follows what your mod is called. In King of the Hill, for example, all objectives and radio events began with 'koth.', such as 'koth.radio.' This is not required, but is recommended to help you debug.

As we've learned, variables play a very big part in rulesets. You can use variables in Radio Events as shown below:

ConfigureRadioEvent("modname.radio")
{
  Messages()
  {
    LocationMessage::Self("modname.selfhelp", "@.engine.name");
  }
}

ConfigureLocationMessage("modname.selfhelp")
{
  Interval();
  Sound();
  Message()
  {
    Type("Message::Console");
    Add("You, {1:s}, need some serious help.");
  }
}

Notice that a variable was called in the message using {1:s}. Since @.engine.name will show up as a STRING, you must use {1:s}. If you had an integer, it would be {1:i} and if you had a float it would be {1.0:f}.

If you want to call a specific player or team in a message, using #player and #team in the variable section in GameMessage:: and LocationMessage:: will give you the player's name, and if you use #team, the player's team will show (not used at all in mods, but it's there.)

NOTE: If a string variable is used in a message, no other variables will work in it.

Also, if you JUST want a blip to show up, you do not have to fill in the Message() at all, instead you can add 'BlipColor()' with an appropriate RGBA color. Only Location Messages give blips, so this is not useful for a Game Message.

ConfigureLocationMessage("modname.beep")
{
  Interval();
  Sound();
  Message();
  BlipColor(255, 100, 0, 100);
}

Remember, Location Messages require a region to give a blip. So when you are calling a location message, you MUST give a region (that has been defined in the studio) for that message to show up on.

    TriggerTeamRadio("modname.beep")
    {
      Region("beepland");
    }