Updated September 8, 2026
XS scripting functionality was extended to AI scripting in AoE2:DE, with many different features. These are documented in the community-based UGC XS Scripting Reference, and this article is designed to be used alongside that guide. For learning how to use the various XS functions, use the UGC website. This article will focus on which XS functions can be safely used in AI scripting without cheating so that tournament hosts can be confident about allowing AI scripts to enter that use XS code. A list provided without commentary is included at the top, and the rest of the article will explain the commands in more detail. Click on the links in the cheating list to jump to commentary for each function category.
These XS functions should not be used in AI scripts:
| Non-Functions | XS rules shouldn't be used |
| All Rules Functions | xsDisableRule, xsDisableSelf, xsEnableRule, xsIsRuleEnabled, xsSetRulePriority, xsSetRulePrioritySelf, sSetRuleMinInterval, xsSetRuleMinIntervalSelf, xsSetRuleMaxInterval, xsSetRuleMaxIntervalSelf, xsEnableRuleGroup, xsDisableRuleGroup, xsIsRuleGroupEnabled |
| Techs Functions | xsResearchTechnology |
| Player Functions | xsEffectAmount, xsSetPlayerAttribute, xsDeclareVictory |
| Tasks Functions | xsTaskAmount, xsResetTaskAmount, xsModifyObjectTasks, xsModifyUnitTasks, xsTask, xsRemoveTask |
| Units & Objects Functions | xsCreateUnit, xsRemoveUnit, xsGetUnitOwner, xsSetUnitPosition, xsSetUnitHitpoints, xsSetUnitBuildPoints, xsSetUnitAttributeHeld, xsSetUnitCharge |
| Map Functions | xsSetColorMood |
| UI Functions | xsPlaySound, xsDisplayInstructions, xsClearInstructions, xsDisplayTimer, xsClearTimer, xsGetTimerRemaining |
Many XS functions have full access to info about every single player. Such functions are obviously cheating if used on enemy players, and may also be considered cheating by some tournament hosts if used on ally players. Unfortunately, XS doesn't have a way to automatically get the playerId of the current AI player, like my-player-number, so you can't dynamically reference the AI's player number by default. A workaround is to store my-player-number in a goal, then call an XS function with xs-script-call which uses xsGetGoal to read this goal value and set a global XS myPlayerNumber variable to that value. Then, you can use myPlayerNumber as the playerId parameter for each of these functions to prevent cheating.
Global variables (variables outside of XS functions, like those in /xs/Constants.xs) are separately created for each player that loads the .xs file that creates them, so you don't have to worry about other AI players overwriting this variable with their own XS code.
| Techs Functions | xsGetTechState, xsGetTechAttribute |
| Player Functions | xsGetPlayerUnitIds, xsPlayerAttribute |
| Tasks Functions | xsGetObjectTaskCount, xsObjectTaskCount, xsGetUnitTaskCount, xsUnitTaskAmount |
| Units & Objects Functions | xsGetObjectAttribute, xsGetUnitAttribute, xsDoesUnitExist, xsGetUnitPosition, xsGetUnitName, xsGetObjectName, xsGetUnitTargetUnitId, xsGetUnitMoveTarget, xsGetUnitGroupId, xsGetGroupMoveTarget, xsIsObjectAvailable, xsGetUnitHitpoints, xsGetUnitBuildPoints, xsGetUnitObjectId, xsGetUnitCopyId, xsGetObjectCopyId, xsGetUnitClass, xsGetObjectClass, xsGetUnitType, xsGetUnitAttributeTypesHeld, xsGetUnitAttributeHeld, xsGetUnitCharge, xsGetGarrisonedInUnitId, xsGetGarrisonedUnitIds, xsGetObjectCount, xsGetObjectCountTotal, xsObjectHasAction, xsIsObjectValid, xsGetPlayerNumberOfObjects |
These functions are allowed to be used, but should be used carefully.
| Array Functions | (can use excessive memory if not managed properly) xsArrayCreateInt, xsArrayCreateFloat, xsArrayCreateBool, xsArrayCreateString, xsArrayCreateVector, xsArrayResizeInt, xsArrayResizeFloat, xsArrayResizeBool, xsArrayResizeString, xsArrayResizeVector |
| Map Functions | (these functions only work in custom scenarios) xsTriggerVariable, xsSetTriggerVariable |
| UI Functions | (can cause a desync in some situations because of language localization differences) xsGetLocale, xsGetString, xsGetPlayerAttributeName, xsGetDamageClassName, xsGetLocalPlayerId, xsSendChat |
| Miscellaneous Functions | (these apparently do nothing or are of little use to anyone besides devs) xsDumpArrays, xsGetFunctionId, xsBreakPoint, xsAddRuntimeEvent |
Here is a list of functions which can be used without cheating concerns.
| All Vector Functions | xsVectorGetX, xsVectorGetY, xsVectorGetZ, xsVectorSetX, xsVectorSetY, xsVectorSetZ, xsVectorSet, xsVectorLength, xsVectorNormalize |
| All Array Functions | xsArrayCreateInt, xsArrayCreateFloat, xsArrayCreateBool, xsArrayCreateString, xsArrayCreateVector, xsArraySetInt, xsArraySetFloat, xsArraySetBool, xsArraySetString, xsArraySetVector, xsArrayGetInt, xsArrayGetFloat, xsArrayGetBool, xsArrayGetString, xsArrayGetVector, xsArrayResizeInt, xsArrayResizeFloat, xsArrayResizeBool, xsArrayResizeString, xsArrayResizeVector, xsArrayGetSize |
| All Maths Functions | abs, sqrt, pow, sin, cos, tan, asin, acos, atan, atan2, atan2v, exp, ceil, floor, bitCastToFloat, bitCastToInt, xsCeilToInt, ln, log2, log10, round, radians, degrees, dist, bitAnd, bitOr, bitXor, bitNot |
| All Randomization Functions | xsGetRandomNumber, xsGetRandomNumberLH, xsGetRandomNumberMax |
| Techs Functions | xsGetTechName |
| Player Functions | xsGetHandicapMultiplier, xsGetWorldPlayerId, xsGetPlayerCivilization, xsGetPlayerInGame, xsGetPlayerNumberOfTechs, xsGetPlayerName, xsGetPlayerType, xsGetDiplomacy, xsSetDiplomacy, xsGetDifficulty |
| Tasks Functions | xsGetTaskAmount (if the stored task struct doesn't belong to another player) |
| Map Functions | xsGetMapName, xsGetMapId, xsGetMapHeight, xsGetMapWidth, xsGetColorMood, xsGetMapSeed, |
| All Game Info Functions | xsGetNumPlayers, xsGetTime, xsGetGameTime, xsGetTurn, xsGetVictoryType, xsGetVictoryPlayer, xsGetVictoryPlayerForSecondaryGameMode, xsGetVictoryTime, xsGetVictoryTimeForSecondaryGameMode, xsGetVictoryCondition, xsGetVictoryConditionForSecondaryGameMode |
| UI Functions | xsChatData, xsGetPlayerColorTag |
| All File I/O Functions | xsOpenFile, xsWriteString, xsWriteInt, xsWriteFloat, xsWriteVector, xsReadString, xsReadInt, xsReadFloat, xsReadVector, xsOffsetFilePosition, xsCloseFile, xsGetFilePosition, xsGetDataTypeSize, xsGetFileSize |
| All AI Scripting Functions | xsGetGoal, xsGetStrategicNumber, xsSetGoal, xsSetStrategicNumber |
| Miscellaneous Functions | xsGetContextPlayer, xsSetContextPlayer |
Here are explanations why these XS functions should or should not be allowed in AI tournaments. This section covers every function category, according to how functions are categorized on the UGC XS Scripting Reference.
XS rules shouldn't be used because they do not operate independently for each AI player. Instead, XS rules seem to function globally, independent of AI players, which can easily throw off any player-specific code the rules contain, such as xsGetGoal. The only code that exists outside of XS function calls should be code that creates variables. XS variables, thankfully, are created and managed separately for each AI player.
See the section above about how XS rules shouldn't be used. Since rules shouldn't be used for AIs, XS functions that affect rules shouldn't be used either.
None of these functions are cheating. All they do is modify or get information about existing vector variables, which store 3-dimensional points.
Arrays are purely ways to store data, and therefore they don't cheat. Arrays are perhaps the most useful tool that XS scripts provide for AI scripters. However, be careful about when creating new arrays or increasing their size to make sure that your script doesn't repeatedly create new arrays or increase their size over and over again, causing massive memory usage. If XS code repeatedly creates new arrays throughout the game, the game can eventually crash after using up all of the computer's memory. Instead, make sure that you only create your arrays once. To be able to reference your created arrays outside of a called function, you can create a global XS variable at the start of the game which stores the array ID when it's created so that it can be referenced later.
All math functions are available to be used. The sqrt and trig functions can be especially useful to AI scripters since these calculations are difficult to replicate in AI .per code.
Non cheating. These functions just generate a random number.
xsResearchTechnology researches the tech immediately, so it is a cheating command. xsGetTechState and xsGetTechAttribute allow you to get tech info about other players, even enemies. Some tournament hosts may allow getting tech info about allies, but it's probably best to only use these functions for the AI player itself. xsGetTechAttribute can be particularly effective to get the research time or location of certain techs, because there are no .per equivalents.
xsEffectAmount is basically the same as fe-cc-effect-amount, which is almost always cheating. To make things simple and transparent for tournament hosts, please use fe-cc-effect-amount instead to implement any permitted non-cheating cosmetic changes. xsGetPlayerUnitIds is essentially a DUC search, but it works on any given player regardless of exploration. xsPlayerAttribute is basically a resource-amount check on any given player. xsSetPlayerAttribute modifies a player's given resource-amount, which is obviously cheating. xsDeclareVictory force declares victory for a player and is obviously cheating. All other player functions are permitted since they get information about players that every player has access to.
These functions are mostly for scenario designers. Tasks in this case refers to the particular tasks or action abilities that a particular unit can do, such as converting, garrisoning, guarding, combat, etc. These functions don't check a unit's current action, but check which tasks an object can potentially do. Most Tasks functions allow you to change the default task abilities available to a unit, which is obviously cheating, but some merely check what task types a unit type currently has, which is permitted if used on objects the AI owns.
These functions are basically XS' version of checking object data. The xsCreateUnit function immediately places a unit on the map at a given location, which is obviously cheating. xsRemoveUnit and the various function that set/change unit attributes are obviously cheating. The rest of the commands can be used as long as the units are owned by the AI itself, but the .per commands are probably easier to use. However, of particular interest are the xsGetGroupMoveTarget, xsGetGarrisonedInUnitId, and xsGetGarrisonedUnitIds functions, which don't have .per equivalents. They might be useful to AI scripters.
AIs shouldn't use xsSetColorMood since it affects all players, but it's just a cosmetic change. All other map functions are permissible since they get map info that is known from the start of the game, but xsTriggerVariable and xsSetTriggerVariable only work in custom scenarios.
All game info functions get global information about the game, so all of these functions are permitted.
Many of these functions can cause desync issues if different players use different languages, such as in a multiplayer game. Really, the only function that should be used in this category is xsChatData, which is essentially up-chat-data-to-self and is the only debugging chat command available in XS.
These functions allow you to create, read, and write external hex files. These functions are all permitted because each file is unique for each player. However, these files are hex files and require more data manipulation to write and read data at the correct position. They are also overwritten each game, and you can't specify a file name or save location. up-log-data is much easier to use, and it's likely a better alternative to these functions.
These functions are all permitted. If used from a function called by xs-script-call, they will only get and set values for the current AI player.
The only functions in this category that are useful are xsGetContextPlayer and xsSetContextPlayer. xsSetContextPlayer must be used before using any of the File I/O functions. The context player also affects xsEffectAmount. It's possible that xsBreakPoint might be useful, but it probably has the same effect as fe-break-point.