.xs scripting in Age of Empires II: Definitive Edition

.xs scripting for is a new functionality added to Age of Empires II: Definitive Edition, available with the November 2020 update. It adds another layer of scripting functionality to the existing trigger system in the scenario editorand in random map scripts.

This is official reference for RMS/Trigger functions accessible in AoE2. For a more in-depth guide, including a reference for beginners in programming, as well as the usage of Rules and other XS features, please check out The UGC Guide for XS created by the community!

Summary:

  • Make sure function names are unique. (e.g. having multiple functions called Function() will cause a conflict)
  • Make sure the function returns the defined type (e.g. bool Function() should return a boolean expression)
  • If you wrote a function inside of the Scenario Editor, it will be compiled into an .xs file called default0.xs. These functions will be called automatically for that specific Script Call.
  • You must place your .xs scripts in resources\_common\xs
  • You can find the Constants.xs file with all constants (like for instance cAttributeStone) and effects (SetAttribute)that can be used within some functions in \resources_common\xs
  • When entering the Script Name inside the Editor, you do not need to include the final .xs extension.
  • You can define as many functions as you want inside an .xs file.
  • To call functions in the Editor, you only need to pass in the function name (e.g. if you had a function called doesPlayerHaveFood() you will only need to write doesPlayerHaveFood in the Script Call textbox.)

Scenario Editor Functions

xsTriggerVariable Returns the value of the desired Trigger Variable.

Syntax:

xsTriggerVariable(long triggerVariableId)

// Returns the value of Trigger Variable 0.

int getTriggerVariable()

{

return (xsTriggerVariable(0));

}

xsSetTriggerVariable Sets a trigger variable to the desired value.

Syntax:

xsSetTriggerVariable(long triggerVariableId, long value)

// Set Trigger Variable 0 to 100.

void setTriggerVariable()

{

xsSetTriggerVariable(0, 100);

}

xsEffectAmount Allows you to modify a unit or building with research-style type effects.

Set playerId to -1 to apply the change to all players.

Syntax:

xsEffectAmount(long effect, long itemName, long type, float value, long playerId)

// Modify players starting resources, in this case, set starting stone to 50.

void setDefaultStone()

{

xsEffectAmount(cModResource, cAttributeStone, cSetAttribute, 50, -1)

}

xsResearchTechnology Allows you to research a technology for a specific player. This can be done forcefully without any condition checking.

You can also check to research the technology if it’s available.

This function will return true if research was successful or false if it was not.

Syntax:

xsResearchTechnology(long techID, bool force, bool techAvailable, long playerID)

// Research Loom for player 2.

void researchLoom()

{

xsResearchTechnology(22, true, false, 2);
}

xsGetPlayerNumberOfTechs Returns the number of technologies a player can research.

Syntax:

xsGetPlayerNumberOfTechs(long playerID)

// Get the number of technologies from player 3.

int getPlayerThreeNumTechs()

{

return (xsGetPlayerNumberOfTechs(3));

}

Random Map Script Functions


xsEffectAmount Allows you to modify a unit or building with research-style type effects.

Set playerId to -1 to apply the change to all players.

Syntax:

xsEffectAmount(long effect, long itemName, long type, float value, long playerId)

// Modify players starting resources, in this case, set starting stone to 50.

void setDefaultStone()

{

xsEffectAmount(cModResource, cAttributeStone, cSetAttribute, 50, -1)

}

Shared Functions


xsChatData Sends a chat with the desired message/variable. This is useful for testing.

Syntax:

xsChatData(const char* text, long value)

// Chat player 1’s food.

void chatFood()

{

int food = xsPlayerAttribute(1,0);

xsChatData(“Player one food: %d” , food);

}

xsPlayerAttribute Returns the value of the desired player attribute.

Syntax:

xsPlayerAttribute(long playerId, long attribute)

// Get the food amount of player 1.

int getPlayerOneFood()

{

return (xsPlayerAttribute(1, 0));

}

xsSetPlayerAttribute Sets the desired player attribute to the value specified.

Syntax:

xsSetPlayerAttribute(long playerId, long attribute, float value)

// Set player 1 food to 100.

void setPlayerOneFood()

{

xsSetPlayerAttribute(1, 0, 100);

}

xsGetNumPlayers Returns the number of players in a match (Excluding Gaia) E.g. if there is 2 players in a match, only 2 is returned.

Syntax:

xsGetNumPlayers()

// Get the number of players.

void getNumberOfPlayers()
{
int numPlayers = xsGetNumPlayers();
xsChatData("Players = %d", numPlayers);
return;
}

xsGetPlayerCivilization Returns the civilization ID of a specific player.

Syntax:

xsGetPlayerCivilization(long playerID)

// Get the civilization ID of player 1

void getPlayerOneCiv()

{

int civId = xsGetPlayerCivilization(1);
}

xsGetPlayerInGame Returns true if the specific player is in the game still, if the specified player has been defeated, resigned or dropped from the match, it will return false.

Syntax:

xsGetPlayerInGame(long playerID)

// Check if player 4 is still in the match.

bool isPlayerFourInGame()

{

return (xsGetPlayerInGame(4));
}

xsGetGameTime Returns the elapsed game time (in seconds).

Syntax:

int xsGetGameTime()

// Get the game time.

void getGameTime()

{

int gameTime = xsGetGameTime();
}

xsGetVictoryPlayer Returns the player ID of who will win using relics, wonder, monastery or monuments.

Syntax:

int xsGetVictoryPlayer()

// Get the winning player ID

void getWinningPlayer()

{

int playerId = xsGetVictoryPlayer();

}

xsGetRandomNumber Generate a random number.

Syntax:

int xsGetRandomNumber()

// Get a random number

void rand()

{

return xsGetRandomNumber();
}

xsGetRandomNumberLH Generate a random number using between low and high.

Syntax:

int xsGetRandomNumberLH(int low, int high)

// Generate a random number between 5 - 10.

void randLH()
{

return xsGetRandomNumberLH(5, 10);

}

xsGetRandomNumberMax Generate a random number using a maximum value.

Syntax:

int xsGetRandomNumberMax(int max)

// Generate a random number with a maximum value of 3.

void randMax()

{

return xsGetRandomNumberMax(3);
}

xsCeilToInt Receives a float and return an int rounded up.

int xsCeilToInt(float number)

// Round up a float value 4.1

void roundUp()

{

return xsCeilToInt(4.1);

}

xsGetObjectAttribute Get an attribute from an object, such as HP.

Syntax:

float xsGetObjectAttribute(int playerId, int masterId, int attribute, int damageClass)

// get P1's Archer HP

xsGetObjectAttribute(1, 4, cHitpoints)

// get P1’s Archer’s pierce attack

xsGetObjectAttribute(1, 4, cAttack, cDamageClassPierce)

xsGetPlayerName Get a player’s name

Syntax:

string xsGetPlayerName(int playerId)

// get P1's Name

xsGetPlayerName(1)

xsIsObjectAvailable Check if an object is enabled (available)

bool xsIsObjectAvailable(int objectId, int playerId)

// check if P1 can make archers:

xsIsObjectAvailable(4, 1)

xsGetTechState Get the technology’s state

Syntax:

int xsGetTechState(int techId, int playerId)

The possible tech states are:

NotReady = 0
Ready = 1
Queued = 4
Researching = 2
Done = 3
Disabled = -1
Invalid = -2

// Get the tech state for Loom for P1:

xsGetTechState(22, 1)

xsGetTechName Get a tech’s name.

Syntax:

string xsGetTechName(int techId, int playerId, bool internal = false)

// get the name of tech 22 (Loom) for P1

xsGetTechName(22, 1)

xsGetObjectName Get an object’s name.

Syntax:

string xsGetObjectName(int objectId, int playerId, bool internal = false)

// get the name of object 4 (Archer) for P1

xsGetObjectName(4, 1)

bitCastToFloat Perform a bit cast from int to float

Syntax:
float bitCastToFloat(int value)

bitCastToFloat(1065353216)

// returns 1.0

bitCastToInt Perform a bit cast from float to int

Syntax:
float bitCastToInt(int value)

bitCastToInt(1.0)

// returns 1065353216

Unit Functions


xsGetPlayerUnitIds Get a list of reference unit IDs

Syntax:

int xsGetPlayerUnitIds(int playerId, int objectId, int arrayId = -1)

// get P1's Archers

xsGetPlayerUnitIds(1, 4)

// get all villagers

xsGetPlayerUnitIds(1, 904)

xsGetUnitOwner Get the owner player ID of the given unit ID.

Syntax:

int xsGetUnitOwner(int playerId)

// Get the player of unit ID 0

xsGetUnitOwner(0);

xsGetUnitTargetId Get the target unit ID of the given unit ID.

Syntax:

int xsGetUnitTargetId(int unitId)

// Get the target unit of unit ID 0

xsGetUnitTargetId(0);

xsDoesUnitExist Check if the given unit ID exist on the map.

Syntax:

bool xsDoesUnitExist(int unitId)

// Check if unit ID 0 exists

xsDoesUnitExist(0);

xsGetUnitPosition Get the position of the given unit ID on the map.

Syntax:

vector xsGetUnitPosition(int unitId)

// Get the position of unit ID 0

xsGetUnitPosition(0);

xsGetUnitMoveTarget Get the destination of the unit if it is moving, cInvalidVector otherwise.

Syntax:

vector xsGetUnitMoveTarget(int unitId)

// Get the position of unit ID 0

xsGetUnitMoveTarget(0);

xsGetUnitMoveTarget Get the destination of the unit if it is moving, cInvalidVector otherwise.

Syntax:

vector xsGetUnitMoveTarget(int unitId)

// Get the destination of unit ID 0

xsGetUnitMoveTarget(0);

xsGetUnitGroupId Get the group ID (formation) of the given unit ID.

Syntax:

int xsGetUnitGroupId(int unitId)

// Get the group ID of unit ID 0

xsGetUnitGroupId(0);

xsGetGroupMoveTarget Get the destination of the unit group if it is moving, cInvalidVector otherwise.

Syntax:

vector xsGetGroupMoveTarget(int groupId)

// Get the destination of group ID 0

xsGetGroupMoveTarget(0);

xsGetUnitName Get a unit’s name

Syntax:

string xsGetUnitName(int unitId, bool internal = false)

// get unit 0's name

xsGetUnitName(1)

xsGetUnitAttribute Get an attribute from a unit on the map, such as HP.

Syntax:

float xsGetUnitAttribute(int unitId, int attribute, int damageClass)

// get unit 0's Max HP

xsGetUnitAttribute(0, cHitpoints)

// get unit 0's Pierce damage

xsGetUnitAttribute(0, cAttack, cDamageClassPierce)

xsGetUnitHitpoints Get a unit’s current HP.

Syntax:

float xsGetUnitHitpoints(int unitId)

// get unit 0's Current HP

xsGetUnitHitpoints(0)

xsSetUnitHitpoints Set a unit’s current HP.

Syntax:

float xsSetUnitHitpoints(int unitId, float value)

// set unit 0's HP to 50000

xsSetUnitHitpoints(0, 50000)

xsGetUnitBuildPoints Get a unit’s current BP.

Syntax:

float xsGetUnitBuildPoints(int unitId)

// get unit 0's Current BP

xsGetUnitBuildPoints(0)

xsSetUnitBuildPoints Set a unit’s current BP.

Syntax:

float xsSetUnitBuildPoints(int unitId, float value)

// set unit 0's BP to 200

xsSetUnitBuildPoints(0, 200)

xsGetUnitObjectId Get a unit’s object ID

Syntax:

int xsGetUnitObjectId(int unitId)

// get unit 0’s object Id

xsGetUnitObjectId(0)

xsGetUnitCopyId Get a unit’s copy ID. This describes which object this unit was last upgraded into

Syntax:

int xsGetUnitCopyId(int unitId)

// get unit 0’s current copy Id

xsGetUnitCopyId(0)

xsGetObjectCopyId Get an object’s copy ID. This describes which object this unit was last upgraded into

Syntax:

int xsGetObjectCopyId(int playerId, int objectId)

// Get the current copy id of player 1's archers

xsGetObjectCopyId(1, 4)

xsGetUnitClass Get a unit’s class (+900, see Constants.xs)

Syntax:

int xsGetUnitClass(int unitId)

// get unit 0’s class

xsGetUnitClass(0)

xsGetObjectClass Get an object’s class (+900, see Constants.xs)

Syntax:

int xsGetObjectClass(int playerId, int objectId)

// Get the class of player 1's archers

xsGetObjectCopyId(1, 4)

xsGetUnitType Get a unit’s type (see Constants.xs)

Syntax:

int xsGetUnitType(int unitId)

// get unit 0’s type

xsGetUnitClass(0)

xsGetObjectType Get a unit’s type (see Constants.xs)

Syntax:

int xsGetObjectType(int playerId, int objectId)

// Get the object type of player 1's archers

xsGetObjectType(1, 4)

xsGetUnitAttributeTypesHeld Get an array containing the types of resources that a unit is holding

Syntax:

int xsGetUnitAttributeTypesHeld(int unitId)

// Get a list of the type of resources held by unit 1

xsGetUnitAttributeTypesHeld(1)

xsGetUnitAttributeHeld Get the amount of a particular resource held by a unit

Syntax:

int xsGetUnitAttributeHeld(int unitId, int attributeId)

// Get the amount of wood held by unit 1

xsGetUnitAttributeHeld(1, cAttributeWood)

// Get the amount of the first resource held by this unit

xsGetUnitAttributeHeld(1)

xsSetUnitAttributeHeld Set the amount of a particular resource held by a unit

Syntax:

int xsSetUnitAttributeHeld(int unitId, float value, int attributeId)

// Set the amount of wood held by unit 1 to 10

xsSetUnitAttributeHeld(1, 10.0, cAttributeWood)

// Set the amount of the first resource held by this unit to 10

xsSetUnitAttributeHeld(1, 10.0)

xsGetUnitCharge Get a unit’s current charge.

Syntax:

float xsGetUnitCharge(int unitId)

// get unit 0's Current charge

xsGetUnitCharge(0)

xsSetUnitCharge Set a unit’s current charge.

Syntax:

float xsSetUnitCharge(int unitId, float value)

// set unit 0's charge to 50

xsSetUnitCharge(0, 50)

xsSetUnitPosition Sets a unit’s position

Syntax:

bool xsSetUnitPosition(int unitId, vector position, bool checkCollision = true)

xsSetUnitPosition(0, vector(5, 5, -1)) // teleports unit 0 to 5, 5
xsGetWorldPlayerId Gets the world player (lobby slot) from the scenario player index

Syntax:

int xsGetWorldPlayerId(int scenarioPlayerId)

xsGetWorldPlayerId(5) // find out which world player Aqua
xsGetGarrisonedInUnitId Gets the unit that this unit is garrisoned in (or -1 if not garrisoned)

Syntax:

int xsGetGarrisonedInUnitId(int unitId)

xsGetGarrisonedInUnitId(0) // returns the id of the unit that unit 0 is garrisoned in
xsGetGarrisonedUnitIds Gets all the IDs for units that are garrisoned in this unit

Syntax:

int xsGetGarrisonedUnitIds(int unitId)

xsGetGarrisonedUnitIds(0) // returns an array of unit IDs garrisoned inside unit 0
xsGetPlayerType Get whether a player is human or AI

Syntax:

int xsGetPlayerType(int playerId)

xsGetPlayerType(1); // get the player type of P1
xsRemoveUnit Removes a unit from the map

Syntax:

bool xsRemoveUnit(int unitId)

xsRemoveUnit(0); // removes unit 0 from the map
xsGetDiplomacy Get the diplo of source player against target player

Syntax:

int xsGetDiplomacy(int sourcePlayerId, int targetPlayerId)

xsGetDiplomacy(1, 2); // returns the stance of p1 against p2
xsSetDiplomacy Set the diplo of source player against target player

Syntax:

bool xsSetDiplomacy(int sourcePlayerId, int targetPlayerId, int diploState, bool mirror = false)

xsSetDiplomacy(1, 2, cDiplomacyAlly); // make p1 ally p2

xsSetDiplomacy(1, 2, cDiplomacyAlly, true); // make p1 ally p2 and p2 ally p1 back

xsGetColorMood Get the color mood of the current map

Syntax:

int xsGetColorMood()

xsGetColorMood(); // get the current color mood
xsSetColorMood Set the color mood of the current map

Syntax:

bool xsSetColorMood(int colorMood, int interval)

xsSetColorMood(cColorMoodWinter, 10); // transition the color mood to winter over 10 seconds
xsGetDifficulty Get the difficulty setting in the lobby

Syntax:

int xsGetDifficulty()

xsGetDifficulty() // get the AI difficulty
xsCreateUnit Create a unit on the map with the specified options

Syntax:

int xsCreateUnit(int objectId, int playerId, vector location, bool foundation = false, bool playCreatedSound = true, bool checkCollision = true)

xsCreateUnit(cArcher, 1, vector(4, 4, -1)) // create an archer at 4, 4 on the map for P1

Read/Write Functions


xsCreateFile Opens a file with the .xsdat extension for writing to. Returns true if the file was successfully opened to write to. Setting append to false will result in a new file being written and the old one being lost.

The file name will use the name of the scenario and random map. Files can only be a maximum of 1 megabyte. Each file is unique to each player’s profile.

bool xsCreateFile(bool append)

// Create a brand new xs data file.

void main()
{

xsCreateFile(false);
}

xsOpenFile Opens a .xsdat file for reading only. Will return true if file was successfully opened for reading.

bool xsOpenFile(string filename)

// Open a file for reading

bool load()

{

return xsOpenFile("default0");
}

xsWriteString Writes a string to the file that has been opened using xsCreateFile. Returns true if the write was successful.

bool xsWriteString(string data)

// Write a string to the xs data file.

bool save()

{

return xsWriteString("test");
}

xsWriteInt Writes an integer to the file that has been opened using xsCreateFile. Returns true if the write was successful.

bool xsWriteInt(int data)

// Write an integer to the xs data file.

bool save()

{

return xsWriteInt(25);
}

xsWriteFloat Writes a float to the file that has been opened using xsCreateFile. Returns true if the write was successful.

bool xsWriteFloat(float data)

// Write a floatto the xs data file.

bool save()

{

return xsWriteFloat(12.34);
}

xsWriteVector Writes a vector to the file that has been opened using xsCreateFile. Returns true if the write was successful.

bool xsWriteVector(vector data)

// Write a vector to the xs data file.

bool save()

{

return xsWriteVector(vector(2.0, 2.0, 2.0));
}

xsReadString Reads a string from the currently opened file at the current file position. Returns a string if successfully read.

string xsReadString()

// Read a string from the xs data file

extern string text = "";

bool load()

{

text = xsReadString();
}

xsReadInt Reads an integer from the currently opened file at the current file position. Returns a int if successfully read.

int xsReadInt()

// Read an int from the xs data file

extern int value = 0;

bool load()

{

value = xsReadInt();
}

xsReadFloat Reads a float from the currently opened file at the current file position. Returns a float if successfully read.

float xsReadFloat()

// Read a float from the xs data file

extern float value = 0;

bool load()

{

value = xsReadFloat();
}

xsReadVector Reads a vector from the currently opened file at the current file position. Returns a vector if successfully read.

vector xsReadVector()

// Read a vector from the xs data file

extern vector vectordata = vector(0.0, 0.0, 0.0);

bool load()

{

vectordata = xsReadVector();
}

xsSetFilePosition Sets the current position in file directly for the currently opened file. Returns true if it was successful.

bool xsSetFilePosition(int pos)

// Set the file position (buffer) to the beginning

void parse()

{

// Set position to the 4th byte in the file.

xsSetFilePosition(4);
}

xsOffsetFilePosition Jump forward or backward from the current file position by using the desired data type. Returns true if it was successful.

Supported data types are:

cOffsetString (assumes current position is at a string)

cOffsetInterger

cOffsetFloat

cOffsetVector

bool xsOffsetFilePosition(int dataType, bool forward)

// Skip reading an integer

void load()

{

// Skips an integer (jumping forward 4 bytes)
xsOffsetFilePosition(cOffsetInterger, true);
}

xsCloseFile Closing the currently opened file (either by xsCreateFile or xsOpenFile) Returns true if a file was successfully closed. // Close the currently opened file.

void load()

{

xsCloseFile();
}

Functions for Creating, Editing, and Removing Tasks from Units


xsTaskAmount Allows you to specify the value of a field in a task which will be used in either a following xsTask or xsRemoveTask function call.

Syntax:

xsTaskAmount(taskFieldId, float value)

// Modify King Henry II's weapon damage.

const int cWorkValue1=0;

void modifyKingHenryII()

{

xsTaskAmount(cWorkValue1, 2);

}

xsTask Insert a new task, if a task with the specified key fields does not already exist.

Set playerId to -1 to apply the change to all players.

Syntax:

xsTask(masterUnitId, actionType, targetMasterUnitId, playerId)

// Modify King Henry II's weapon damage.

const int cAura = 155;

const int cHenryII = 1040;

const int cWorkValue1=0;

const int cPlayer1=1;

void modifyKingHenryII()

{

xsTask(cHenryII, cAura, cMilitia, cPlayer1); // add an aura to Henry II for Player One that affects Militia team and his allies

}

xsRemoveTask Remove a task from a master unit, if a task with the specified key fields already exists.

Set playerId to -1 to apply the change to all players.

Syntax:

xsRemoveTask(masterUnitId, actionType, targetMasterUnitId, playerId)

// Modify King Henry II's weapon damage.

const int cAura = 155;

const int cHenryII = 1040;

const int cWorkValue1=0;

const int cPlayer1=1;

void modifyKingHenryII()

{

xsRemoveTask(cHenryII, cAura, cMilitia, cPlayer1); // remove the first task that matches the indicated fields

}

xsGetObjectTaskCount Get the number of tasks on a data object

Syntax:

int xsGetObjectTaskCount(int objectId, int playerId)

int xsGetObjectTaskCount(cArcher, 1); // get the number of tasks on the archer object of player 1
xsGetUnitTaskCount Get the number of tasks on a unit on the map.

Syntax:

int xsGetUnitTaskCount(int unitId)

int xsGetObjectTaskCount(0); // get the number of tasks on the unit with ID 0 on the map
xsGetObjectTaskAmount Copies the specified task from the data object into XS

Syntax:

int xsGetObjectTaskAmount(int objectId, int playerId, int taskId)

int xsGetObjectTaskAmount(cArcher, 1, 0); // get the first task on the archer object of player 1
xsGetUnittTaskAmount Copies the specified task from the unit on the map into XS

Syntax:

int xsGetUnitTaskAmount(int unitId, int taskId)

int xsGetUnitTaskAmount(0, 0); // get the first task on the unit with ID 0 on the map
xsGetTaskAmount Gets a field from the XS task struct

Syntax:

float xsGetTaskAmount(int taskFieldId)

xsGetTaskAmount(cTaskAttrTaskType); // get the task type of the XS task struct
xsModifyObjectTasks Adds/Edits/Removes a task from a data object

Syntax:
bool xsModifyObjectTasks(int objectOrClassId, int playerId, int taskId, bool edit = false)

bool xsModifyObjectTasks(cArcher, 1, 0) // inserts the XS task struct into the archer object for player 1

bool xsModifyObjectTasks(cArcher, 1, 0, true) // overwrites the first task of the data object with the values from the XS task

bool xsModifyObjectTasks(cArcher, 1, -1) // deletes the first task on the data object

xsModifyUnitTasks Adds/Edits/Removes a task from a unit on the map

Syntax:
bool xsModifyUnitTasks(int unitId, int taskId, bool edit = false)

Same as above, except the int objectId, int playerId parameters are replaced with int unitId to affect a specific unit on the map.

XS scripts within RMS

To use an XS script in a Random Map Script, do the following:

  • At the top of your RMS file (before <PLAYER_SETUP>) add #includeXS scriptname.xs
    • “scriptname.xs” is the name of the file located in your resources\_common\xs folder. You can put the file name in quotation marks if it contains spaces. Paths relative to the “xs” folder are allowed.
  • In the XS file, create a void main() function definition. All of its content will be executed upon loading the Random map script. You can use all general functions and RMS-specific functions (described at the top of this document).

How to write functions which accept parameters

If you want to write a function which accepts parameters (e.g. you want to chat the amount of food a player has) you must initialize your parameter variables.

Example:

Example on how a function written inside the editor looks: