Advanced RMS: Part 5 – Triggers in RMS

By Matei of Woad Creations
created 9/10/03

Triggers can be used to make your script more than a standard Supremacy/Death Match/Lightning game and add events and interactivity to it. They are mainly used in scenarios, but can also be used in random maps. If you haven’t tried using triggers before, you should open the scenario editor and make a couple of them before trying to use them in a random map script. Visit the Scenario Editor FAQ on AoM Heaven for information on how triggers work in scenarios. The various RMS guides list the different RMS functions to do with triggers but do not really explain all aspects of using triggers in RMS, so this section will cover some common questions on triggers.

A trigger is essentially a “rule” that has several conditions and several effects. If the trigger is active and all its conditions are true, then it will fire and perform its effects. If the trigger is looping, it will be able to fire again when the conditions become true again; if not, it will only fire once during the course of the game, and then be deactivated (it may be activated again later by another trigger, however). Triggers can be marked as run immediately to fire their events before the game even begins (for example, a trigger that grants or disables technologies for players should do this); such triggers should not be looping and should not have any conditions. Triggers that run in-game can have a priority between 1 and 5, which dictates how often the game checks their conditions (it should only be higher for triggers that need precise timing; the default value of 3 works fine otherwise).

Note that all of your triggers need a name, and each trigger should have a unique name. If two triggers have the same name, you’ll get an error. Usually it is simple to come up with a unique name for each trigger, but if you have a variable number of triggers you might want to keep a global “uniqueID” integer variable; then name each new trigger “trigger_”+uniqueID, and increase uniqueID by 1 after you use it, or even create a makeUniqueID() function that increases the variable by 1 and returns it. This can also be a useful technique when placing areas or object definitions, since they must also have unique names.

A Short Trigger FAQ

Here are some commonly asked questions about triggers and their answers:

Q: Where can I find a list of trigger conditions and effects and the names of their parameters?
A: Check out this file. It is a .txt format copy of the file trigger.xml in the Age of Mythology\ rigger folder, which lists all the effects and conditions available in AoM. The file contains some XML code – the easiest way to find your required effect or condition is to use the Edit | Find (Ctrl-F) command in Notepad and search for the name of the effect or condition you want. The condition or effect parameters, and their default values, will be listed there.

Q: Where can I find numerical ID’s for trigger parameters such as technologies, unit stances, and technology statuses?
A: Check out this file. It is a copy of part of the AoM default AI file, which lists many useful constants. Test that all your techs are researched by placing a unit for each player that would benefit from them and seeing if it has them when the game starts.

Q: How can I specify a location, such as (x=0.5, z=0.5), in a trigger?
A: You have to use a string in the form xInMetres,0,zInMetres. The following function converts a location (x,z) in fractions to a location string that you can then pass to rmSetTriggerEffectParam:
string pointLoc(float fracX = 0, float fracZ = 0) {
    return(""+rmXFractionToMeters(fracX)+",0,"+rmZFractionToMeters(fracZ));
}

Q: How can I place a Gastraphetes, Son of Osiris or Einherjar? Some objects’ trigger names are not the same as game names.
A: Check outthis file. It contains the trigger names (also used for simply placing objects) of all units. The least obvious is Gastraphetes, which is called Crossbowman. Einherjar is Einheriar. Son of Osiris is Pharaoh of Osiris. Other units also have different names.

Q: How can I use a unit in a trigger condition/effect?
A: You have to get the unit’s in-game ID when you place it, and convert it to a string to use in rmSetTriggerEffectParam. Here’s an example that places an Arkantos for player 2 at the center of the map and stores its unit ID in the string unitID:
int id = rmCreateObjectDef("arkantos_p2");
rmAddObjectDefItem(id, "Arkantos", 1, 0.0);
rmSetObjectDefMinDistance(id, 0.0);
rmSetObjectDefMaxDistance(id, 0.0);
rmPlaceObjectDefAtLoc(id, 2, 0.5, 0.5);
string unitID = rmGetUnitPlaced(id,0);

Q: How can I an army in a trigger condition/effect?
A: You can create armies using rmCreateArmy(playerNumber, armyName). If you want an empty army, just use rmCreateArmy and store its return value in some ID variable. If you want an army to start off with certain units in it, here’s how you might do it (this example places a player 2 hill fort at the center of the map and stores the army ID in the integer armyID):
int id=rmCreateObjectDef("hillFort");
rmAddObjectDefItem(id, "Hill Fort", 1, 0.0);
rmSetObjectDefMinDistance(id, 0.0);
rmSetObjectDefMaxDistance(id, 0.0);
rmPlaceObjectDefAtLoc(id, 2, 0.5, 0.5);
int armyID = rmCreateArmy(2, "hillFort");
rmAddUnitsToArmy(2, armyID, id);
Note that armies always have a player number associated which you have to use whenever you reference the army, in rmAddTriggerEffectParamArmy for example, and that army IDs are ints, not strings.

Q: I get weird text when trying to use “%” characters in in-game messages. Why?
A: Use a double percent sign (%%) if you want to print a percent sign. Percent signs in strings have a special meaning in C++, the language in which AoM was written, so you shouldn’t have single percent signs in an in-game message string.

Q: What is the last (bool) parameter in rmAddTriggerConditionParam and rmAddTriggerEffectParam?
A: This value should always be false. It’s used internally by AoM.

Q: Trigger code in RMS is so long and messy! How can I make it quicker to develop?
A: Use functions, lots and lots of them. For example, I made a grantTech function which simply adds a trigger effect for enabling a certain tech (it will be added to whatever trigger is active when the function is called), and a sendChat function which adds a send chat effect. In general, anything repetitive and time-consuming should be put in a function. It saves a lot of typing!

Back to the RMS Section