{"updated":"2026-10-12T14:41:15Z","source":"https://community.bistudio.com/wiki/Main_Page","count":60,"items":[{"name":"Anything","title":"Anything","type":"topic","url":"https://community.bistudio.com/wiki/Anything","revid":330444,"updated":"2022-09-15T21:31:40Z","aliases":["Any"],"markdown":"A variable of type **Anything** may be of any data types **or** Nothing.\n\n> [!WARNING]\n> Even though some commands list data type **Anything** as possible value, passing nil (Nothing) to a command might cause it not to work:\n>\n> ```sqf\n> str nil; // while the documentation for str states it takes Anything, nil / Nothing will cause it to not execute.\n> ```\n\n### See Also\n\n- nil\n- isNil\n- Nothing","sections":[{"heading":null,"level":1,"markdown":"A variable of type **Anything** may be of any data types **or** Nothing.\n\n> [!WARNING]\n> Even though some commands list data type **Anything** as possible value, passing nil (Nothing) to a command might cause it not to work:\n>\n> ```sqf\n> str nil; // while the documentation for str states it takes Anything, nil / Nothing will cause it to not execute.\n> ```"},{"heading":"See Also","level":3,"markdown":"- nil\n- isNil\n- Nothing"}],"categories":["Magic Types"],"groups":["Data Types"]},{"name":"Arma 3: Actions","title":"Arma 3: Actions","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Actions","revid":376089,"updated":"2025-08-09T20:25:33Z","aliases":["ArmA 3: Actions","Arma 3 Actions","action/Arma 3 Actions List"],"markdown":"> [!NOTE]\n> - See ArmA: Armed Assault: Actions for an introduction to Actions\n> - Not to be confused with playAction\n\n## General Syntax\n\n ***unit* action [*\"actionType\"*, *parameter(s)*]**\n\n|  |  |\n|---|---|\n| *unit*: | Object. Can be any occupied vehicle or person that is not in a vehicle or also a Game Logic. |\n| *\"actionType\"*: | String. Name of the action, found in the CfgActions class. Not case sensitive. |\n| *parameter(s)*: | Various data types, dependant on the action used. The number of required parameters depends on the action type. |\n\n## Actions\n\n### ActiveSensorsOn\n\n|  |  |\n|---|---|\n| Description | Activates the vehicle's active sensor (radar). |\n| Syntax | *unit* action [\"ActiveSensorsOn\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"ActiveSensorsOn\", vehicle player];<br>``` |\n\n### ActiveSensorsOff\n\n|  |  |\n|---|---|\n| Description | Deactivates the vehicle's active sensor (radar). |\n| Syntax | *unit* action [\"ActiveSensorsOff\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"ActiveSensorsOff\", vehicle player];<br>``` |\n\n### AddBag\n\n|  |  |  |\n|---|---|---|\n| Description | Causes a unit to take backpack from another unit/vehicle or weaponholder. |  |\n| Syntax | *targetUnit* action [\"AddBag\", *sourceUnit*, *\"backpackName\"*] |  |\n|  | Where *targetUnit* is the person to receive a backpack (the action animation will be performed), *sourceUnit* is either another unit/vehicle or weaponholder containing the backpack. *\"backpackName\"* is the classname (string) of the backpack to be picked up. |  |\n| Note | Bags can be picked up at any distance. To drop bag use \"DropBag\" action. If several backpacks of the same class name exist in the container, the oldest will be added first. |  |\n| Examples | ```sqf<br>soldierOne action [\"AddBag\", soldierTwo, backpack soldierTwo];<br>```<br>```sqf<br>player action [\"AddBag\", car, typeOf firstBackpack car];<br>```<br>Swap player bag with parachute: <br>```sqf<br>player action [\"DropBag\", _plane, backpack player];<br>player action [\"AddBag\", _plane, \"B_Parachute\"];<br>``` |  |\n\n### ArtilleryComputer\n\n|  |  |  |\n|---|---|---|\n| Description | Opens up Artillery Computer display just like the one in action menu for a mortar. Unit has to be in gunner position or display will immediately close. |  |\n| Syntax | *unit* action [\"ArtilleryComputer\", *artillery*] |  |\n|  | Where *unit* is any unit, and *artillery* is the artillery weapon |  |\n| Example | ```sqf<br>soldierOne action [\"ArtilleryComputer\", mortarOne];<br>``` |  |\n\n### AutoHover\n\n|  |  |\n|---|---|\n| Description | Toggles auto-hovering on. Note that while the auto-hover status can be toggled on an AI crewed or even an empty vehicle, it will only affect a vehicle controlled by a human pilot. |\n| Syntax | *unit* action [\"AutoHover\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is capable of hovering. |\n| Example | ```sqf<br>chopperOne action [\"AutoHover\", chopperOne];<br>``` |\n\n### AutoHoverCancel\n\n|  |  |\n|---|---|\n| Description | Toggles auto-hovering off. Note that while the auto-hover status can be toggled on an AI crewed or even an empty vehicle, it will only affect a vehicle controlled by a human pilot. |\n| Syntax | *unit* action [\"AutoHoverCancel\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is capable of hovering. |\n| Example | ```sqf<br>driver chopperOne action [\"AutoHoverCancel\", chopperOne];<br>``` |\n\n### BackFromUAV\n\n|  |  |\n|---|---|\n| Description | Moves player control back from driver/gunner position of connected UAV. Does what \"Release UAV controls\" UI action does. |\n| Syntax | *unit* action [\"BackFromUAV\"] |\n|  | Where *unit* is the connected UAV unit. |\n| Example | ```sqf<br>getConnectedUAVUnit player action [\"BackFromUAV\"];<br>``` |\n\n### CancelAction\n\n|  |  |\n|---|---|\n| Description | Cancels an action in progress. The target unit will complete it is current animation, although the action itself will not be performed. |\n| Syntax | *unit* action [\"CancelAction\", *targetUnit*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetUnit* is any unit that is in the process of performing an action. |\n| Example | ```sqf<br>soldierOne action [\"CancelAction\", soldierOne];<br>``` |\n\n### CancelLand\n\n|  |  |\n|---|---|\n| Description | Cancels autopilot landing for an aircraft, including AI controlled aircraft. |\n| Syntax | *unit* action [\"CancelLand\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is currently performing an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"CancelLand\", planeOne];<br>``` |\n\n### CancelTakeFlag\n\n|  |  |\n|---|---|\n| Description | Cancels taking of a flag. The unit will complete the taking/action animation, but the flag will remain attached to it is current object. This action needs to be executed while the flag is being taken (which happens after the unit completes the taking/action animation) to prevent a unit taking the flag. For example, if a person is taking a flag from a flagpole, then the cancelTakeFlag action should be executed while the flag is descending the flagpole. |\n| Syntax | *unit* action [\"CancelTakeFlag\", *targetFlag*] |\n|  | Where *unit* is any unit that is currently taking a flag (no action animation is performed) and *targetFlag*' is a flag object. |\n| Example | ```sqf<br>westSoldierOne action [\"CancelTakeFlag\", eastFlag];<br>``` |\n\n### CollisionLightOff\n\n|  |  |\n|---|---|\n| Description | Turns off the collision lights of an air vehicle. |\n| Syntax | *unit* action [\"CollisionLightOff\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"CollisionLightOff\", vehicle player];<br>``` |\n\n### CollisionLightOn\n\n|  |  |\n|---|---|\n| Description | Turns on the collision lights of an air vehicle. |\n| Syntax | *unit* action [\"CollisionLightOn\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"CollisionLightOn\", vehicle player];<br>``` |\n\n### Deactivate\n\n|  |  |\n|---|---|\n| Description | Causes a unit to deactivate and take a active satchel charge placed by any unit. This action can be performed upon a satchel object from any distance.<br>This action also works for landmines created with createVehicle command:<br>```sqf<br>private _mine = \"ATMine_Range_Ammo\" createVehicle getPosATL player;    // create<br>player action [\"Deactivate\", player, mine];                            // deactivate<br>``` |\n| Syntax | *unit* action [\"Deactivate\", *targetUnit*, *targetObject*] |\n|  | Where *unit* is any unit (they will perform the action animation as if deactivating a satchel charge). *targetUnit* will have the deactivated satchel charge added to it is inventory. *targetObject* is the armed satchel object to be deactivated (class \"pipeBomb\" or \"timeBomb\"). |\n| Examples | ```sqf<br>soldierOne action [\"Deactivate\", soldierOne, mySatchelCharge];<br>``` |\n|  | ```sqf<br>soldierOne action [\"Deactivate\", soldierOne, nearestObject [soldierOne, \"pipeBomb\"]];<br>``` |\n\n### DeactivateMine\n\n|  |  |\n|---|---|\n| Description | Causes a unit to deactivate any armed landmine that is within about two meters of a unit. Neither unit requires the ability to disable landmines.<br>NOTE: This action works only with mines that have been spotted by player (marked with triangle). Use \"Deactivate\" if you need to deactivate any mine. |\n| Syntax | *unit* action [\"DeactivateMine\", *targetUnit*] |\n|  | Where *unit* is any unit, who will perform the action animation. The closest landmine to *targetUnit* will be deactivated. |\n| Example | ```sqf<br>soldierOne action [\"DeactivateMine\", soldierOne];<br>``` |\n\n### Diary\n\n|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"Diary\", *<target>*] |\n|  |  |\n| Example |  |\n\n### Disassemble\n\n|  |  |\n|---|---|\n| Description | Takes assembled weapon to parts (carry bags). Assembled weapon object reference may need to be kept for assembly. See also: enableWeaponDisassembly |\n| Syntax | *unit* action [\"Disassemble\", *weapon*] |\n|  | Where *unit* is any unit and *weapon* is assembled weapon |\n| Example | ```sqf<br>soldierOne action [\"Disassemble\", mortarOne];<br>``` |\n\n### DropBag\n\n|  |  |  |\n|---|---|---|\n| Description | Causes a unit to drop a backpack into another unit/vehicle. To drop backpack on the ground, a weaponholder object needs to be created first. |  |\n| Syntax | *sourceUnit* action [\"DropBag\", *targetUnit*, *\"backpackName\"*] |  |\n|  | Where *sourceUnit* is the person to drop a backpack (the action animation will be performed), *targetUnit* is either another unit/vehicle into which the backpack will be dropped or a weaponholder. *\"backpackName\"* is the classname (string) of the backpack to be dropped. |  |\n| Note | Bags can be dropped into other units at any distance. If targetUnit already has a backpack, sourceUnit's backpack will drop to the ground at targetUnit's feet, and be unavailable (for picking up/using). |  |\n| Examples | ```sqf<br>soldierOne action [\"DropBag\", soldierTwo, backpack soldierOne];<br>```<br>```sqf<br>private _gwh = \"Weapon_Empty\" createVehicle getPosATL player;<br>player action [\"DropBag\", _gwh, typeOf unitBackpack player];<br>// the reason \"Weapon_Empty\" type of weaponholder is used in this case is because<br>// unlike other weaponholders it is not autodeleted when empty and will not disappear before the action is complete.<br>// you should take care of deleting it after yourself. Alternatively use \"PutBag\" action.<br>```<br>```sqf<br>(unitBackpack player) setVariable [\"backpackOwner\", name player, true];<br>player action [\"DropBag\", car, typeOf unitBackpack player];<br>hint ((firstBackpack car) getVariable \"backpackOwner\");<br>```<br>Swap player bag with parachute:<br>```sqf<br>player action [\"DropBag\", _plane, backpack player];<br>player action [\"AddBag\", _plane, \"B_Parachute\"];<br>```<br>Transfer player's backpack to bob<br>```sqf<br>player action [\"DropBag\", bob];<br>``` |  |\n\n### DropMagazine\n\n|  |  |\n|---|---|\n| Description | Causes a person to drop a magazine either into another unit (both persons and vehicles), or onto the ground (creating a new WeaponHolder object). Magazines can be dropped into other units at any distance. |\n| Syntax | *unit* action [\"DropMagazine\", *targetUnit*, *\"magazineName\"*] |\n|  | Where *unit* is the person to drop a magazine (the action animation will be performed), *targetUnit* is either another unit into which the magazine will be dropped, or the same unit that is dropping the magazine. *\"magazineName\"* is the classname (string) of the magazine to be dropped (see the ArmA weapons list for magazine classnames). |\n| Examples | ```sqf<br>soldierOne action [\"DropMagazine\", soldierOne, \"30Rnd_545x39_AK\"];<br>``` |\n|  | ```sqf<br>soldierOne action [\"DropMagazine\", ammoCrateOne, \"30Rnd_545x39_AK\"];<br>``` |\n\n### DropWeapon\n\n|  |  |\n|---|---|\n| Description | Causes a person to drop a weapon and all associated magazines either into specified vehicle or weaponholder. Weapons can be dropped at any distance. |\n| Syntax | *unit* action [\"DropWeapon\", *targetHolder*, *\"weaponName\"*] |\n|  | Where *unit* is the person to drop a weapon (the action animation will be performed), *targetHolder* is either a vehicle or weaponholder. *\"weaponName\"* is the classname (string) of the CfgWeapons class. |\n| Examples | ```sqf<br>private _weaponHolder = \"GroundWeaponHolder_Scripted\" createVehicle getPosATL player;<br>player action [\"DropWeapon\", _weaponHolder, currentWeapon player];<br>```<br>```sqf<br>soldierOne action [\"DropWeapon\", unitBackpack soldierTwo, currentWeapon soldierOne];<br>player action [\"DropWeapon\", tank, \"arifle_MX_ACO_pointer_F\"];<br>``` |\n|  |  |\n\n### Eject\n\n|  |  |\n|---|---|\n| Description | Causes a person to eject out of the vehicle they are currently inside. If the unit was the driver of the vehicle, the vehicle will retain it is steering control input and it is engine will remain on. This action has a global effect when used on a local unit in multiplayer. If the vehicle parameter used is an moving aircraft, the ejecting person will use a parachute (and likewise if it is not an moving aircraft, no parachute will be used). |\n| Syntax | *unit* action [\"Eject\", *vehicle*] |\n|  | Where *unit* is the person to eject from their current vehicle, and *vehicle* is any vehicle (generally the vehicle *unit* is within). |\n| Example | ```sqf<br>soldierOne action [\"Eject\", vehicle soldierOne];<br>``` |\n\n### EngineOn\n\n|  |  |\n|---|---|\n| Description | Turns a vehicle's engine on. This command will not override an AI driver's desires. |\n| Syntax | *unit* action [\"EngineOn\", *targetVehicle*] |\n|  | Where *unit* is any unit, and *targetVehicle* is the vehicle to start it is engine. |\n| Example | ```sqf<br>soldierOne action [\"EngineOn\", vehicle soldierOne];<br>``` |\n\n### EngineOff\n\n|  |  |\n|---|---|\n| Description | Turns a vehicle's engine off. This command will not override an AI driver's desires. |\n| Syntax | *unit* action [\"EngineOff\", *targetVehicle*] |\n|  | Where *unit* is any unit, and *targetVehicle* is the vehicle to have it is engine turned off. |\n| Example | ```sqf<br>soldierOne action [\"EngineOff\", vehicle soldierOne];<br>``` |\n\n### FireInflame\n\n|  |  |\n|---|---|\n| Description | Ignites a fireplace object (from any distance). |\n| Syntax | *unit* action [\"FireInflame\", *targetObject*] |\n|  | Where *unit* is any unit(the action animation will be performed), and *targetObject* is the fireplace to be ignited. |\n| Example | ```sqf<br>soldierOne action [\"FireInflame\", firePlaceOne];<br>``` |\n\n### FirePutDown\n\n|  |  |\n|---|---|\n| Description | Extinguishes a fireplace object (from any distance). |\n| Syntax | *unit* action [\"FirePutDown\", *targetObject*] |\n|  | Where *unit* is any unit (the action animation will be performed), and *targetObject* is the fireplace to be extinguished. |\n| Example | ```sqf<br>soldierOne action [\"FirePutDown\", firePlaceOne];<br>``` |\n\n### FlapsUp\n\n|  |  |\n|---|---|\n| Description | Adjusts an aircraft's flaps upwards one notch. AI pilot's will instantly adjust their flaps to whatever setting they feel is suitable. |\n| Syntax | *unit* action [\"FlapsUp\", *targetVehicle*] |\n|  | Where *unit* is any unit (the action animation will not be performed), and *targetVehicle* is the aircraft to have it is flaps adjusted. |\n| Example | ```sqf<br>harrierOne action [\"FlapsUp\", harrierOne];<br>``` |\n\n### FlapsDown\n\n|  |  |\n|---|---|\n| Description | Adjusts an aircraft's flaps down one notch. AI pilot's will instantly adjust their flaps to whatever setting they feel is suitable. |\n| Syntax | *unit* action [\"FlapsDown\", *targetVehicle*] |\n|  | Where *unit* is any unit (the action animation will not be performed), and *targetVehicle* is the aircraft to have it is flaps adjusted. |\n| Example | ```sqf<br>harrierOne action [\"FlapsDown\", harrierOne];<br>``` |\n\n### Gear\n\n|  |  |\n|---|---|\n| Description | Opens inventory dialog for the player and plays the appropriate animation. The left part of the inventory dialog gets populated with the inventory of the target unit. Player has to be in range of inventory operations with the targetUnit (~ <5m). |\n| Syntax | *unit* action [\"Gear\", *targetUnit*] |\n|  | Where *unit* is a player, and *targetUnit* is another player, vehicle or container. |\n| Examples | ```sqf<br>player action [\"Gear\", \"GroundWeaponHolder\" createVehicle position player];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", objNull];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", soldier1];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", cursorTarget];<br>``` |\n\n### GetInCargo\n\n|  |  |\n|---|---|\n| Description | Instantly moves a person to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as cargo, in a specific cargo position if given as an optional parameter, otherwise in the first available cargo position. If the specific position is already occupied, the person will board in the first available cargo position. If the all cargo positions are already occupied by living persons, or no cargo position exists, the boarding will fail. This action works only with cargo positions that have no person turret, i.e. if player cannot shoot his rifle from them. If position is cargo but also person turret, it will be ignored. Use `fullCrew [_veh, \"cargo\", true]` to determine which positions are compatible cargo. Alternatively, use moveInCargo command instead, which has no such limitation. |\n| Syntax | *unit* action [\"GetInCargo\", *targetVehicle*] |\n|  | *unit* action [\"GetInCargo\", *targetVehicle*, *positionNumber*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. ''positionNumber is a specific cargo position index number. |\n| Examples | ```sqf<br>soldierOne action [\"GetInCargo\", truckOne];<br>``` |\n|  | ```sqf<br>soldierOne action [\"GetInCargo\", truckOne, 0];<br>``` |\n\n### GetInCommander\n\n|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, they then attempt to board the vehicle as the commander. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInCommander\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInCommander\", tankOne];<br>``` |\n\n### GetInDriver\n\n|  |  |\n|---|---|\n| Description | Instantly moves an person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the driver/pilot. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInDriver\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInDriver\", carOne];<br>``` |\n\n### GetInGunner\n\n|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the primary gunner. If the gunner position is already occupied by another living person or it does not exist, the boarding will fail. Also see getInTurret. |\n| Syntax | *unit* action [\"GetInGunner\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInGunner\", mySpotlight];<br>``` |\n\n### GetInPilot\n\n|  |  |\n|---|---|\n| Description | This action is identical to getInDriver. It instantly moves an person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the driver/pilot. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInPilot\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>pilotOne action [\"GetInPilot\", chopperOne];<br>``` |\n\n### GetInTurret\n\n|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the specified turret user. If the turret position is already occupied by another living person the boarding will fail. If the turret position does not exist, ArmA may crash. See also getInGunner. |\n| Syntax | *unit* action [\"GetInTurret\", *targetVehicle*, *turretArray*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded, and *turretArray* is an array defining the turret. For example, *[1]* would be a vehicle's second turret, and *[0, 2, 1]* is the second turret of the third turret of the first turret. A vehicle's turret order is defined in it is class CfgVehicles of the Config. |\n| Examples | ```sqf<br>gunnerTwo action [\"GetInTurret\", myUH60MG, [1]];<br>``` |\n|  | ```sqf<br>tankCommanderOne action [\"GetInTurret\", myT72, [0,1]];<br>``` |\n\n### GetOut\n\n|  |  |\n|---|---|\n| Description | Causes a person to disembark from a vehicle, without a parachute in the case of aircraft. See also eject. |\n| Syntax | *unit* action [\"GetOut\", *targetVehicle*] |\n|  | Where *unit* is the person to disembark, and *targetVehicle* is the vehicle to disembark from. |\n| Example | ```sqf<br>soldierOne action [\"GetOut\", carOne];<br>``` |\n\n### HandGunOn\n\n|  |  |\n|---|---|\n| Description | Causes a person to ready their hand gun (if equiped). This action may not work if the unit does not have a primary rifle. |\n| Syntax | *unit* action [\"HandGunOn\", *targetUnit*] |\n|  | Where *unit* is any unit (who will not play the action animation), and *targetUnit* is the unit who will ready their pistol. |\n| Example | ```sqf<br>soldierOne action [\"HandGunOn\", soldierOne];<br>``` |\n\n### HandGunOff\n\n|  |  |\n|---|---|\n| Description | Causes a person to return a readied pistol to it is holster, then switch to the primary rifle. This action may not work if the unit does not have a primary rifle. |\n| Syntax | *unit* action [\"HandGunOff\", *targetUnit*] |\n|  | Where *unit* is any unit (who will not play the action animation), and *targetUnit* is the person to holster it is pistol. |\n| Example | ```sqf<br>soldierOne action [\"HandGunOff\", soldierOne];<br>``` |\n\n### Heal\n\n|  |  |\n|---|---|\n| Description | Instantly teleports a person unit to the target medic. The target medic then heals the unit. If the target unit is not a medic, the animations will still be played, but no healing occurs. If the medic is within a vehicle, no teleporting will occur and the wounded unit will only be healed if they are already within healing range (a few meters). |\n| Syntax | *unit* action [\"Heal\", *targetUnit*] |\n|  | Where *unit* is a wounded person, and *targetUnit* is the medic to do the healing. |\n| Example | ```sqf<br>soldierOne action [\"Heal\", medicOne];<br>``` |\n\n### HealSoldier\n\n|  |  |\n|---|---|\n| Description | Performs one soldier healing of another soldier. Needs to have MedKit or FAK (first aid kit) in the inventory, which gets used. |\n| Syntax | *unit* action [\"HealSoldier\", *targetUnit*] |\n|  | Where *unit* is the unit to perform treatment, and *targetUnit* is the unit to receive treatment. |\n| Example | ```sqf<br>player action [\"HealSoldier\", soldier1];<br>``` |\n\n### HealSoldierSelf\n\n|  |  |\n|---|---|\n| Description | Performs one soldier healing of another soldier. In case the target is the same unit, the soldier performs treatment on himself. Needs to have FAK (first aid kit) in the inventory, which gets used. |\n| Syntax | *unit* action [\"HealSoldierSelf\", *targetUnit*] |\n|  | Where *unit* is the unit to perform treatment, and *targetUnit* is the unit to receive treatment. |\n| Example | ```sqf<br>player action [\"HealSoldierSelf\", soldier1];<br>``` |\n\n### HideBody\n\n|  |  |\n|---|---|\n| Description | Causes a person to bend down and hide (bury) a body in the ground. The body is automatically deleted within a few seconds. The person performing the action does not require the ability to hide bodies, and may be any distance from the body. |\n| Syntax | *unit* action [\"HideBody\", *targetUnit*] |\n|  | Where *unit* is a person, and *targetUnit* is a dead person. |\n| Example | ```sqf<br>soldierOne action [\"HideBody\", soldierTwo];<br>``` |\n\n### InGameMenu\n\n|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"InGameMenu\", *<target>*] |\n|  |  |\n| Example |  |\n\n### LadderDown\n\n|  |  |\n|---|---|\n| Description | Causes a person to play an animation as if mounting the top of a ladder, then instantly teleport onto the specified ladder in the specified position. If the person is controlled by AI, they will automatically climb up or down the ladder. If the 2 parameter syntax is used, the person will become stuck in the ladder mounting animation state until the ladderOff action is executed upon them. It may also crash ArmA (pre 1.09). |\n| Syntax | *unit* action [\"LadderDown\", *targetObject*] |\n|  | *unit* action [\"LadderDown\", *targetObject*, *ladderNumber*, *positionNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is an object with a ladder, *ladderNumber* is a number defining the desired ladder, and *positionNumber* is a number defining the desired position. |\n| Example | ```sqf<br>soldierOne action [\"LadderDown\", (position soldierOne nearestObject 452221), 0, 1];<br>``` |\n\n### LadderUp\n\n|  |  |\n|---|---|\n| Description | Causes a person to play an animation as if mounting the bottom of a ladder, then instantly teleport onto the specified ladder in the specified position. If the person is controlled by AI, they will automatically climb up or down the ladder. If the 2 parameter syntax is used, the person will become stuck in the ladder mounting animation state until the ladderOff action is executed upon them. It may also crash ArmA (pre 1.09). |\n| Syntax | *unit* action [\"LadderUp\", *targetObject*] **!!!Warning!!! This syntax causes Arma 3 to freeze** |\n|  | *unit* action [\"LadderUp\", *targetObject*, *ladderNumber*, *positionNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is an object with a ladder, *ladderNumber* is a number defining the desired ladder, and *positionNumber* is a number defining the desired position (0 - bottom, 1 - top). All numbers in between get rounded towards 1 or 0. |\n| Example | ```sqf<br>soldierOne action [\"LadderUp\", (position soldierOne nearestObject 452221), 0, 0];<br>``` |\n\n### LadderOff\n\n|  |  |\n|---|---|\n| Description | Causes a person to dismount from any ladder of the specified object they may be happen to be on. The alternative 3 parameter syntax expects a number, the use of which is not known. |\n| Syntax | *unit* action [\"LadderOff\", *targetObject*] |\n|  | *unit* action [\"LadderOff\", *targetObject*, *unknownNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is the object with a ladder that the person is currently upon, *unknownNumber* is a number. |\n| Example | ```sqf<br>soldierOne action [\"LadderOff\", (position soldierOne nearestObject 452221)];<br>``` |\n\n### LadderOnDown\n\n|  |\n|---|\n| **Description**: This action appears to be identical to LadderDown. |\n\n### LadderOnUp\n\n|  |\n|---|\n| **Description**: This action appears to be identical to LadderUp. |\n\n### Land\n\n|  |  |\n|---|---|\n| Description | Turns on autopilot landing for an aircraft, including AI controlled aircraft. The aircraft will land at the closest airfield. |\n| Syntax | *unit* action [\"Land\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"Land\", planeOne];<br>``` |\n\n### LandGear\n\n|  |  |\n|---|---|\n| Description | Lowers the landing gear of an aircraft. In the case of AI-controlled aircraft, it has to be used in an each-frame loop to override the AI behavior (otherwise they'll raise the landing gear when they take off). |\n| Syntax | *unit* action [\"LandGear\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"LandGear\", planeOne];<br>``` |\n\n### LandGearUp\n\n|  |  |\n|---|---|\n| Description | Raises the landing gear of an aircraft. In the case of AI-controlled aircraft, it has to be used in an each-frame loop to override the AI behavior (otherwise they'll lower the landing gear when they're close to the ground). |\n| Syntax | *unit* action [\"LandGearUp\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"LandGearUp\", planeOne];<br>``` |\n\n### LightOff\n\n|  |  |\n|---|---|\n| Description | Turns off the headlights of an empty vehicle. If the vehicle is AI-controlled (either as the lone driver, or as the commander/gunner) then the light status depends on the AI's behaviour mode (\"combat\" or \"stealth\" = lights off, any other mode = lights on). |\n| Syntax | *unit* action [\"LightOff\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"LightOff\", vehicle player];<br>``` |\n\n### LightOn\n\n|  |  |\n|---|---|\n| Description | Turns on the headlights of an empty vehicle. If vehicle is AI-controlled, see notes under the #LightOff action. |\n| Syntax | *unit* action [\"LightOn\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"LightOn\", vehicle player];<br>``` |\n\n### LoadMagazine\n\n|  |  |\n|---|---|\n| Description | Plays a reload weapon animation. |\n| Syntax | *unit* action [\"LoadMagazine\", target, magazineCreator, *number1*, *number2*, weaponName, muzzleName] |\n|  | Expects a 7 elements array: |\n|  | target: Object - unit to perform the reload action. |\n|  | magazineCreator: Object - unknown. Can be objNull. |\n|  | *number1*: Number - cr - see magazinesDetail. For characters it is mainly 0 |\n|  | *number2*: Number - id - magazine ID - can be obtained via magazinesDetail. With 0, it only plays the reload animation. With values from 1 up, it actually reloads the magazine. If the number becomes too high (meaning of the upper limit is also unknown), the action will no longer be performed. |\n|  | weaponName: String - weapon to reload. Must not be selected, but may cause weapon not to reload to the full amount. |\n|  | muzzleName: String - weapon's muzzle to reload. |\n| Example | ```sqf<br>player action [\"LoadMagazine\", player, player, 0, 1 , \"vbs2_us_m16a2_iron_gla\", \"vbs2_us_m16a2_iron_gla\"];<br>``` |\n\n### LockVehicleControl\n\n|  |  |\n|---|---|\n| Description | Locks co-pilot controls, removes #TakeVehicleControl action. enableCopilot must be set true to function. |\n| Syntax | *unit* action [\"LockVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"LockVehicleControl\", vehicle player];<br>``` |\n\n### ManualFire\n\n|  |  |\n|---|---|\n| Description | Enables manual fire mode for a player unit that is driver or commander of a vehicle. This action toggled manual fire mode in old versions of ArmA. (See also isManualFire) |\n| Syntax | *unit* action [\"ManualFire\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is the vehicle in which manual fire mode is to be enabled. |\n| Example | ```sqf<br>player action [\"ManualFire\", vehicle player];<br>``` |\n\n### ManualFireCancel\n\n|  |  |\n|---|---|\n| Description | Disables manual fire mode for a player unit that is driver or commander of a vehicle. (See also isManualFire) |\n| Syntax | *unit* action [\"ManualFireCancel\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is the vehicle in which manual fire mode is to be disabled. |\n| Example | ```sqf<br>player action [\"ManualFireCancel\", vehicle player];<br>``` |\n\n### MarkEntity\n\n|  |  |\n|---|---|\n| Description | Use and effects unknown. Same as #MarkWeapon action. |\n| Syntax | *unit* action [\"MarkEntity\", <target>] |\n|  |  |\n| Example |  |\n\n### MoveToCargo\n\n|  |  |\n|---|---|\n| Description | Move a unit to the chosen cargo position within a vehicle. If another unit is already in that position, the units will swap positions.<br>This works only with cargo positions that have no person turret, i.e. if player cannot shoot his rifle from them.<br>If position is cargo but also person turret, it will be ignored.<br>Use `fullCrew [_veh, \"cargo\", true]` to determine which positions are compatible cargo. |\n| Syntax | *unit* action [\"MoveToCargo\", *targetVehicle*, *cargoPosition*] |\n|  | Where *unit* is a unit within *targetVehicle*, and *cargoPosition* is the number of the desired cargo position (0 being the first). |\n| Example | ```sqf<br>player action [\"MoveToCargo\", vehicle player, 2];<br>``` |\n\n### MoveToCommander\n\n|  |  |\n|---|---|\n| Description | Move a unit to the commander's position within a vehicle. If another unit is already in that position, the units will swap positions. |\n| Syntax | *unit* action [\"MoveToCommander\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToCommander\", vehicle player];<br>``` |\n\n### MoveToDriver\n\n|  |  |\n|---|---|\n| Description | Move a unit to the driver's position within a vehicle. If another unit is already in that position, the units will generally swap positions, although in some scenarios this action may not work (although having the existing driver move always works). |\n| Syntax | *unit* action [\"MoveToDriver\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToDriver\", vehicle player];<br>``` |\n\n### MoveToGunner\n\n|  |  |\n|---|---|\n| Description | Move a unit to the primary gunner's position within a vehicle. If another unit is already in that position, the units will swap positions. See also moveToTurret. |\n| Syntax | *unit* action [\"MoveToGunner\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToGunner\", vehicle player];<br>``` |\n\n### MoveToPilot\n\n|  |\n|---|\n| **Description**: Identical to moveToDriver. |\n\n### MoveToTurret\n\n|  |  |\n|---|---|\n| Description | Move a unit to the chosen turret position within a vehicle. If another unit is already in that position, the units will swap positions. |\n| Syntax | *unit* action [\"MoveToTurret\", *targetVehicle*, *turretArray*] |\n|  | Where *unit* is a unit within *targetVehicle*, and *turret Array* is an array referring to the desired turret (for example, [0,1,2] refers to the third turret of the second turret of the first turret of the vehicle). |\n| Examples | ```sqf<br>player action [\"MoveToTurret\", vehicle player, [0]];<br>``` |\n|  | ```sqf<br>player action [\"MoveToTurret\", vehicle player, [0,1]];<br>``` |\n\n### None\n\n|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"None\", *<target>*] |\n|  |  |\n| Example |  |\n\n### NVGoggles\n\n|  |  |\n|---|---|\n| Description | Causes a unit to put on it is night vision goggles. AI controlled units will automatically put on and take off goggles depending on daylight. |\n| Syntax | *unit* action [\"NvGoggles\", *<anything>*] |\n|  | Where *unit* is the unit to put on NVGoggles, and *<anything>* can be anything (it seems to not be used at all, but the action parameter array must contain at least two elements). |\n| Example | ```sqf<br>player action [\"NvGoggles\", player];<br>``` |\n\n### NVGogglesOff\n\n|  |  |\n|---|---|\n| Description | Causes a unit to take off it is night vision goggles. AI controlled units will automatically put on and take off goggles depending on daylight. |\n| Syntax | *unit* action [\"NvGogglesOff\", *<anything>*] |\n|  | Where *unit* is the unit to put on goggles, and *<anything>* can be anything (it seems not to be used at all, but the action parameter array must contain at least two elements). |\n| Example | ```sqf<br>player action [\"NvGogglesOff\", player];<br>``` |\n\n### OpenParachute\n\n|  |  |\n|---|---|\n| Description | Opens unit's parachute. Unit must have parachute backpack. |\n| Syntax | *unit* action [\"OpenParachute\", *unit*] |\n|  | Where *unit* is the unit with parachute backpack. |\n| Example | ```sqf<br>player action [\"OpenParachute\", player];<br>``` |\n\n### PutBag\n\n|  |  |  |\n|---|---|---|\n| Description | Causes *sourceUnit* to bend over and put target backpack on the ground. If the *targetUnit* param is omitted or it is the same as *sourceUnit*, the *sourceUnit* will drop own backpack. If *targetUnit* is another unit, *sourceUnit* will bend over but *targetUnit* will drop its backpack at its feet. |  |\n| Syntax | *sourceUnit* action [\"PutBag\", *targetUnit*] |  |\n|  | *targetUnit* is optional |  |\n| Note | To pick the backpack from the ground use \"AddBag\" action. |  |\n| Examples | ```sqf<br>player action [\"PutBag\"];<br>unit1 action [\"PutBag\", unit2];<br>``` |  |\n\n### Rearm\n\n|  |  |\n|---|---|\n| Description | Causes an occupied vehicle or person to rearm from any object with some ammoCargo (generally an ammo truck) in the case of vehicles, or some magazines in it is cargo in the case of a rearming person. The rearming vehicle/person can be any distance from the rearming object. Rearming vehicles takes some time and will be interrupted if the vehicle starts to move. A rearming person will bend down as if picking up something. |\n| Syntax | *unit* action [\"Rearm\", *reamingObject*] |\n|  | Where *unit* is the occupied vehicle or person to be rearmed, and *rearmingObject* is the object from which to rearm. |\n| Examples | ```sqf<br>tankOne action [\"Rearm\", ammoTruckOne];<br>``` |\n|  | ```sqf<br>soldierOne action [\"Rearm\", ammoTruckOne];<br>``` |\n\n### Refuel\n\n|  |  |\n|---|---|\n| Description | Causes an occupied vehicle to refuel from any object with some fuelCargo (generally an refueling truck). The refueling object can be any distance from the vehicle. Refueling takes some time and will be interrupted if the vehicle starts to move. |\n| Syntax | *vehicle* action [\"Refuel\", *refuelingObject*] |\n|  | Where *vehicle* is the occupied vehicle to be refueled, and *refuelingObject* is the object from which to refuel. |\n| Example | ```sqf<br>tankOne action [\"Refuel\", refuelTruckOne];<br>``` |\n\n### Repair\n\n|  |  |\n|---|---|\n| Description | Causes an occupied vehicle to repair from any object with some repairCargo (generally an repair truck). The repair object can be any distance from the vehicle. Repairing takes some time and will be interrupted if the vehicle starts to move. |\n| Syntax | *vehicle* action [\"Repair\", *repairingObject*] |\n|  | Where *vehicle* is the occupied vehicle to be repaired, and *repairingObject* is the object from which to repair. |\n| Example | ```sqf<br>tankOne action [\"Repair\", repairTruckOne];<br>``` |\n\n### ReturnFlag\n\n|  |  |\n|---|---|\n| Description | Causes a person to return a flag from a nearby dead person back to it is flagpole. As of ArmA v1.12 this action is bugged and can not be used upon flags attached to destroyed vehicles. |\n| Syntax | *unit* action [\"ReturnFlag\", *targetObject*] |\n|  | Where *unit* is any person, and *targetObject* is the dead person with a flag to be returned. |\n| Example | ```sqf<br>soldierOne action [\"ReturnFlag\", westFlag];<br>``` |\n\n### RepairVehicle\n\n|  |  |\n|---|---|\n| Description | Causes an Engineer unit to repair an object using their Engineer Repair ability (from v1.54). The Engineer can be any distance from the vehicle. Repairing takes some time. If *unit* is not the Engineer class no repairs are made but the animation will still play. |\n| Syntax | *unit* action [\"RepairVehicle\", *vehicle*] |\n|  | Where *unit* is an Engineer unit, and *vehicle* is the object to repair. |\n| Example | ```sqf<br>engineerOne action [\"RepairVehicle\", truckOne];<br>``` |\n\n### Salute\n\n|  |  |\n|---|---|\n| Description | Causes a person to salute. AI controlled units will only make a momentary salute, unless the AI is in safe or careless behaviour mode. |\n| Syntax | *unit* action [\"Salute\", *targetUnit*] |\n|  | Where *unit* is any unit (no animation is performed), and *targetUnit* is the person to make the salute. |\n| Example | ```sqf<br>soldierOne action [\"Salute\", soldierOne];<br>``` |\n\n### ScudCancel\n\n|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudCancel\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |\n\n### ScudLaunch\n\n|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudLaunch\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |\n\n### ScudStart\n\n|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudStart\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |\n\n### SearchlightOff\n\n|  |  |\n|---|---|\n| Description | Turns off the vehicle's searchlight.<br>> [!NOTE]<br>> Out of all the vanilla vehicles, only the WY-55 Hellcat has a searchlight and the action should be used on the copilot seat. See Arma 3: Lights#Search Light. |\n| Syntax | *unit* action [\"SearchlightOff\", *vehicle*] |\n| Example | hellcatCopilot action [\"SearchlightOff\", vehicle hellcatCopilot] |\n\n### SearchlightOn\n\n|  |  |\n|---|---|\n| Description | Turns on the searchlight.<br>> [!NOTE]<br>> Out of all the vanilla vehicles, only the WY-55 Hellcat has a searchlight and the action should be used on the copilot seat. See Arma 3: Lights#Search Light. |\n| Syntax | *unit* action [\"SearchlightOn\", *vehicle*] |\n| Example | hellcatCopilot action [\"SearchlightOn\", vehicle hellcatCopilot] |\n\n### SetTimer\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitOne' plays the action animation. UnitTwo activates and adds 40 seconds to the timer for a satchel charge. Neither unit needs to be near the satchel.<br>Charge has to be placed first using *unitname Fire [\"pipebombmuzzle\", \"pipebombmuzzle\", \"pipebomb\"]* or createMine command. |\n| Syntax | *unitOne* action [\"SetTimer\", *unitTwo*, *bombName*] |\n|  |  |\n| Example |  |\n\n### SitDown\n\n|  |  |\n|---|---|\n| Description | Causes a person to sit down on the ground (or get up, if already sitting). AI controlled units will only stay seated if they are in safe or careless behaviour mode. |\n| Syntax | *unit* action [\"SitDown\", *targetUnit*] |\n|  | Where *unit* is any unit (no animation is performed), and *targetUnit* is the person who is to sit down. |\n| Example | ```sqf<br>soldierOne action [\"SitDown\", soldierOne];<br>``` |\n\n### StrokeFist\n\n|  |  |\n|---|---|\n| Description | Does nothing. There is no punch animation in Armed Assault and later titles, however this action remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"StrokeFist\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |\n\n### StrokeGun\n\n|  |  |\n|---|---|\n| Description | Does nothing (other than making a person twitch a little). There is no suitable animation for this action in Armed Assault and later titles, however this action remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"StrokeGun\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |\n\n### Surrender\n\n|  |  |\n|---|---|\n| Description | Makes unit to put weapon on shoulder and put hands behind the head temporarily. For the lasting effect all weapons from the unit should be removed first. |\n| Syntax | *unit* action [\"Surrender\", *targetUnit*] |\n|  | Where *unit* is any unit, and *targetUnit* is the unit to surrender. |\n| Example | ```sqf<br>soldierOne action [\"Surrender\", soldierTwo];<br>``` |\n\n### SuspendVehicleControl\n\n|  |  |\n|---|---|\n| Description | Release vehicle controls from co-pilot. Control immediately returns to pilot. |\n| Syntax | *unit* action [\"SuspendVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"SuspendVehicleControl\", vehicle player];<br>``` |\n\n### SwitchMagazine\n\n|  |  |\n|---|---|\n| Description | Target unit switches to the given firing mode index. This allows selection of any firing mode for any weapon carried by a soldier, or mounted on a weapon. First are the firing modes for the primary weapon (index 0 upwards), then secondary weapon, then optics, then pistol, then thrown and placed weapons. Changing to NVGoggles just plays an animation, not actually setting NV mode. Unfortunately, the list of firing modes seems to only be created when a soldier is initiated; modes are removed from the list when a weapon is dropped and not re-added when a weapon is picked up. Thus, only use this during the initiation phase of the soldier. On vehicles, where the weapons are not likely to be changed, this action might be useful after the vehicle has been initiated. |\n|  | If the mode index is higher than available indices, it assumes index 0. If you just want to change the muzzle used, rather than the firing mode, the standard command selectWeapon is generally more useful. |\n| Syntax | *unit* action [\"SwitchMagazine\", *targetVehicle*, *targetUnit*, *mode index*] |\n|  |  |\n| Example | ```sqf<br>gameLogic action [\"SwitchMagazine\", unit1, unit1, 3];<br>gameLogic action [\"SwitchMagazine\", m1a1, gunner m1a1, 1];<br>``` |\n\n### SwitchWeapon\n\n|  |  |\n|---|---|\n| Description | UnitOne plays the action animation. Target unit switches to the given muzzle/mode index. Target unit can also be a vehicle. The weapons array is a list of all weapon modes specific to each weapon, muzzle and firing mode combination. |\n| Syntax | *unit* action [\"SwitchWeapon\", *targetUnit*, *targetUnit*, *muzzle index*] |\n|  |  |\n| Example | ```sqf<br>unit2 action [\"SwitchWeapon\", unit1, unit1, 7];<br>player action [\"SwitchWeapon\", player, player, 3];            // switching personal weapon<br>player action [\"SwitchWeapon\", vehicle player, player, 3];    // switching vehicle weapon<br>``` |\n|  | ```sqf<br>player action [\"SwitchWeapon\", player, player, weaponIndex];<br>```<br>Result => weaponIndex: weaponState for \"B_soldier_LAT_F\"<br> 0: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"Single\", \"30Rnd_65x39_caseless_mag\",30]<br> 1: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"FullAuto\", \"30Rnd_65x39_caseless_mag\",30]<br> 2: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"fullauto_medium\", \"30Rnd_65x39_caseless_mag\",30]<br> 3: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"single_medium_optics1\", \"30Rnd_65x39_caseless_mag\",30]<br> 4: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"single_far_optics2\", \"30Rnd_65x39_caseless_mag\",30]<br> 5: [\"launch_NLAW_F\", \"launch_NLAW_F\", \"launch_NLAW_F\", \"NLAW_F\",1]<br> 6: [\"hgun_P07_F\", \"hgun_P07_F\", \"hgun_P07_F\", \"16Rnd_9x21_Mag\",16]<br> 7: [\"Throw\", \"HandGrenade_Stone\", \"HandGrenade_Stone\", \"\",0]<br> 8: [\"Throw\", \"HandGrenadeMuzzle\", \"HandGrenadeMuzzle\", \"\",0]<br> 9: [\"Throw\", \"MiniGrenadeMuzzle\", \"MiniGrenadeMuzzle\", \"\",0]<br> 10: [\"Throw\", \"MiniGrenadeMuzzle\", \"MiniGrenadeMuzzle\", \"\",0]<br> 11: [\"Throw\", \"SmokeShellYellowMuzzle\", \"SmokeShellYellowMuzzle\", \"\",0]<br> 12: [\"Throw\", \"SmokeShellYellowMuzzle\", \"SmokeShellYellowMuzzle\", \"\",0]<br> 13: [\"Throw\", \"SmokeShellRedMuzzle\", \"SmokeShellRedMuzzle\", \"\",0]<br> 14: [\"Throw\", \"SmokeShellPurpleMuzzle\", \"SmokeShellPurpleMuzzle\", \"\",0]<br> 15: [\"Throw\", \"SmokeShellOrangeMuzzle\", \"SmokeShellOrangeMuzzle\", \"\",0]<br> 16: [\"Throw\", \"SmokeShellBlueMuzzle\", \"SmokeShellBlueMuzzle\", \"\",0]<br> 17: [\"Throw\", \"SmokeShellBlueMuzzle\", \"SmokeShellBlueMuzzle\", \"\",0]<br> 18: [\"Throw\", \"ChemlightRedMuzzle\", \"ChemlightRedMuzzle\", \"\",0]<br> 19: [\"Throw\", \"ChemlightYellowMuzzle\", \"ChemlightYellowMuzzle\", \"\",0]<br> 20: [\"Throw\", \"ChemlightBlueMuzzle\", \"ChemlightBlueMuzzle\", \"\",0]<br> 21: [\"Throw\", \"IRGrenade\", \"IRGrenade\", \"\",0]<br> 22: [\"Put\", \"DemoChargeMuzzle\", \"DemoChargeMuzzle\", \"\",0]<br> 23: [\"Put\", \"PipeBombMuzzle\", \"PipeBombMuzzle\", \"\",0]<br> 24: [\"Put\", \"MineMuzzle\", \"MineMuzzle\", \"\",0]<br> 25: [\"Put\", \"ClassicMineRangeMuzzle\", \"ClassicMineRangeMuzzle\", \"\",0]<br> 27: [\"Put\", \"BoundingMineRangeMuzzle\", \"BoundingMineRangeMuzzle\", \"\",0]<br> 28: [\"Put\", \"DirectionalMineRangeMuzzle\", \"DirectionalMineRangeMuzzle\", \"\",0]<br> 29: [\"Put\", \"ClassicMineWireMuzzle\", \"ClassicMineWireMuzzle\", \"\",0]<br>As of **2.10**, weaponsInfo is better suited for finding the desired weapon index. |\n\n### SwitchToUAVDriver\n\n|  |  |\n|---|---|\n| Description | Moves player control into driver position of connected UAV. Does what \"Take UAV controls\" UI action does. |\n| Syntax | *unit* action [\"SwitchToUAVDriver\", *uav*] |\n|  | Where *unit* is a player and *uav* is the connected UAV. |\n| Example | ```sqf<br>player action [\"SwitchToUAVDriver\", getConnectedUAV player];<br>``` |\n\n### SwitchToUAVGunner\n\n|  |  |\n|---|---|\n| Description | Moves player control into gunner position of connected UAV. Does what \"Take UAV turret controls\" UI action does. |\n| Syntax | *unit* action [\"SwitchToUAVGunner\", *uav*] |\n|  | Where *unit* is a player and *uav* is the connected UAV. |\n| Example | ```sqf<br>player action [\"SwitchToUAVGunner\", getConnectedUAV player];<br>``` |\n\n### TakeFlag\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitname' takes control of 'flag1'. He must be close to the flagpole and it must belong to an enemy side. |\n| Syntax | *unit* action [\"TakeFlag\", *flag1*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TakeFlag\", FlagOne];<br>``` |\n\n### TakeMagazine\n\n|  |  |\n|---|---|\n| Description | Soldier 'unit' takes one magazine of specified type from the ground (Weaponholder) or from named vehicle (ammo box, car, etc.) Transfer happens immediately and via teleportation. Unit plays pickup animation at its current position, no matter where magazine is. Since Arma 3 v2.06.147667 optional param 'forcePutInBackpack' is added allowing to store picked up magazine in backpack. By default the magazine will go to any unit container with space, starting with uniform. |\n| Syntax | *unit* action [\"TakeMagazine\", *weaponholder*, *magazineName*, (*forcePutInBackpack*)] |\n|  | Where *unit* is any unit, and *weaponholder* is storage container. |\n| Example1 | ```sqf<br>player action [\"TakeMagazine\", ammoBox, \"RPGLauncher\"];<br>``` |\n| Example2 | Drop Magazine, then make your buddy Bob come and take magazine and put it in backpack:<br>```sqf<br>0 spawn<br>{<br>    private _wh = \"Weapon_Empty\" createVehicle (player getRelPos [2, 0]);<br>    private _mag = currentMagazine player;<br>    player action [\"PutMagazine\", _wh, _mag];<br>    private _bob = group player createUnit [\"B_Soldier_F\", player getRelPos [10, 0], [], 0, \"NONE\"];<br>    _bob addBackpack \"B_AssaultPack_blk\";<br>    _bob doMove position _wh;<br>    waitUntil { unitReady _bob };<br>    _bob action [\"TakeMagazine\", _wh, _mag, true];<br>};<br>``` |\n\n### TakeWeapon\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitname' takes weapon of specified type (see list) from the ground (Weaponholder) or from named vehicle (ammo box, car, etc.) Transfer happens immediately and via teleportation. Unit1 plays pickup animation at its current position, no matter where weapon is. |\n|  | *unit* action [\"TakeWeapon\", *vehicle*, *weaponName*] |\n|  | Where *unit* is any unit, and *vehicle* is any unit or vehicle. |\n| Example | ```sqf<br>player action [\"TakeWeapon\", SoldierTwo, currentWeapon player];<br>``` |\n\n### TakeMine\n\n|  |  |\n|---|---|\n| Description | Unit will perform pick up action animation. The closest mine that is within two meters of the target unit will be placed into the target unit's inventory. The mine has to be active for this action to succeed. If there is not enough room in the target inventory, the mine will still be picked up but will not appear in inventory. See createMine for how to place explosive by script. |\n| Syntax | *unit* action [\"TakeMine\", *targetUnit*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TakeMine\", player];<br>``` |\n\n### TakeVehicleControl\n\n|  |  |  |\n|---|---|---|\n| Description | In case of a helicopter, copilot will take flying controls, even if enableCopilot is disabled and isCopilotEnabled is false. | Use #SuspendVehicleControl action to release control. |\n| Syntax | *unit* action [\"TakeVehicleControl\", *vehicle*] |  |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |  |\n| Example | ```sqf<br>player action [\"TakeVehicleControl\", vehicle player];<br>``` |  |\n\n### Talk\n\n|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"Talk\", *target*] |\n|  |  |\n| Example |  |\n\n### TeamSwitch\n\n|  |  |\n|---|---|\n| Description | Opens the normal team-switch dialog. <current unit> will be greyed out in the list and thus unselectable.<br>The effect of the second array element is unknown, but it must be a unit.<br>Works in single-player game only (in MP games, will just momentarily show the mouse cursor without the team-switch window being shown). |\n| Syntax | *currentUnit* action [\"TeamSwitch\", *unit*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TeamSwitch\", player];<br>``` |\n\n### TouchOff\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitOne' plays the action animation. UnitTwo's satchels are \"touched off\".<br>UnitTwo must be within range (300m) of his satchels to touch them off. See createMine for how to place explosives with script. |\n| Syntax | *unitOne* action [\"TouchOff\", *unitTwo*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TouchOff\", player];<br>``` |\n\n### TurnIn\n\n### TurnOut\n\n|  |  |\n|---|---|\n| Description | Crew of 'vehiclename' turns in/out (gets in and out of hatches).<br>UnitName must be a player in effective commander of vehicleName. AI will automatically turn in/out based on their current behaviour mode.<br>Only to be used on positions that have the turnIn/turnOut capability (otherwise it breaks the cargo anim). |\n| Syntax | *unit* action [\"TurnIn\", *vehicle*] |\n|  | *unit* action [\"TurnOut\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>commander TankOne action [\"TurnIn\", TankOne];<br>player action [\"TurnOut\", vehicle player];<br>``` |\n\n### UAVTerminalHackConnection\n\n|  |  |\n|---|---|\n| Description | Hacks into given UAV. Does what \"Hack UAV\" UI action does. Player has to be in normal UI action proximity to the UAV for this action to work. <br>> [!NOTE]<br>> Controlling a UAV/UGV in Arma 3 is done via remote controlling the invisible driver or gunner AI. These AI units have to be on the same side as player. \"Hacking\" is essentially placing own AI into the UAV/UGV, either replacing existing AI, or creating own AI in empty positions (for example when UAV/UGV is placed 'without crew') |\n| Syntax | *unit* action [\"UAVTerminalHackConnection\", *uav*] |\n|  | Where *unit* is any unit (enemy to the drone) and *uav* is the UAV to hack. |\n| Example | ```sqf<br>player action [\"UAVTerminalHackConnection\", drone];<br>``` |\n\n### UAVTerminalMakeConnection\n\n|  |  |\n|---|---|\n| Description | Connects player to chosen UAV. Does what \"Connect terminal to UAV\" UI action does.<br>**NOTE**: Player has to be in normal UI action proximity to the UAV for this action to work.<br>To connect to far away UAV use connectTerminalToUAV command instead. |\n| Syntax | *unit* action [\"UAVTerminalMakeConnection\", *uav*] |\n|  | Where *unit* is a player and *uav* is UAV to be connected to. |\n| Example | ```sqf<br>player action [\"UAVTerminalMakeConnection\", allUnitsUAV select 0];<br>``` |\n\n### UAVTerminalOpen\n\n|  |  |\n|---|---|\n| Description | Opens UAV Terminal UI. Player must have UAV Terminal item in GPS slot of inventory. Does what \"Open UAV Terminal\" UI action does. |\n| Syntax | *unit* action [\"UAVTerminalOpen\", *unit*] |\n|  | Where *unit* is a player. |\n| Example | ```sqf<br>player action [\"UAVTerminalOpen\", player];<br>``` |\n\n### UAVTerminalReleaseConnection\n\n|  |  |\n|---|---|\n| Description | Disconnects player from connected UAV. Does what \"Disconnect terminal from UAV\" UI action does.<br>**NOTE**: Unlike with \"UAVTerminalMakeConnection\", player can be far away from the UAV. Notice how the passed params are swapped around for this action. |\n| Syntax | *uav* action [\"UAVTerminalReleaseConnection\", *unit*] |\n|  | Where *uav* is the connected UAV and *unit* is the player controlling it. |\n| Example | ```sqf<br>getConnectedUAV player action [\"UAVTerminalReleaseConnection\", player];<br>``` |\n\n### UnlockVehicleControl\n\n|  |  |\n|---|---|\n| Description | Unlocks co-pilot controls, shows Take Control action. enableCopilot must be set true to function. |\n| Syntax | *unit* action [\"UnlockVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"UnlockVehicleControl\", vehicle player];<br>``` |\n\n### UseMagazine\n\n|  |  |\n|---|---|\n| Description | Loads a weapon with magazine with known id and fires that weapon. The weapon is selected based on magazine type. Details for <cr> and <id> can be found with magazinesDetail command (not 100% about <cr> but it seems 0 works for all weapons) |\n| Syntax | *logic* action [\"UseMagazine\", *target*, *magazine creator*, *<cr>*, *<id>*] |\n|  |  |\n| Example | ```sqf<br>private _logic = createGroup west createUnit [\"Logic\", [0,0,0], [], 0, \"NONE\"];<br>hint str magazinesDetail player; // loaded mags not shown<br>/*[<br>\"6.5mm 30Rnd STANAG Mag(30/30)[id/cr:3/0]\",<br>\"Smoke Round (White)(1/1)[id/cr:121/0]\",<br>\"Smoke Round (White)(1/1)[id/cr:122/0]\",<br>\"9mm 16Rnd Mag(16/16)[id/cr:11/0]\"<br>]*/<br>_logic action [\"UseMagazine\", player, player, 0, 3];    // loads rifle with mag id 3 and fires<br>_logic action [\"UseMagazine\", player, player, 0, 11];    // loads pistol with mag id 11 and fires from inventory<br>_logic action [\"UseMagazine\", player, player, 0, 121];    // throws smoke grenade with id 121<br>``` |\n\n### User\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitName' does nothing. Executes the custom action with the given index of the the target unit. Indexes are based upon the order in which the actions are added to the unit. See addAction. |\n| Syntax | *unitName* action [\"User\", *target unit*, *action index*] |\n|  |  |\n| Example | ```sqf<br>gameLogic action [\"User\", player, 3];<br>``` |\n\n### UserType\n\n|  |  |\n|---|---|\n| Description | As of ArmA version 1.08, using this action type will cause ArmA to crash to desktop. |\n| Syntax | *unit* action [\"UserType\", *target*, *action index*] |\n|  |  |\n| Example |  |\n\n### UseWeapon\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitOne' will play the action animation. Target unit will fire the specified unit's position in the target vehicle's (can be the unit itself) weapon mode index. The indexes seem to be based upon the order in which weapons are added to the unit/vehicle, with each weapon's muzzle's fire mode having an unique index. Weapons can be fired in this way from a not-readied position (eg, firing a rifle on a soldiers back). Pistols will fire from the current weapon's proxy. It can also be used to sound the horn on AI controlled vehicles. |\n|  | **NOTE:** If 'unitOne' is player object, the player goes into pick up animation before action is performed. If 'unitOne' is a game logic, the action is performed immediately with no animation. |\n| Syntax | *unitOne* action [\"UseWeapon\", *target vehicle*, *target unit*, *weapon index*] |\n|  |  |\n| Example | ```sqf<br>_logic = createGroup west createUnit [\"Logic\", [0,0,0], [], 0, \"NONE\"];<br>_logic action [\"UseWeapon\", player, player, 0];    // player fires single shot<br>_logic action [\"UseWeapon\", player, player, 2];    // player fires 3 round burst<br>_logic action [\"UseWeapon\", player, player, 5];    // player fires pistol from inventory<br>_logic action [\"UseWeapon\", player, player, 7];    // player throws hand grenade<br>_logic action [\"UseWeapon\", car, car, 0];        // car sounds its horn<br>// more examples<br>gameLogic action [\"UseWeapon\", unit1, unit1, 16];<br>gameLogic action [\"UseWeapon\", vehicle unit1, unit1, 0];<br>gameLogic action [\"UseWeapon\", myTank, gunner myTank, 1];<br>gameLogic action [\"UseWeapon\", myTank, commander myTank, 0];<br>``` |\n\n### VectoringDown\n\n|  |  |\n|---|---|\n| Description | If VTOL auto-vectoring is off, incremental forward tilt of engine nacelles. |\n| Syntax | *unit* action [\"VectoringDown\", *vehicle*] |\n|  |  |\n| Example |  |\n\n### VectoringUp\n\n|  |  |\n|---|---|\n| Description | If VTOL auto-vectoring is off, incremental upward tilt of engine nacelles. |\n| Syntax | *unit* action [\"VectoringUp\", *vehicle*] |\n|  |  |\n| Example |  |\n\n### VTOLVectoring\n\n|  |  |\n|---|---|\n| Description | Toggles **off** VTOL auto-vectoring (manual mode) |\n| Syntax | *unit* action [\"VTOLVectoring\", *vehicle*] |\n|  |  |\n| Example |  |\n\n### VTOLVectoringCancel\n\n|  |  |\n|---|---|\n| Description | Toggles **on** VTOL auto-vectoring (forward mode) |\n| Syntax | *unit* action [\"VTOLVectoringCancel\", *vehicle*] |\n|  |  |\n| Example |  |\n\n### WeaponInHand / WeaponOnBack\n\n|  |  |\n|---|---|\n| Description | Soldier 'unitName' does nothing, 'target unit' moves his weapon from/to the safety position (gun held across chest pointing at the ground).<br>Change is persistent with player, but AI units will change back to suit their current setBehaviour\\|behaviour mode. AI generally keep their rifles safe unless moving or targeting. |\n| Syntax | *unitName* action [\"WeaponInHand\", *target unit*] |\n|  | *unitName* action [\"WeaponOnBack\", *target unit*] |\n|  |  |\n| Example | ```sqf<br>SoldierOne action [\"WeaponOnBack\", SoldierTwo];<br>``` |\n\n### WheelsBrakeOn\n\n|  |  |\n|---|---|\n| Description | Engages wheels brakes on RTM helicopter |\n| Syntax | *unit* action [\"WheelsBrakeOn\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"WheelsBrakeOn\", heli];<br>``` |\n\n### WheelsBrakeOff\n\n|  |  |\n|---|---|\n| Description | Disengages wheels brakes on RTM helicopter |\n| Syntax | *unit* action [\"WheelsBrakeOff\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"WheelsBrakeOff\", heli];<br>``` |\n\n## Unsorted actions found in UI.pbo/config.bin\n\n### LoadOtherMagazine\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### LoadEmptyMagazine\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### PutWeapon\n\n|  |  |\n|---|---|\n| Description | Is alias of DropWeapon |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>_wh = \"GroundWeaponHolder_Scripted\" createVehicle position player;<br>player action [\"PutWeapon\", _wh, currentWeapon player];<br>``` |\n\n### PutMagazine\n\n|  |  |\n|---|---|\n| Description | is synonym for DropMagazine (same syntax)? |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### StartTimer\n\n|  |  |\n|---|---|\n| Description | is synonym for SetTimer (same syntax) ? |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### HideWeapon\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax | unit action [\"HideWeapon\", <object>, <object>, <Number>] |\n|  |  |\n| Example |  |\n\n### MarkWeapon\n\n|  |  |\n|---|---|\n| Description | Something to do with campaign. Campaign param \"WeaponPool\" has to be enabled as well as mission param \"MarkWeapons\". Possibly related to \"MarkEntity\" action as well. |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### HandGunOffStand\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### HandGunOnStand\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### TakeDropMagazine\n\n|  |  |\n|---|---|\n| **Description**: Redundant even if works, use #TakeMagazine |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### TakeDropWeapon\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### Assemble\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>_unit action [\"Assemble\", nearestObject [_unit, \"Tripod_Bag\"]];<br>``` |\n\n### FirstAid\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### GetOver\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### GunLightOff\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"GunLightOff\", player];<br>``` |\n\n### GunLightOn\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"GunLightOn\", player];<br>``` |\n\n### IRLaserOff\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"IRLaserOff\", player];<br>``` |\n\n### IRLaserOn\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"IRLaserOn\", player];<br>``` |\n\n### OpenBag\n\n|  |  |\n|---|---|\n| Description | Opens inventory UI with backpack of a unit (another unit). Unit must be in proximity. |\n| Syntax | unit1 action [\"OpenBag\", unit2]; |\n|  |  |\n| Example | player action [\"OpenBag\", bob]; |\n\n### TakeBag\n\n|  |  |\n|---|---|\n| Description | Unit takes specified backpack from the ground. |\n| Syntax | _unit action [\"TakeBag\", _bag]; |\n|  |  |\n| Example | ```sqf<br>player addEventHandler [\"WeaponDisassembled\",<br>{<br>    _this spawn {<br>        _unit = _this select 0;<br>        _bag1 = _this select 1;<br>        _bag2 = _this select 2;<br>        _currBag = unitBackpack _unit;<br>        titleText [\"You are not allowed to disassemble static weapons.\", \"PLAIN DOWN\", 0.5];<br>        _unit action [\"TakeBag\", _bag1];<br>        _time = time + 3;<br>        waitUntil { unitBackpack _unit == _bag1 \\|\\| time > _time };<br>        _unit action [\"Assemble\", _bag2];<br>        if (!isNull _currBag) then { _unit action [\"TakeBag\", _currBag] };<br>    };<br>}];<br>``` |\n\n### Tell\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### APUOn\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### APUOff\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### BatteriesOn\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### BatteriesOff\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### StarterOn<#>\n\n|  |  |\n|---|---|\n| Description | StarterOn(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### StarterOff<#>\n\n|  |  |\n|---|---|\n| Description | StarterOff(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ThrottleFull<#>\n\n|  |  |\n|---|---|\n| Description | ThrottleFull(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ThrottleIdle<#>\n\n|  |  |\n|---|---|\n| Description | ThrottleIdle(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ThrottleOff<#>\n\n|  |  |\n|---|---|\n| Description | ThrottleOff(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### RotorBrakeOn\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### RotorBrakeOff\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### AIAssemble\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ListLeftVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ListRightVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ListPrevLeftVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### ListPrevRightVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### CloseLeftVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### CloseRightVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### NextModeLeftVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### NextModeRightVehicleDisplay\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### UnloadUnconsciousUnits\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### HookCargo\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### UnhookCargo\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### LoadVehicle\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### UnloadVehicle\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |\n\n### UnloadAllVehicles\n\n|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |","sections":[{"heading":null,"level":1,"markdown":"> [!NOTE]\n> - See ArmA: Armed Assault: Actions for an introduction to Actions\n> - Not to be confused with playAction"},{"heading":"General Syntax","level":2,"markdown":"***unit* action [*\"actionType\"*, *parameter(s)*]**\n\n|  |  |\n|---|---|\n| *unit*: | Object. Can be any occupied vehicle or person that is not in a vehicle or also a Game Logic. |\n| *\"actionType\"*: | String. Name of the action, found in the CfgActions class. Not case sensitive. |\n| *parameter(s)*: | Various data types, dependant on the action used. The number of required parameters depends on the action type. |"},{"heading":"Actions","level":2,"markdown":""},{"heading":"ActiveSensorsOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Activates the vehicle's active sensor (radar). |\n| Syntax | *unit* action [\"ActiveSensorsOn\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"ActiveSensorsOn\", vehicle player];<br>``` |"},{"heading":"ActiveSensorsOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Deactivates the vehicle's active sensor (radar). |\n| Syntax | *unit* action [\"ActiveSensorsOff\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"ActiveSensorsOff\", vehicle player];<br>``` |"},{"heading":"AddBag","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| Description | Causes a unit to take backpack from another unit/vehicle or weaponholder. |  |\n| Syntax | *targetUnit* action [\"AddBag\", *sourceUnit*, *\"backpackName\"*] |  |\n|  | Where *targetUnit* is the person to receive a backpack (the action animation will be performed), *sourceUnit* is either another unit/vehicle or weaponholder containing the backpack. *\"backpackName\"* is the classname (string) of the backpack to be picked up. |  |\n| Note | Bags can be picked up at any distance. To drop bag use \"DropBag\" action. If several backpacks of the same class name exist in the container, the oldest will be added first. |  |\n| Examples | ```sqf<br>soldierOne action [\"AddBag\", soldierTwo, backpack soldierTwo];<br>```<br>```sqf<br>player action [\"AddBag\", car, typeOf firstBackpack car];<br>```<br>Swap player bag with parachute: <br>```sqf<br>player action [\"DropBag\", _plane, backpack player];<br>player action [\"AddBag\", _plane, \"B_Parachute\"];<br>``` |  |"},{"heading":"ArtilleryComputer","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| Description | Opens up Artillery Computer display just like the one in action menu for a mortar. Unit has to be in gunner position or display will immediately close. |  |\n| Syntax | *unit* action [\"ArtilleryComputer\", *artillery*] |  |\n|  | Where *unit* is any unit, and *artillery* is the artillery weapon |  |\n| Example | ```sqf<br>soldierOne action [\"ArtilleryComputer\", mortarOne];<br>``` |  |"},{"heading":"AutoHover","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Toggles auto-hovering on. Note that while the auto-hover status can be toggled on an AI crewed or even an empty vehicle, it will only affect a vehicle controlled by a human pilot. |\n| Syntax | *unit* action [\"AutoHover\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is capable of hovering. |\n| Example | ```sqf<br>chopperOne action [\"AutoHover\", chopperOne];<br>``` |"},{"heading":"AutoHoverCancel","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Toggles auto-hovering off. Note that while the auto-hover status can be toggled on an AI crewed or even an empty vehicle, it will only affect a vehicle controlled by a human pilot. |\n| Syntax | *unit* action [\"AutoHoverCancel\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is capable of hovering. |\n| Example | ```sqf<br>driver chopperOne action [\"AutoHoverCancel\", chopperOne];<br>``` |"},{"heading":"BackFromUAV","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Moves player control back from driver/gunner position of connected UAV. Does what \"Release UAV controls\" UI action does. |\n| Syntax | *unit* action [\"BackFromUAV\"] |\n|  | Where *unit* is the connected UAV unit. |\n| Example | ```sqf<br>getConnectedUAVUnit player action [\"BackFromUAV\"];<br>``` |"},{"heading":"CancelAction","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Cancels an action in progress. The target unit will complete it is current animation, although the action itself will not be performed. |\n| Syntax | *unit* action [\"CancelAction\", *targetUnit*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetUnit* is any unit that is in the process of performing an action. |\n| Example | ```sqf<br>soldierOne action [\"CancelAction\", soldierOne];<br>``` |"},{"heading":"CancelLand","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Cancels autopilot landing for an aircraft, including AI controlled aircraft. |\n| Syntax | *unit* action [\"CancelLand\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is any vehicle that is currently performing an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"CancelLand\", planeOne];<br>``` |"},{"heading":"CancelTakeFlag","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Cancels taking of a flag. The unit will complete the taking/action animation, but the flag will remain attached to it is current object. This action needs to be executed while the flag is being taken (which happens after the unit completes the taking/action animation) to prevent a unit taking the flag. For example, if a person is taking a flag from a flagpole, then the cancelTakeFlag action should be executed while the flag is descending the flagpole. |\n| Syntax | *unit* action [\"CancelTakeFlag\", *targetFlag*] |\n|  | Where *unit* is any unit that is currently taking a flag (no action animation is performed) and *targetFlag*' is a flag object. |\n| Example | ```sqf<br>westSoldierOne action [\"CancelTakeFlag\", eastFlag];<br>``` |"},{"heading":"CollisionLightOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns off the collision lights of an air vehicle. |\n| Syntax | *unit* action [\"CollisionLightOff\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"CollisionLightOff\", vehicle player];<br>``` |"},{"heading":"CollisionLightOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns on the collision lights of an air vehicle. |\n| Syntax | *unit* action [\"CollisionLightOn\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"CollisionLightOn\", vehicle player];<br>``` |"},{"heading":"Deactivate","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a unit to deactivate and take a active satchel charge placed by any unit. This action can be performed upon a satchel object from any distance.<br>This action also works for landmines created with createVehicle command:<br>```sqf<br>private _mine = \"ATMine_Range_Ammo\" createVehicle getPosATL player;    // create<br>player action [\"Deactivate\", player, mine];                            // deactivate<br>``` |\n| Syntax | *unit* action [\"Deactivate\", *targetUnit*, *targetObject*] |\n|  | Where *unit* is any unit (they will perform the action animation as if deactivating a satchel charge). *targetUnit* will have the deactivated satchel charge added to it is inventory. *targetObject* is the armed satchel object to be deactivated (class \"pipeBomb\" or \"timeBomb\"). |\n| Examples | ```sqf<br>soldierOne action [\"Deactivate\", soldierOne, mySatchelCharge];<br>``` |\n|  | ```sqf<br>soldierOne action [\"Deactivate\", soldierOne, nearestObject [soldierOne, \"pipeBomb\"]];<br>``` |"},{"heading":"DeactivateMine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a unit to deactivate any armed landmine that is within about two meters of a unit. Neither unit requires the ability to disable landmines.<br>NOTE: This action works only with mines that have been spotted by player (marked with triangle). Use \"Deactivate\" if you need to deactivate any mine. |\n| Syntax | *unit* action [\"DeactivateMine\", *targetUnit*] |\n|  | Where *unit* is any unit, who will perform the action animation. The closest landmine to *targetUnit* will be deactivated. |\n| Example | ```sqf<br>soldierOne action [\"DeactivateMine\", soldierOne];<br>``` |"},{"heading":"Diary","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"Diary\", *<target>*] |\n|  |  |\n| Example |  |"},{"heading":"Disassemble","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Takes assembled weapon to parts (carry bags). Assembled weapon object reference may need to be kept for assembly. See also: enableWeaponDisassembly |\n| Syntax | *unit* action [\"Disassemble\", *weapon*] |\n|  | Where *unit* is any unit and *weapon* is assembled weapon |\n| Example | ```sqf<br>soldierOne action [\"Disassemble\", mortarOne];<br>``` |"},{"heading":"DropBag","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| Description | Causes a unit to drop a backpack into another unit/vehicle. To drop backpack on the ground, a weaponholder object needs to be created first. |  |\n| Syntax | *sourceUnit* action [\"DropBag\", *targetUnit*, *\"backpackName\"*] |  |\n|  | Where *sourceUnit* is the person to drop a backpack (the action animation will be performed), *targetUnit* is either another unit/vehicle into which the backpack will be dropped or a weaponholder. *\"backpackName\"* is the classname (string) of the backpack to be dropped. |  |\n| Note | Bags can be dropped into other units at any distance. If targetUnit already has a backpack, sourceUnit's backpack will drop to the ground at targetUnit's feet, and be unavailable (for picking up/using). |  |\n| Examples | ```sqf<br>soldierOne action [\"DropBag\", soldierTwo, backpack soldierOne];<br>```<br>```sqf<br>private _gwh = \"Weapon_Empty\" createVehicle getPosATL player;<br>player action [\"DropBag\", _gwh, typeOf unitBackpack player];<br>// the reason \"Weapon_Empty\" type of weaponholder is used in this case is because<br>// unlike other weaponholders it is not autodeleted when empty and will not disappear before the action is complete.<br>// you should take care of deleting it after yourself. Alternatively use \"PutBag\" action.<br>```<br>```sqf<br>(unitBackpack player) setVariable [\"backpackOwner\", name player, true];<br>player action [\"DropBag\", car, typeOf unitBackpack player];<br>hint ((firstBackpack car) getVariable \"backpackOwner\");<br>```<br>Swap player bag with parachute:<br>```sqf<br>player action [\"DropBag\", _plane, backpack player];<br>player action [\"AddBag\", _plane, \"B_Parachute\"];<br>```<br>Transfer player's backpack to bob<br>```sqf<br>player action [\"DropBag\", bob];<br>``` |  |"},{"heading":"DropMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to drop a magazine either into another unit (both persons and vehicles), or onto the ground (creating a new WeaponHolder object). Magazines can be dropped into other units at any distance. |\n| Syntax | *unit* action [\"DropMagazine\", *targetUnit*, *\"magazineName\"*] |\n|  | Where *unit* is the person to drop a magazine (the action animation will be performed), *targetUnit* is either another unit into which the magazine will be dropped, or the same unit that is dropping the magazine. *\"magazineName\"* is the classname (string) of the magazine to be dropped (see the ArmA weapons list for magazine classnames). |\n| Examples | ```sqf<br>soldierOne action [\"DropMagazine\", soldierOne, \"30Rnd_545x39_AK\"];<br>``` |\n|  | ```sqf<br>soldierOne action [\"DropMagazine\", ammoCrateOne, \"30Rnd_545x39_AK\"];<br>``` |"},{"heading":"DropWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to drop a weapon and all associated magazines either into specified vehicle or weaponholder. Weapons can be dropped at any distance. |\n| Syntax | *unit* action [\"DropWeapon\", *targetHolder*, *\"weaponName\"*] |\n|  | Where *unit* is the person to drop a weapon (the action animation will be performed), *targetHolder* is either a vehicle or weaponholder. *\"weaponName\"* is the classname (string) of the CfgWeapons class. |\n| Examples | ```sqf<br>private _weaponHolder = \"GroundWeaponHolder_Scripted\" createVehicle getPosATL player;<br>player action [\"DropWeapon\", _weaponHolder, currentWeapon player];<br>```<br>```sqf<br>soldierOne action [\"DropWeapon\", unitBackpack soldierTwo, currentWeapon soldierOne];<br>player action [\"DropWeapon\", tank, \"arifle_MX_ACO_pointer_F\"];<br>``` |\n|  |  |"},{"heading":"Eject","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to eject out of the vehicle they are currently inside. If the unit was the driver of the vehicle, the vehicle will retain it is steering control input and it is engine will remain on. This action has a global effect when used on a local unit in multiplayer. If the vehicle parameter used is an moving aircraft, the ejecting person will use a parachute (and likewise if it is not an moving aircraft, no parachute will be used). |\n| Syntax | *unit* action [\"Eject\", *vehicle*] |\n|  | Where *unit* is the person to eject from their current vehicle, and *vehicle* is any vehicle (generally the vehicle *unit* is within). |\n| Example | ```sqf<br>soldierOne action [\"Eject\", vehicle soldierOne];<br>``` |"},{"heading":"EngineOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns a vehicle's engine on. This command will not override an AI driver's desires. |\n| Syntax | *unit* action [\"EngineOn\", *targetVehicle*] |\n|  | Where *unit* is any unit, and *targetVehicle* is the vehicle to start it is engine. |\n| Example | ```sqf<br>soldierOne action [\"EngineOn\", vehicle soldierOne];<br>``` |"},{"heading":"EngineOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns a vehicle's engine off. This command will not override an AI driver's desires. |\n| Syntax | *unit* action [\"EngineOff\", *targetVehicle*] |\n|  | Where *unit* is any unit, and *targetVehicle* is the vehicle to have it is engine turned off. |\n| Example | ```sqf<br>soldierOne action [\"EngineOff\", vehicle soldierOne];<br>``` |"},{"heading":"FireInflame","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Ignites a fireplace object (from any distance). |\n| Syntax | *unit* action [\"FireInflame\", *targetObject*] |\n|  | Where *unit* is any unit(the action animation will be performed), and *targetObject* is the fireplace to be ignited. |\n| Example | ```sqf<br>soldierOne action [\"FireInflame\", firePlaceOne];<br>``` |"},{"heading":"FirePutDown","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Extinguishes a fireplace object (from any distance). |\n| Syntax | *unit* action [\"FirePutDown\", *targetObject*] |\n|  | Where *unit* is any unit (the action animation will be performed), and *targetObject* is the fireplace to be extinguished. |\n| Example | ```sqf<br>soldierOne action [\"FirePutDown\", firePlaceOne];<br>``` |"},{"heading":"FlapsUp","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Adjusts an aircraft's flaps upwards one notch. AI pilot's will instantly adjust their flaps to whatever setting they feel is suitable. |\n| Syntax | *unit* action [\"FlapsUp\", *targetVehicle*] |\n|  | Where *unit* is any unit (the action animation will not be performed), and *targetVehicle* is the aircraft to have it is flaps adjusted. |\n| Example | ```sqf<br>harrierOne action [\"FlapsUp\", harrierOne];<br>``` |"},{"heading":"FlapsDown","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Adjusts an aircraft's flaps down one notch. AI pilot's will instantly adjust their flaps to whatever setting they feel is suitable. |\n| Syntax | *unit* action [\"FlapsDown\", *targetVehicle*] |\n|  | Where *unit* is any unit (the action animation will not be performed), and *targetVehicle* is the aircraft to have it is flaps adjusted. |\n| Example | ```sqf<br>harrierOne action [\"FlapsDown\", harrierOne];<br>``` |"},{"heading":"Gear","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Opens inventory dialog for the player and plays the appropriate animation. The left part of the inventory dialog gets populated with the inventory of the target unit. Player has to be in range of inventory operations with the targetUnit (~ <5m). |\n| Syntax | *unit* action [\"Gear\", *targetUnit*] |\n|  | Where *unit* is a player, and *targetUnit* is another player, vehicle or container. |\n| Examples | ```sqf<br>player action [\"Gear\", \"GroundWeaponHolder\" createVehicle position player];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", objNull];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", soldier1];<br>``` |\n|  | ```sqf<br>player action [\"Gear\", cursorTarget];<br>``` |"},{"heading":"GetInCargo","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly moves a person to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as cargo, in a specific cargo position if given as an optional parameter, otherwise in the first available cargo position. If the specific position is already occupied, the person will board in the first available cargo position. If the all cargo positions are already occupied by living persons, or no cargo position exists, the boarding will fail. This action works only with cargo positions that have no person turret, i.e. if player cannot shoot his rifle from them. If position is cargo but also person turret, it will be ignored. Use `fullCrew [_veh, \"cargo\", true]` to determine which positions are compatible cargo. Alternatively, use moveInCargo command instead, which has no such limitation. |\n| Syntax | *unit* action [\"GetInCargo\", *targetVehicle*] |\n|  | *unit* action [\"GetInCargo\", *targetVehicle*, *positionNumber*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. ''positionNumber is a specific cargo position index number. |\n| Examples | ```sqf<br>soldierOne action [\"GetInCargo\", truckOne];<br>``` |\n|  | ```sqf<br>soldierOne action [\"GetInCargo\", truckOne, 0];<br>``` |"},{"heading":"GetInCommander","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, they then attempt to board the vehicle as the commander. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInCommander\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInCommander\", tankOne];<br>``` |"},{"heading":"GetInDriver","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly moves an person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the driver/pilot. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInDriver\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInDriver\", carOne];<br>``` |"},{"heading":"GetInGunner","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the primary gunner. If the gunner position is already occupied by another living person or it does not exist, the boarding will fail. Also see getInTurret. |\n| Syntax | *unit* action [\"GetInGunner\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>soldierOne action [\"GetInGunner\", mySpotlight];<br>``` |"},{"heading":"GetInPilot","level":3,"markdown":"|  |  |\n|---|---|\n| Description | This action is identical to getInDriver. It instantly moves an person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the driver/pilot. The boarding will fail if the position is already occupied or does not exist. |\n| Syntax | *unit* action [\"GetInPilot\", *targetVehicle*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded. |\n| Example | ```sqf<br>pilotOne action [\"GetInPilot\", chopperOne];<br>``` |"},{"heading":"GetInTurret","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly moves a person (who is not already in a vehicle) to the appropriate boarding position of a vehicle, then they attempt to board the vehicle as the specified turret user. If the turret position is already occupied by another living person the boarding will fail. If the turret position does not exist, ArmA may crash. See also getInGunner. |\n| Syntax | *unit* action [\"GetInTurret\", *targetVehicle*, *turretArray*] |\n|  | Where *unit* is the person to board, and *targetVehicle* is the vehicle to be boarded, and *turretArray* is an array defining the turret. For example, *[1]* would be a vehicle's second turret, and *[0, 2, 1]* is the second turret of the third turret of the first turret. A vehicle's turret order is defined in it is class CfgVehicles of the Config. |\n| Examples | ```sqf<br>gunnerTwo action [\"GetInTurret\", myUH60MG, [1]];<br>``` |\n|  | ```sqf<br>tankCommanderOne action [\"GetInTurret\", myT72, [0,1]];<br>``` |"},{"heading":"GetOut","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to disembark from a vehicle, without a parachute in the case of aircraft. See also eject. |\n| Syntax | *unit* action [\"GetOut\", *targetVehicle*] |\n|  | Where *unit* is the person to disembark, and *targetVehicle* is the vehicle to disembark from. |\n| Example | ```sqf<br>soldierOne action [\"GetOut\", carOne];<br>``` |"},{"heading":"HandGunOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to ready their hand gun (if equiped). This action may not work if the unit does not have a primary rifle. |\n| Syntax | *unit* action [\"HandGunOn\", *targetUnit*] |\n|  | Where *unit* is any unit (who will not play the action animation), and *targetUnit* is the unit who will ready their pistol. |\n| Example | ```sqf<br>soldierOne action [\"HandGunOn\", soldierOne];<br>``` |"},{"heading":"HandGunOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to return a readied pistol to it is holster, then switch to the primary rifle. This action may not work if the unit does not have a primary rifle. |\n| Syntax | *unit* action [\"HandGunOff\", *targetUnit*] |\n|  | Where *unit* is any unit (who will not play the action animation), and *targetUnit* is the person to holster it is pistol. |\n| Example | ```sqf<br>soldierOne action [\"HandGunOff\", soldierOne];<br>``` |"},{"heading":"Heal","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Instantly teleports a person unit to the target medic. The target medic then heals the unit. If the target unit is not a medic, the animations will still be played, but no healing occurs. If the medic is within a vehicle, no teleporting will occur and the wounded unit will only be healed if they are already within healing range (a few meters). |\n| Syntax | *unit* action [\"Heal\", *targetUnit*] |\n|  | Where *unit* is a wounded person, and *targetUnit* is the medic to do the healing. |\n| Example | ```sqf<br>soldierOne action [\"Heal\", medicOne];<br>``` |"},{"heading":"HealSoldier","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Performs one soldier healing of another soldier. Needs to have MedKit or FAK (first aid kit) in the inventory, which gets used. |\n| Syntax | *unit* action [\"HealSoldier\", *targetUnit*] |\n|  | Where *unit* is the unit to perform treatment, and *targetUnit* is the unit to receive treatment. |\n| Example | ```sqf<br>player action [\"HealSoldier\", soldier1];<br>``` |"},{"heading":"HealSoldierSelf","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Performs one soldier healing of another soldier. In case the target is the same unit, the soldier performs treatment on himself. Needs to have FAK (first aid kit) in the inventory, which gets used. |\n| Syntax | *unit* action [\"HealSoldierSelf\", *targetUnit*] |\n|  | Where *unit* is the unit to perform treatment, and *targetUnit* is the unit to receive treatment. |\n| Example | ```sqf<br>player action [\"HealSoldierSelf\", soldier1];<br>``` |"},{"heading":"HideBody","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to bend down and hide (bury) a body in the ground. The body is automatically deleted within a few seconds. The person performing the action does not require the ability to hide bodies, and may be any distance from the body. |\n| Syntax | *unit* action [\"HideBody\", *targetUnit*] |\n|  | Where *unit* is a person, and *targetUnit* is a dead person. |\n| Example | ```sqf<br>soldierOne action [\"HideBody\", soldierTwo];<br>``` |"},{"heading":"InGameMenu","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"InGameMenu\", *<target>*] |\n|  |  |\n| Example |  |"},{"heading":"LadderDown","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to play an animation as if mounting the top of a ladder, then instantly teleport onto the specified ladder in the specified position. If the person is controlled by AI, they will automatically climb up or down the ladder. If the 2 parameter syntax is used, the person will become stuck in the ladder mounting animation state until the ladderOff action is executed upon them. It may also crash ArmA (pre 1.09). |\n| Syntax | *unit* action [\"LadderDown\", *targetObject*] |\n|  | *unit* action [\"LadderDown\", *targetObject*, *ladderNumber*, *positionNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is an object with a ladder, *ladderNumber* is a number defining the desired ladder, and *positionNumber* is a number defining the desired position. |\n| Example | ```sqf<br>soldierOne action [\"LadderDown\", (position soldierOne nearestObject 452221), 0, 1];<br>``` |"},{"heading":"LadderUp","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to play an animation as if mounting the bottom of a ladder, then instantly teleport onto the specified ladder in the specified position. If the person is controlled by AI, they will automatically climb up or down the ladder. If the 2 parameter syntax is used, the person will become stuck in the ladder mounting animation state until the ladderOff action is executed upon them. It may also crash ArmA (pre 1.09). |\n| Syntax | *unit* action [\"LadderUp\", *targetObject*] **!!!Warning!!! This syntax causes Arma 3 to freeze** |\n|  | *unit* action [\"LadderUp\", *targetObject*, *ladderNumber*, *positionNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is an object with a ladder, *ladderNumber* is a number defining the desired ladder, and *positionNumber* is a number defining the desired position (0 - bottom, 1 - top). All numbers in between get rounded towards 1 or 0. |\n| Example | ```sqf<br>soldierOne action [\"LadderUp\", (position soldierOne nearestObject 452221), 0, 0];<br>``` |"},{"heading":"LadderOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to dismount from any ladder of the specified object they may be happen to be on. The alternative 3 parameter syntax expects a number, the use of which is not known. |\n| Syntax | *unit* action [\"LadderOff\", *targetObject*] |\n|  | *unit* action [\"LadderOff\", *targetObject*, *unknownNumber*] |\n|  | Where *unit* is any person unit, *targetObject* is the object with a ladder that the person is currently upon, *unknownNumber* is a number. |\n| Example | ```sqf<br>soldierOne action [\"LadderOff\", (position soldierOne nearestObject 452221)];<br>``` |"},{"heading":"LadderOnDown","level":3,"markdown":"|  |\n|---|\n| **Description**: This action appears to be identical to LadderDown. |"},{"heading":"LadderOnUp","level":3,"markdown":"|  |\n|---|\n| **Description**: This action appears to be identical to LadderUp. |"},{"heading":"Land","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns on autopilot landing for an aircraft, including AI controlled aircraft. The aircraft will land at the closest airfield. |\n| Syntax | *unit* action [\"Land\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"Land\", planeOne];<br>``` |"},{"heading":"LandGear","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Lowers the landing gear of an aircraft. In the case of AI-controlled aircraft, it has to be used in an each-frame loop to override the AI behavior (otherwise they'll raise the landing gear when they take off). |\n| Syntax | *unit* action [\"LandGear\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"LandGear\", planeOne];<br>``` |"},{"heading":"LandGearUp","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Raises the landing gear of an aircraft. In the case of AI-controlled aircraft, it has to be used in an each-frame loop to override the AI behavior (otherwise they'll lower the landing gear when they're close to the ground). |\n| Syntax | *unit* action [\"LandGearUp\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle that can perform an autopilot landing. |\n| Example | ```sqf<br>driver planeOne action [\"LandGearUp\", planeOne];<br>``` |"},{"heading":"LightOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns off the headlights of an empty vehicle. If the vehicle is AI-controlled (either as the lone driver, or as the commander/gunner) then the light status depends on the AI's behaviour mode (\"combat\" or \"stealth\" = lights off, any other mode = lights on). |\n| Syntax | *unit* action [\"LightOff\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"LightOff\", vehicle player];<br>``` |"},{"heading":"LightOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns on the headlights of an empty vehicle. If vehicle is AI-controlled, see notes under the #LightOff action. |\n| Syntax | *unit* action [\"LightOn\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is a vehicle with lights. |\n| Example | ```sqf<br>player action [\"LightOn\", vehicle player];<br>``` |"},{"heading":"LoadMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Plays a reload weapon animation. |\n| Syntax | *unit* action [\"LoadMagazine\", target, magazineCreator, *number1*, *number2*, weaponName, muzzleName] |\n|  | Expects a 7 elements array: |\n|  | target: Object - unit to perform the reload action. |\n|  | magazineCreator: Object - unknown. Can be objNull. |\n|  | *number1*: Number - cr - see magazinesDetail. For characters it is mainly 0 |\n|  | *number2*: Number - id - magazine ID - can be obtained via magazinesDetail. With 0, it only plays the reload animation. With values from 1 up, it actually reloads the magazine. If the number becomes too high (meaning of the upper limit is also unknown), the action will no longer be performed. |\n|  | weaponName: String - weapon to reload. Must not be selected, but may cause weapon not to reload to the full amount. |\n|  | muzzleName: String - weapon's muzzle to reload. |\n| Example | ```sqf<br>player action [\"LoadMagazine\", player, player, 0, 1 , \"vbs2_us_m16a2_iron_gla\", \"vbs2_us_m16a2_iron_gla\"];<br>``` |"},{"heading":"LockVehicleControl","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Locks co-pilot controls, removes #TakeVehicleControl action. enableCopilot must be set true to function. |\n| Syntax | *unit* action [\"LockVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"LockVehicleControl\", vehicle player];<br>``` |"},{"heading":"ManualFire","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Enables manual fire mode for a player unit that is driver or commander of a vehicle. This action toggled manual fire mode in old versions of ArmA. (See also isManualFire) |\n| Syntax | *unit* action [\"ManualFire\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is the vehicle in which manual fire mode is to be enabled. |\n| Example | ```sqf<br>player action [\"ManualFire\", vehicle player];<br>``` |"},{"heading":"ManualFireCancel","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Disables manual fire mode for a player unit that is driver or commander of a vehicle. (See also isManualFire) |\n| Syntax | *unit* action [\"ManualFireCancel\", *targetVehicle*] |\n|  | Where *unit* is any unit (no action animation is performed) and *targetVehicle* is the vehicle in which manual fire mode is to be disabled. |\n| Example | ```sqf<br>player action [\"ManualFireCancel\", vehicle player];<br>``` |"},{"heading":"MarkEntity","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Use and effects unknown. Same as #MarkWeapon action. |\n| Syntax | *unit* action [\"MarkEntity\", <target>] |\n|  |  |\n| Example |  |"},{"heading":"MoveToCargo","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Move a unit to the chosen cargo position within a vehicle. If another unit is already in that position, the units will swap positions.<br>This works only with cargo positions that have no person turret, i.e. if player cannot shoot his rifle from them.<br>If position is cargo but also person turret, it will be ignored.<br>Use `fullCrew [_veh, \"cargo\", true]` to determine which positions are compatible cargo. |\n| Syntax | *unit* action [\"MoveToCargo\", *targetVehicle*, *cargoPosition*] |\n|  | Where *unit* is a unit within *targetVehicle*, and *cargoPosition* is the number of the desired cargo position (0 being the first). |\n| Example | ```sqf<br>player action [\"MoveToCargo\", vehicle player, 2];<br>``` |"},{"heading":"MoveToCommander","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Move a unit to the commander's position within a vehicle. If another unit is already in that position, the units will swap positions. |\n| Syntax | *unit* action [\"MoveToCommander\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToCommander\", vehicle player];<br>``` |"},{"heading":"MoveToDriver","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Move a unit to the driver's position within a vehicle. If another unit is already in that position, the units will generally swap positions, although in some scenarios this action may not work (although having the existing driver move always works). |\n| Syntax | *unit* action [\"MoveToDriver\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToDriver\", vehicle player];<br>``` |"},{"heading":"MoveToGunner","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Move a unit to the primary gunner's position within a vehicle. If another unit is already in that position, the units will swap positions. See also moveToTurret. |\n| Syntax | *unit* action [\"MoveToGunner\", *targetVehicle*] |\n|  | Where *unit* is a unit within *targetVehicle*. |\n| Example | ```sqf<br>player action [\"MoveToGunner\", vehicle player];<br>``` |"},{"heading":"MoveToPilot","level":3,"markdown":"|  |\n|---|\n| **Description**: Identical to moveToDriver. |"},{"heading":"MoveToTurret","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Move a unit to the chosen turret position within a vehicle. If another unit is already in that position, the units will swap positions. |\n| Syntax | *unit* action [\"MoveToTurret\", *targetVehicle*, *turretArray*] |\n|  | Where *unit* is a unit within *targetVehicle*, and *turret Array* is an array referring to the desired turret (for example, [0,1,2] refers to the third turret of the second turret of the first turret of the vehicle). |\n| Examples | ```sqf<br>player action [\"MoveToTurret\", vehicle player, [0]];<br>``` |\n|  | ```sqf<br>player action [\"MoveToTurret\", vehicle player, [0,1]];<br>``` |"},{"heading":"None","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"None\", *<target>*] |\n|  |  |\n| Example |  |"},{"heading":"NVGoggles","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a unit to put on it is night vision goggles. AI controlled units will automatically put on and take off goggles depending on daylight. |\n| Syntax | *unit* action [\"NvGoggles\", *<anything>*] |\n|  | Where *unit* is the unit to put on NVGoggles, and *<anything>* can be anything (it seems to not be used at all, but the action parameter array must contain at least two elements). |\n| Example | ```sqf<br>player action [\"NvGoggles\", player];<br>``` |"},{"heading":"NVGogglesOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a unit to take off it is night vision goggles. AI controlled units will automatically put on and take off goggles depending on daylight. |\n| Syntax | *unit* action [\"NvGogglesOff\", *<anything>*] |\n|  | Where *unit* is the unit to put on goggles, and *<anything>* can be anything (it seems not to be used at all, but the action parameter array must contain at least two elements). |\n| Example | ```sqf<br>player action [\"NvGogglesOff\", player];<br>``` |"},{"heading":"OpenParachute","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Opens unit's parachute. Unit must have parachute backpack. |\n| Syntax | *unit* action [\"OpenParachute\", *unit*] |\n|  | Where *unit* is the unit with parachute backpack. |\n| Example | ```sqf<br>player action [\"OpenParachute\", player];<br>``` |"},{"heading":"PutBag","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| Description | Causes *sourceUnit* to bend over and put target backpack on the ground. If the *targetUnit* param is omitted or it is the same as *sourceUnit*, the *sourceUnit* will drop own backpack. If *targetUnit* is another unit, *sourceUnit* will bend over but *targetUnit* will drop its backpack at its feet. |  |\n| Syntax | *sourceUnit* action [\"PutBag\", *targetUnit*] |  |\n|  | *targetUnit* is optional |  |\n| Note | To pick the backpack from the ground use \"AddBag\" action. |  |\n| Examples | ```sqf<br>player action [\"PutBag\"];<br>unit1 action [\"PutBag\", unit2];<br>``` |  |"},{"heading":"Rearm","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes an occupied vehicle or person to rearm from any object with some ammoCargo (generally an ammo truck) in the case of vehicles, or some magazines in it is cargo in the case of a rearming person. The rearming vehicle/person can be any distance from the rearming object. Rearming vehicles takes some time and will be interrupted if the vehicle starts to move. A rearming person will bend down as if picking up something. |\n| Syntax | *unit* action [\"Rearm\", *reamingObject*] |\n|  | Where *unit* is the occupied vehicle or person to be rearmed, and *rearmingObject* is the object from which to rearm. |\n| Examples | ```sqf<br>tankOne action [\"Rearm\", ammoTruckOne];<br>``` |\n|  | ```sqf<br>soldierOne action [\"Rearm\", ammoTruckOne];<br>``` |"},{"heading":"Refuel","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes an occupied vehicle to refuel from any object with some fuelCargo (generally an refueling truck). The refueling object can be any distance from the vehicle. Refueling takes some time and will be interrupted if the vehicle starts to move. |\n| Syntax | *vehicle* action [\"Refuel\", *refuelingObject*] |\n|  | Where *vehicle* is the occupied vehicle to be refueled, and *refuelingObject* is the object from which to refuel. |\n| Example | ```sqf<br>tankOne action [\"Refuel\", refuelTruckOne];<br>``` |"},{"heading":"Repair","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes an occupied vehicle to repair from any object with some repairCargo (generally an repair truck). The repair object can be any distance from the vehicle. Repairing takes some time and will be interrupted if the vehicle starts to move. |\n| Syntax | *vehicle* action [\"Repair\", *repairingObject*] |\n|  | Where *vehicle* is the occupied vehicle to be repaired, and *repairingObject* is the object from which to repair. |\n| Example | ```sqf<br>tankOne action [\"Repair\", repairTruckOne];<br>``` |"},{"heading":"ReturnFlag","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to return a flag from a nearby dead person back to it is flagpole. As of ArmA v1.12 this action is bugged and can not be used upon flags attached to destroyed vehicles. |\n| Syntax | *unit* action [\"ReturnFlag\", *targetObject*] |\n|  | Where *unit* is any person, and *targetObject* is the dead person with a flag to be returned. |\n| Example | ```sqf<br>soldierOne action [\"ReturnFlag\", westFlag];<br>``` |"},{"heading":"RepairVehicle","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes an Engineer unit to repair an object using their Engineer Repair ability (from v1.54). The Engineer can be any distance from the vehicle. Repairing takes some time. If *unit* is not the Engineer class no repairs are made but the animation will still play. |\n| Syntax | *unit* action [\"RepairVehicle\", *vehicle*] |\n|  | Where *unit* is an Engineer unit, and *vehicle* is the object to repair. |\n| Example | ```sqf<br>engineerOne action [\"RepairVehicle\", truckOne];<br>``` |"},{"heading":"Salute","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to salute. AI controlled units will only make a momentary salute, unless the AI is in safe or careless behaviour mode. |\n| Syntax | *unit* action [\"Salute\", *targetUnit*] |\n|  | Where *unit* is any unit (no animation is performed), and *targetUnit* is the person to make the salute. |\n| Example | ```sqf<br>soldierOne action [\"Salute\", soldierOne];<br>``` |"},{"heading":"ScudCancel","level":3,"markdown":"|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudCancel\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |"},{"heading":"ScudLaunch","level":3,"markdown":"|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudLaunch\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |"},{"heading":"ScudStart","level":3,"markdown":"|  |  |\n|---|---|\n| Description | There is no Scud Launcher in ArmA, however this action (probably) remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"ScudStart\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |"},{"heading":"SearchlightOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns off the vehicle's searchlight.<br>> [!NOTE]<br>> Out of all the vanilla vehicles, only the WY-55 Hellcat has a searchlight and the action should be used on the copilot seat. See Arma 3: Lights#Search Light. |\n| Syntax | *unit* action [\"SearchlightOff\", *vehicle*] |\n| Example | hellcatCopilot action [\"SearchlightOff\", vehicle hellcatCopilot] |"},{"heading":"SearchlightOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Turns on the searchlight.<br>> [!NOTE]<br>> Out of all the vanilla vehicles, only the WY-55 Hellcat has a searchlight and the action should be used on the copilot seat. See Arma 3: Lights#Search Light. |\n| Syntax | *unit* action [\"SearchlightOn\", *vehicle*] |\n| Example | hellcatCopilot action [\"SearchlightOn\", vehicle hellcatCopilot] |"},{"heading":"SetTimer","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitOne' plays the action animation. UnitTwo activates and adds 40 seconds to the timer for a satchel charge. Neither unit needs to be near the satchel.<br>Charge has to be placed first using *unitname Fire [\"pipebombmuzzle\", \"pipebombmuzzle\", \"pipebomb\"]* or createMine command. |\n| Syntax | *unitOne* action [\"SetTimer\", *unitTwo*, *bombName*] |\n|  |  |\n| Example |  |"},{"heading":"SitDown","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Causes a person to sit down on the ground (or get up, if already sitting). AI controlled units will only stay seated if they are in safe or careless behaviour mode. |\n| Syntax | *unit* action [\"SitDown\", *targetUnit*] |\n|  | Where *unit* is any unit (no animation is performed), and *targetUnit* is the person who is to sit down. |\n| Example | ```sqf<br>soldierOne action [\"SitDown\", soldierOne];<br>``` |"},{"heading":"StrokeFist","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Does nothing. There is no punch animation in Armed Assault and later titles, however this action remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"StrokeFist\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |"},{"heading":"StrokeGun","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Does nothing (other than making a person twitch a little). There is no suitable animation for this action in Armed Assault and later titles, however this action remains in the engine from the days of Operation Flashpoint. |\n| Syntax | *unit* action [\"StrokeGun\", *targetVehicle*] |\n|  | Syntax unknown. |\n| Example |  |"},{"heading":"Surrender","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Makes unit to put weapon on shoulder and put hands behind the head temporarily. For the lasting effect all weapons from the unit should be removed first. |\n| Syntax | *unit* action [\"Surrender\", *targetUnit*] |\n|  | Where *unit* is any unit, and *targetUnit* is the unit to surrender. |\n| Example | ```sqf<br>soldierOne action [\"Surrender\", soldierTwo];<br>``` |"},{"heading":"SuspendVehicleControl","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Release vehicle controls from co-pilot. Control immediately returns to pilot. |\n| Syntax | *unit* action [\"SuspendVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"SuspendVehicleControl\", vehicle player];<br>``` |"},{"heading":"SwitchMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Target unit switches to the given firing mode index. This allows selection of any firing mode for any weapon carried by a soldier, or mounted on a weapon. First are the firing modes for the primary weapon (index 0 upwards), then secondary weapon, then optics, then pistol, then thrown and placed weapons. Changing to NVGoggles just plays an animation, not actually setting NV mode. Unfortunately, the list of firing modes seems to only be created when a soldier is initiated; modes are removed from the list when a weapon is dropped and not re-added when a weapon is picked up. Thus, only use this during the initiation phase of the soldier. On vehicles, where the weapons are not likely to be changed, this action might be useful after the vehicle has been initiated. |\n|  | If the mode index is higher than available indices, it assumes index 0. If you just want to change the muzzle used, rather than the firing mode, the standard command selectWeapon is generally more useful. |\n| Syntax | *unit* action [\"SwitchMagazine\", *targetVehicle*, *targetUnit*, *mode index*] |\n|  |  |\n| Example | ```sqf<br>gameLogic action [\"SwitchMagazine\", unit1, unit1, 3];<br>gameLogic action [\"SwitchMagazine\", m1a1, gunner m1a1, 1];<br>``` |"},{"heading":"SwitchWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | UnitOne plays the action animation. Target unit switches to the given muzzle/mode index. Target unit can also be a vehicle. The weapons array is a list of all weapon modes specific to each weapon, muzzle and firing mode combination. |\n| Syntax | *unit* action [\"SwitchWeapon\", *targetUnit*, *targetUnit*, *muzzle index*] |\n|  |  |\n| Example | ```sqf<br>unit2 action [\"SwitchWeapon\", unit1, unit1, 7];<br>player action [\"SwitchWeapon\", player, player, 3];            // switching personal weapon<br>player action [\"SwitchWeapon\", vehicle player, player, 3];    // switching vehicle weapon<br>``` |\n|  | ```sqf<br>player action [\"SwitchWeapon\", player, player, weaponIndex];<br>```<br>Result => weaponIndex: weaponState for \"B_soldier_LAT_F\"<br> 0: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"Single\", \"30Rnd_65x39_caseless_mag\",30]<br> 1: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"FullAuto\", \"30Rnd_65x39_caseless_mag\",30]<br> 2: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"fullauto_medium\", \"30Rnd_65x39_caseless_mag\",30]<br> 3: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"single_medium_optics1\", \"30Rnd_65x39_caseless_mag\",30]<br> 4: [\"arifle_MX_ACO_pointer_F\", \"arifle_MX_ACO_pointer_F\", \"single_far_optics2\", \"30Rnd_65x39_caseless_mag\",30]<br> 5: [\"launch_NLAW_F\", \"launch_NLAW_F\", \"launch_NLAW_F\", \"NLAW_F\",1]<br> 6: [\"hgun_P07_F\", \"hgun_P07_F\", \"hgun_P07_F\", \"16Rnd_9x21_Mag\",16]<br> 7: [\"Throw\", \"HandGrenade_Stone\", \"HandGrenade_Stone\", \"\",0]<br> 8: [\"Throw\", \"HandGrenadeMuzzle\", \"HandGrenadeMuzzle\", \"\",0]<br> 9: [\"Throw\", \"MiniGrenadeMuzzle\", \"MiniGrenadeMuzzle\", \"\",0]<br> 10: [\"Throw\", \"MiniGrenadeMuzzle\", \"MiniGrenadeMuzzle\", \"\",0]<br> 11: [\"Throw\", \"SmokeShellYellowMuzzle\", \"SmokeShellYellowMuzzle\", \"\",0]<br> 12: [\"Throw\", \"SmokeShellYellowMuzzle\", \"SmokeShellYellowMuzzle\", \"\",0]<br> 13: [\"Throw\", \"SmokeShellRedMuzzle\", \"SmokeShellRedMuzzle\", \"\",0]<br> 14: [\"Throw\", \"SmokeShellPurpleMuzzle\", \"SmokeShellPurpleMuzzle\", \"\",0]<br> 15: [\"Throw\", \"SmokeShellOrangeMuzzle\", \"SmokeShellOrangeMuzzle\", \"\",0]<br> 16: [\"Throw\", \"SmokeShellBlueMuzzle\", \"SmokeShellBlueMuzzle\", \"\",0]<br> 17: [\"Throw\", \"SmokeShellBlueMuzzle\", \"SmokeShellBlueMuzzle\", \"\",0]<br> 18: [\"Throw\", \"ChemlightRedMuzzle\", \"ChemlightRedMuzzle\", \"\",0]<br> 19: [\"Throw\", \"ChemlightYellowMuzzle\", \"ChemlightYellowMuzzle\", \"\",0]<br> 20: [\"Throw\", \"ChemlightBlueMuzzle\", \"ChemlightBlueMuzzle\", \"\",0]<br> 21: [\"Throw\", \"IRGrenade\", \"IRGrenade\", \"\",0]<br> 22: [\"Put\", \"DemoChargeMuzzle\", \"DemoChargeMuzzle\", \"\",0]<br> 23: [\"Put\", \"PipeBombMuzzle\", \"PipeBombMuzzle\", \"\",0]<br> 24: [\"Put\", \"MineMuzzle\", \"MineMuzzle\", \"\",0]<br> 25: [\"Put\", \"ClassicMineRangeMuzzle\", \"ClassicMineRangeMuzzle\", \"\",0]<br> 27: [\"Put\", \"BoundingMineRangeMuzzle\", \"BoundingMineRangeMuzzle\", \"\",0]<br> 28: [\"Put\", \"DirectionalMineRangeMuzzle\", \"DirectionalMineRangeMuzzle\", \"\",0]<br> 29: [\"Put\", \"ClassicMineWireMuzzle\", \"ClassicMineWireMuzzle\", \"\",0]<br>As of **2.10**, weaponsInfo is better suited for finding the desired weapon index. |"},{"heading":"SwitchToUAVDriver","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Moves player control into driver position of connected UAV. Does what \"Take UAV controls\" UI action does. |\n| Syntax | *unit* action [\"SwitchToUAVDriver\", *uav*] |\n|  | Where *unit* is a player and *uav* is the connected UAV. |\n| Example | ```sqf<br>player action [\"SwitchToUAVDriver\", getConnectedUAV player];<br>``` |"},{"heading":"SwitchToUAVGunner","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Moves player control into gunner position of connected UAV. Does what \"Take UAV turret controls\" UI action does. |\n| Syntax | *unit* action [\"SwitchToUAVGunner\", *uav*] |\n|  | Where *unit* is a player and *uav* is the connected UAV. |\n| Example | ```sqf<br>player action [\"SwitchToUAVGunner\", getConnectedUAV player];<br>``` |"},{"heading":"TakeFlag","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitname' takes control of 'flag1'. He must be close to the flagpole and it must belong to an enemy side. |\n| Syntax | *unit* action [\"TakeFlag\", *flag1*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TakeFlag\", FlagOne];<br>``` |"},{"heading":"TakeMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unit' takes one magazine of specified type from the ground (Weaponholder) or from named vehicle (ammo box, car, etc.) Transfer happens immediately and via teleportation. Unit plays pickup animation at its current position, no matter where magazine is. Since Arma 3 v2.06.147667 optional param 'forcePutInBackpack' is added allowing to store picked up magazine in backpack. By default the magazine will go to any unit container with space, starting with uniform. |\n| Syntax | *unit* action [\"TakeMagazine\", *weaponholder*, *magazineName*, (*forcePutInBackpack*)] |\n|  | Where *unit* is any unit, and *weaponholder* is storage container. |\n| Example1 | ```sqf<br>player action [\"TakeMagazine\", ammoBox, \"RPGLauncher\"];<br>``` |\n| Example2 | Drop Magazine, then make your buddy Bob come and take magazine and put it in backpack:<br>```sqf<br>0 spawn<br>{<br>    private _wh = \"Weapon_Empty\" createVehicle (player getRelPos [2, 0]);<br>    private _mag = currentMagazine player;<br>    player action [\"PutMagazine\", _wh, _mag];<br>    private _bob = group player createUnit [\"B_Soldier_F\", player getRelPos [10, 0], [], 0, \"NONE\"];<br>    _bob addBackpack \"B_AssaultPack_blk\";<br>    _bob doMove position _wh;<br>    waitUntil { unitReady _bob };<br>    _bob action [\"TakeMagazine\", _wh, _mag, true];<br>};<br>``` |"},{"heading":"TakeWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitname' takes weapon of specified type (see list) from the ground (Weaponholder) or from named vehicle (ammo box, car, etc.) Transfer happens immediately and via teleportation. Unit1 plays pickup animation at its current position, no matter where weapon is. |\n|  | *unit* action [\"TakeWeapon\", *vehicle*, *weaponName*] |\n|  | Where *unit* is any unit, and *vehicle* is any unit or vehicle. |\n| Example | ```sqf<br>player action [\"TakeWeapon\", SoldierTwo, currentWeapon player];<br>``` |"},{"heading":"TakeMine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Unit will perform pick up action animation. The closest mine that is within two meters of the target unit will be placed into the target unit's inventory. The mine has to be active for this action to succeed. If there is not enough room in the target inventory, the mine will still be picked up but will not appear in inventory. See createMine for how to place explosive by script. |\n| Syntax | *unit* action [\"TakeMine\", *targetUnit*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TakeMine\", player];<br>``` |"},{"heading":"TakeVehicleControl","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| Description | In case of a helicopter, copilot will take flying controls, even if enableCopilot is disabled and isCopilotEnabled is false. | Use #SuspendVehicleControl action to release control. |\n| Syntax | *unit* action [\"TakeVehicleControl\", *vehicle*] |  |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |  |\n| Example | ```sqf<br>player action [\"TakeVehicleControl\", vehicle player];<br>``` |  |"},{"heading":"Talk","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Use and effects unknown. |\n| Syntax | *unit* action [\"Talk\", *target*] |\n|  |  |\n| Example |  |"},{"heading":"TeamSwitch","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Opens the normal team-switch dialog. <current unit> will be greyed out in the list and thus unselectable.<br>The effect of the second array element is unknown, but it must be a unit.<br>Works in single-player game only (in MP games, will just momentarily show the mouse cursor without the team-switch window being shown). |\n| Syntax | *currentUnit* action [\"TeamSwitch\", *unit*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TeamSwitch\", player];<br>``` |"},{"heading":"TouchOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitOne' plays the action animation. UnitTwo's satchels are \"touched off\".<br>UnitTwo must be within range (300m) of his satchels to touch them off. See createMine for how to place explosives with script. |\n| Syntax | *unitOne* action [\"TouchOff\", *unitTwo*] |\n|  |  |\n| Example | ```sqf<br>player action [\"TouchOff\", player];<br>``` |"},{"heading":"TurnIn","level":3,"markdown":""},{"heading":"TurnOut","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Crew of 'vehiclename' turns in/out (gets in and out of hatches).<br>UnitName must be a player in effective commander of vehicleName. AI will automatically turn in/out based on their current behaviour mode.<br>Only to be used on positions that have the turnIn/turnOut capability (otherwise it breaks the cargo anim). |\n| Syntax | *unit* action [\"TurnIn\", *vehicle*] |\n|  | *unit* action [\"TurnOut\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>commander TankOne action [\"TurnIn\", TankOne];<br>player action [\"TurnOut\", vehicle player];<br>``` |"},{"heading":"UAVTerminalHackConnection","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Hacks into given UAV. Does what \"Hack UAV\" UI action does. Player has to be in normal UI action proximity to the UAV for this action to work. <br>> [!NOTE]<br>> Controlling a UAV/UGV in Arma 3 is done via remote controlling the invisible driver or gunner AI. These AI units have to be on the same side as player. \"Hacking\" is essentially placing own AI into the UAV/UGV, either replacing existing AI, or creating own AI in empty positions (for example when UAV/UGV is placed 'without crew') |\n| Syntax | *unit* action [\"UAVTerminalHackConnection\", *uav*] |\n|  | Where *unit* is any unit (enemy to the drone) and *uav* is the UAV to hack. |\n| Example | ```sqf<br>player action [\"UAVTerminalHackConnection\", drone];<br>``` |"},{"heading":"UAVTerminalMakeConnection","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Connects player to chosen UAV. Does what \"Connect terminal to UAV\" UI action does.<br>**NOTE**: Player has to be in normal UI action proximity to the UAV for this action to work.<br>To connect to far away UAV use connectTerminalToUAV command instead. |\n| Syntax | *unit* action [\"UAVTerminalMakeConnection\", *uav*] |\n|  | Where *unit* is a player and *uav* is UAV to be connected to. |\n| Example | ```sqf<br>player action [\"UAVTerminalMakeConnection\", allUnitsUAV select 0];<br>``` |"},{"heading":"UAVTerminalOpen","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Opens UAV Terminal UI. Player must have UAV Terminal item in GPS slot of inventory. Does what \"Open UAV Terminal\" UI action does. |\n| Syntax | *unit* action [\"UAVTerminalOpen\", *unit*] |\n|  | Where *unit* is a player. |\n| Example | ```sqf<br>player action [\"UAVTerminalOpen\", player];<br>``` |"},{"heading":"UAVTerminalReleaseConnection","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Disconnects player from connected UAV. Does what \"Disconnect terminal from UAV\" UI action does.<br>**NOTE**: Unlike with \"UAVTerminalMakeConnection\", player can be far away from the UAV. Notice how the passed params are swapped around for this action. |\n| Syntax | *uav* action [\"UAVTerminalReleaseConnection\", *unit*] |\n|  | Where *uav* is the connected UAV and *unit* is the player controlling it. |\n| Example | ```sqf<br>getConnectedUAV player action [\"UAVTerminalReleaseConnection\", player];<br>``` |"},{"heading":"UnlockVehicleControl","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Unlocks co-pilot controls, shows Take Control action. enableCopilot must be set true to function. |\n| Syntax | *unit* action [\"UnlockVehicleControl\", *vehicle*] |\n|  | Where *unit* is any unit, and *vehicle* is any vehicle with co-pilot controls. |\n| Example | ```sqf<br>player action [\"UnlockVehicleControl\", vehicle player];<br>``` |"},{"heading":"UseMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Loads a weapon with magazine with known id and fires that weapon. The weapon is selected based on magazine type. Details for <cr> and <id> can be found with magazinesDetail command (not 100% about <cr> but it seems 0 works for all weapons) |\n| Syntax | *logic* action [\"UseMagazine\", *target*, *magazine creator*, *<cr>*, *<id>*] |\n|  |  |\n| Example | ```sqf<br>private _logic = createGroup west createUnit [\"Logic\", [0,0,0], [], 0, \"NONE\"];<br>hint str magazinesDetail player; // loaded mags not shown<br>/*[<br>\"6.5mm 30Rnd STANAG Mag(30/30)[id/cr:3/0]\",<br>\"Smoke Round (White)(1/1)[id/cr:121/0]\",<br>\"Smoke Round (White)(1/1)[id/cr:122/0]\",<br>\"9mm 16Rnd Mag(16/16)[id/cr:11/0]\"<br>]*/<br>_logic action [\"UseMagazine\", player, player, 0, 3];    // loads rifle with mag id 3 and fires<br>_logic action [\"UseMagazine\", player, player, 0, 11];    // loads pistol with mag id 11 and fires from inventory<br>_logic action [\"UseMagazine\", player, player, 0, 121];    // throws smoke grenade with id 121<br>``` |"},{"heading":"User","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitName' does nothing. Executes the custom action with the given index of the the target unit. Indexes are based upon the order in which the actions are added to the unit. See addAction. |\n| Syntax | *unitName* action [\"User\", *target unit*, *action index*] |\n|  |  |\n| Example | ```sqf<br>gameLogic action [\"User\", player, 3];<br>``` |"},{"heading":"UserType","level":3,"markdown":"|  |  |\n|---|---|\n| Description | As of ArmA version 1.08, using this action type will cause ArmA to crash to desktop. |\n| Syntax | *unit* action [\"UserType\", *target*, *action index*] |\n|  |  |\n| Example |  |"},{"heading":"UseWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitOne' will play the action animation. Target unit will fire the specified unit's position in the target vehicle's (can be the unit itself) weapon mode index. The indexes seem to be based upon the order in which weapons are added to the unit/vehicle, with each weapon's muzzle's fire mode having an unique index. Weapons can be fired in this way from a not-readied position (eg, firing a rifle on a soldiers back). Pistols will fire from the current weapon's proxy. It can also be used to sound the horn on AI controlled vehicles. |\n|  | **NOTE:** If 'unitOne' is player object, the player goes into pick up animation before action is performed. If 'unitOne' is a game logic, the action is performed immediately with no animation. |\n| Syntax | *unitOne* action [\"UseWeapon\", *target vehicle*, *target unit*, *weapon index*] |\n|  |  |\n| Example | ```sqf<br>_logic = createGroup west createUnit [\"Logic\", [0,0,0], [], 0, \"NONE\"];<br>_logic action [\"UseWeapon\", player, player, 0];    // player fires single shot<br>_logic action [\"UseWeapon\", player, player, 2];    // player fires 3 round burst<br>_logic action [\"UseWeapon\", player, player, 5];    // player fires pistol from inventory<br>_logic action [\"UseWeapon\", player, player, 7];    // player throws hand grenade<br>_logic action [\"UseWeapon\", car, car, 0];        // car sounds its horn<br>// more examples<br>gameLogic action [\"UseWeapon\", unit1, unit1, 16];<br>gameLogic action [\"UseWeapon\", vehicle unit1, unit1, 0];<br>gameLogic action [\"UseWeapon\", myTank, gunner myTank, 1];<br>gameLogic action [\"UseWeapon\", myTank, commander myTank, 0];<br>``` |"},{"heading":"VectoringDown","level":3,"markdown":"|  |  |\n|---|---|\n| Description | If VTOL auto-vectoring is off, incremental forward tilt of engine nacelles. |\n| Syntax | *unit* action [\"VectoringDown\", *vehicle*] |\n|  |  |\n| Example |  |"},{"heading":"VectoringUp","level":3,"markdown":"|  |  |\n|---|---|\n| Description | If VTOL auto-vectoring is off, incremental upward tilt of engine nacelles. |\n| Syntax | *unit* action [\"VectoringUp\", *vehicle*] |\n|  |  |\n| Example |  |"},{"heading":"VTOLVectoring","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Toggles **off** VTOL auto-vectoring (manual mode) |\n| Syntax | *unit* action [\"VTOLVectoring\", *vehicle*] |\n|  |  |\n| Example |  |"},{"heading":"VTOLVectoringCancel","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Toggles **on** VTOL auto-vectoring (forward mode) |\n| Syntax | *unit* action [\"VTOLVectoringCancel\", *vehicle*] |\n|  |  |\n| Example |  |"},{"heading":"WeaponInHand / WeaponOnBack","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Soldier 'unitName' does nothing, 'target unit' moves his weapon from/to the safety position (gun held across chest pointing at the ground).<br>Change is persistent with player, but AI units will change back to suit their current setBehaviour\\|behaviour mode. AI generally keep their rifles safe unless moving or targeting. |\n| Syntax | *unitName* action [\"WeaponInHand\", *target unit*] |\n|  | *unitName* action [\"WeaponOnBack\", *target unit*] |\n|  |  |\n| Example | ```sqf<br>SoldierOne action [\"WeaponOnBack\", SoldierTwo];<br>``` |"},{"heading":"WheelsBrakeOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Engages wheels brakes on RTM helicopter |\n| Syntax | *unit* action [\"WheelsBrakeOn\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"WheelsBrakeOn\", heli];<br>``` |"},{"heading":"WheelsBrakeOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Disengages wheels brakes on RTM helicopter |\n| Syntax | *unit* action [\"WheelsBrakeOff\", *vehicle*] |\n|  |  |\n| Example | ```sqf<br>player action [\"WheelsBrakeOff\", heli];<br>``` |"},{"heading":"Unsorted actions found in UI.pbo/config.bin","level":2,"markdown":""},{"heading":"LoadOtherMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"LoadEmptyMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"PutWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Is alias of DropWeapon |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>_wh = \"GroundWeaponHolder_Scripted\" createVehicle position player;<br>player action [\"PutWeapon\", _wh, currentWeapon player];<br>``` |"},{"heading":"PutMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| Description | is synonym for DropMagazine (same syntax)? |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"StartTimer","level":3,"markdown":"|  |  |\n|---|---|\n| Description | is synonym for SetTimer (same syntax) ? |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"HideWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax | unit action [\"HideWeapon\", <object>, <object>, <Number>] |\n|  |  |\n| Example |  |"},{"heading":"MarkWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Something to do with campaign. Campaign param \"WeaponPool\" has to be enabled as well as mission param \"MarkWeapons\". Possibly related to \"MarkEntity\" action as well. |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"HandGunOffStand","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"HandGunOnStand","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"TakeDropMagazine","level":3,"markdown":"|  |  |\n|---|---|\n| **Description**: Redundant even if works, use #TakeMagazine |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"TakeDropWeapon","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"Assemble","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>_unit action [\"Assemble\", nearestObject [_unit, \"Tripod_Bag\"]];<br>``` |"},{"heading":"FirstAid","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"GetOver","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"GunLightOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"GunLightOff\", player];<br>``` |"},{"heading":"GunLightOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"GunLightOn\", player];<br>``` |"},{"heading":"IRLaserOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"IRLaserOff\", player];<br>``` |"},{"heading":"IRLaserOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example | ```sqf<br>player action [\"IRLaserOn\", player];<br>``` |"},{"heading":"OpenBag","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Opens inventory UI with backpack of a unit (another unit). Unit must be in proximity. |\n| Syntax | unit1 action [\"OpenBag\", unit2]; |\n|  |  |\n| Example | player action [\"OpenBag\", bob]; |"},{"heading":"TakeBag","level":3,"markdown":"|  |  |\n|---|---|\n| Description | Unit takes specified backpack from the ground. |\n| Syntax | _unit action [\"TakeBag\", _bag]; |\n|  |  |\n| Example | ```sqf<br>player addEventHandler [\"WeaponDisassembled\",<br>{<br>    _this spawn {<br>        _unit = _this select 0;<br>        _bag1 = _this select 1;<br>        _bag2 = _this select 2;<br>        _currBag = unitBackpack _unit;<br>        titleText [\"You are not allowed to disassemble static weapons.\", \"PLAIN DOWN\", 0.5];<br>        _unit action [\"TakeBag\", _bag1];<br>        _time = time + 3;<br>        waitUntil { unitBackpack _unit == _bag1 \\|\\| time > _time };<br>        _unit action [\"Assemble\", _bag2];<br>        if (!isNull _currBag) then { _unit action [\"TakeBag\", _currBag] };<br>    };<br>}];<br>``` |"},{"heading":"Tell","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"APUOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"APUOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"BatteriesOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"BatteriesOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"StarterOn<#>","level":3,"markdown":"|  |  |\n|---|---|\n| Description | StarterOn(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"StarterOff<#>","level":3,"markdown":"|  |  |\n|---|---|\n| Description | StarterOff(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ThrottleFull<#>","level":3,"markdown":"|  |  |\n|---|---|\n| Description | ThrottleFull(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ThrottleIdle<#>","level":3,"markdown":"|  |  |\n|---|---|\n| Description | ThrottleIdle(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ThrottleOff<#>","level":3,"markdown":"|  |  |\n|---|---|\n| Description | ThrottleOff(1-3) |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"RotorBrakeOn","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"RotorBrakeOff","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"AIAssemble","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ListLeftVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ListRightVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ListPrevLeftVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"ListPrevRightVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"CloseLeftVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"CloseRightVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"NextModeLeftVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"NextModeRightVehicleDisplay","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"UnloadUnconsciousUnits","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"HookCargo","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"UnhookCargo","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"LoadVehicle","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"UnloadVehicle","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"},{"heading":"UnloadAllVehicles","level":3,"markdown":"|  |  |\n|---|---|\n| Description |  |\n| Syntax |  |\n|  |  |\n| Example |  |"}],"categories":["Actions"],"groups":["Scripting"]},{"name":"Arma 3: Curator","title":"Arma 3: Curator","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Curator","revid":369849,"updated":"2024-10-16T13:52:02Z","aliases":["Arma 3 Curator","Curator","Zeus Editing"],"markdown":"**Curator** is a technical name for Arma 3 Zeus game master system. Every involved scripting command, event handler or class name contains the name.\nThe reason for it is to have a generic name which can be passed from project to project without any associations.\n\n### Setup\n\nThe central piece of every curator is Game Master module, otherwise referred to as Curator Logic. It stores every setting, like editing areas, available objects or their costs.\n\nYou can find the module in **Systems (F5) > Zeus > Game Master**\n\nIn module arguments, can set the curator unit (either specific unit, player with given UID or server admin) and that's all you need to add game master to your mission.\nWithout any further settings, all objects will be available for free and whole map will be editable.\n\nThere can be multiple modules present in a mission, each with its own settings. As a result, you can have for example two competing curators, or a group of allied curators, each with different abilities.\n\nIn every examples on this page, we'll call the module *myCurator*.\n\n> [!NOTE]\n> - Detailed module descriptions are available in the game after clicking on SHOW INFO button while editing a module.\n> - Function descriptions can be accessed in game using Functions Viewer.\n> - All curator related scripting commands can be found in the Curator command group.\n\n### Costs\n\nMission designer can assign cost to every object curator can interact with. The cost is applied when performing actions like placing, editing or deleting.\nIt affects curator's resources - **points** - which are in range from 0 (no points) to 1 (full points; can't be larger than this value).\nThe cost can be both negative and positive, so some actions can actually add points (e.g., deleting).\nPoints can be adjusted by addCuratorPoints and returned using curatorPoints, or you can use *Manage Resources* module.\n\nCosts for each entity type are calculated differently:\n- Object costs are defined in the event handler.\n- Modules are perceived as normal objects and are also defined in the handler.\n- Waypoint costs are set by setCuratorWaypointCost command.\n- Markers are always free.\n\n#### Assigning\n\n##### Manual\n\nYou can assign individual cost for every object in the game using CuratorObjectRegistered event handler.\nIt's executed when player enters curator interface, so individual values cannot be changed on the fly.\nHowever, you can still tweak costs using action coefficients and available objects by unlocking addons.\n\n```sqf\nmyCurator addEventHandler [\"CuratorObjectRegistered\", { /* code here, see below */ }];\n```\n\nArguments passed into the handler are:\n- curator: Object\n- input: Array of Strings - all CfgVehicles classes\n\nExpected returned value is an Array of Arrays of the same size as the input array, with each item belonging to a class with the same array index. Missing or incorrect values will be replaced by default *[true,0,0]*.\n- Input: `[string1, string2, string3, ... classN]`\n- Output: `[array1, array2, array3, ... arrayN]`\n**Example**:\n- Input (3 classes): `[\"B_Soldier_F\", \"B_MRAP_01_F\", \"ModuleLightning_F\"]`\n- Output (3 arrays with settings): `[[true, 0.1], [true, 0.5, 0.6], [false, 0, 0]]`\n\nEvery item in the array is in the following format:\n [show, cost, (costWithCrew)]\n- show: Boolean - true to let the object appear in the CREATE list, false to hide it (costs will still be accepted if an object of the type is already present in the mission and made editable)\n- cost: Number - cost of the object\n- costWithCrew (Optional): Number - cost of the object with crew in it (affects only vehicles). When undefined, normal cost is used.\n\n**Example of the whole event handler:**\n\n```sqf\nmyCurator addEventHandler [\n    \"CuratorObjectRegistered\",\n    {\n        _classes = _this select 1;\n        _costs = [];\n        {\n            _cost = if (_x isKindOf \"Man\") then {[true,0.1]} else { [false, 0] }; // show only objects of type \"Man\", hide everything else\n            _costs pushBack _cost;\n        } forEach _classes; // go through all classes and assign cost for each of them\n        _costs\n    }\n];\n```\n\nAlternatively, you can set cost of specific objects by BIS_fnc_curatorObjectRegistered, with crew costs calculated automatically based on vehicle cost + cost of all crew members.\n- When the function is executed multiple times, results are combined together.\n  - Example:\n    - **Show** value of an object has to be true in all instances (e.g., one false will hide the object)\n    - **Cost** values are multiplied together (e.g., one 0 will set the cost to 0)\n\n##### Using Cost Tables\n\nThere's a scripted function which will export all objects from specified addons into spreadsheet format, where you can define individual costs and see additional data, like how many objects can be build at one or how long will it take to \"recharge\" points until the object is available. The table also automatically calculates costs of vehicles with crew and of whole groups. As such, it is invaluable tool for balancing curator missions.\n\nSteps how to create the table:\n1. Call BIS_fnc_exportCuratorCostTable to generate the table based on given addons into clipboard\n**Example:** `[\"A3_Characters_F_BLUFOR\", \"A3_Soft_F_MRAP_01\"], \"ods\"] spawn BIS_fnc_exportCuratorCostTable;`\n1. Run OpenOffice Calc (or Microsoft Excel; use \"xls\" as a second param when calling the functions, as both programs are using different formula formatting)\n1. Paste the generated text into the spreadsheet\n\nNow when the table is generated, you can assign specific costs to each objects and watch how it affects vehicles and groups involving the object./\n- Class names in the second column leads to Arma 3 Assets page with further details, like weapons or magazines the object can carry.\n- Display names in the third column are links directly to object preview images.\n\nWhen finished, export the result into the game by following these steps:\n1. Scroll down to \"Export\" field\n1. Copy all cells between *// Generated by BIS_fnc_exportCuratorCostTable* and the document end.\n**Example:**\n\n```sqf\n// Generated by BIS_fnc_exportCuratorCostTable\n// [[\"A3_Characters_F_BLUFOR\",\"A3_Soft_F_MRAP_01\"],\"ods\"] call BIS_fnc_exportCuratorCostTable;\n_BLUFOR_A3_Characters_F_BLUFOR = ['B_Soldier_GL_F',1,'B_soldier_AR_F',1,'B_Soldier_TL_F',1,'B_soldier_LAT_F',1,,0];\n_BLUFOR_A3_Soft_F_MRAP_01 = ['B_MRAP_01_F',3,,0];\n_BLUFOR = _BLUFOR_A3_Characters_F_BLUFOR + _BLUFOR_A3_Soft_F_MRAP_01 + [];\n```\n\n1. Import the result in the game again using BIS_fnc_curatorObjectRegisteredTable\n**Example:**\n\n```sqf\n[myCurator,_BLUFOR] call BIS_fnc_curatorObjectRegisteredTable;\n```\n\n#### Action Coefficients\n\nOnce you assigned cost to every object, you can now use it for every action curator can perform.\n\n```sqf\nmyCurator setCuratorCoef [\"place\", -0.2];\n```\n\nIf some object, for example BLUFOR soldier \"B_Soldier_F\" from the previous example, will have assigned cost 0.1, cost for placing will be:\n\n*0.1 * -0.2 = -0.02*\n\nIf curator have full points (value is 1), it means he can build 50 BLUFOR soldiers (*-1 * -0.02 = 50*). While individual object costs cannot be changed on the fly, coefficient can be easily used to tweak all costs.\n\nAvailable actions are:\n- \"place\"\n- \"edit\"\n- \"delete\"\n- \"destroy\"\n- \"group\"\n- \"synchronize\"\n\nAdditionally, while action can be disabled by assigning large negative coefficient, e.g., -10000. Trying to perform the action will then result in onscreen warning for curator.\n\nCoefficients can be also assigned in *Set Editing Costs* module.\n\n### Unlocking Addons\n\nYou can set which objects will be available curator by toggling specific addons. This can be done on the fly, and it is primary way how to unlock content for curator during a mission.\n\nSee Arma 3 assets to check which objects belongs to which addon, or use unitAddons to get addons of specific object class.\n\n> [!NOTE]\n> Only activated addons can be added (i.e., addons preloaded by the mission).\n> All official addons are activated by default, but unofficial ones are activated only when an object contained in such addon is present in the mission.\n> If that's not the case, you can use activateAddons or BIS_fnc_activateAddons to activate them. This is however possible only at the mission start - on the fly activation is not possible.\n\nInitial addons can be adjusted in *Game Master* module attributes, with available values being:\n- **All official addons** - default state, includes all activeted addons\n- **Addons present in the mission** - only addons of objects present in the mission upon mission start. E.g., if you inserted only BLUFOR soldiers and MRAPs in the mission, addons will be [\"A3_Characters_F_BLUFOR\",\"A3_Soft_F_MRAP_01\"]\n- **None** - no addons are enabled by the module, mission designer has to add them manually.\n\nDuring the missions, use *Manage Addons* module or scripting commands to toggle addons:\n- addCuratorAddons\n- removeCuratorAddons\n- removeAllCuratorAddons\n- curatorAddons\n\n**Example:**\n\n```sqf\nmyCurator addCuratorAddons [\"A3_Armor_F_AMV\", \"A3_Armor_F_Panther\"];\nmyCurator removeCuratorAddons [\"A3_Soft_F_MRAP_01\"];\n```\n\n#### Community Addons\n\nCurator system relies on correct configuration of object. When you unlock an addon, it will in turn enable all objects defined in *units* array of *CfgPatches*.\nIf the addon author didn't do this, his objects won't be available.\n\n```cpp\nclass CfgPatches\n{\n    class TAG_MyAddon\n    {\n        units[] = { \"TAG_MyObject1\", \"TAG_MyObject2\" }; // here\n        weapons[] = {};\n        requiredVersion = 1;\n        requiredAddons[] = {};\n    };\n};\n```\n\n### Editable Objects\n\nBy default, every object placed by curator is immediately made editable. Any other object can be added by *Add Editable Objects* module or using\nscripting commands:\n- addCuratorEditableObjects\n- removeCuratorEditableObjects\n- curatorEditableObjects\n\nEditable players are marked by a red color in the EDIT list and by red circle displayed over their icon. They cannot be moved, rotated, deleted or destroyed, but grouping, syncing and setting attributes works.\nEditable players can also ping their curator by pressing Zeus key (<kbd>Y</kbd> by default), which results in their name and icon flashing for a short moment.\nCurator can press <kbd>Space</kbd> to quickly move the camera to their location.\n\n### Editing Areas\n\nEditing area is a zone in which curator can modify entities. It's used to limit curator into specific area, or restrict him from other (e.g., around players).\n\nIt can be set using *Add Editing Area* and *Restrict Editing Around Players* modules or by following scripting commands:\n- addCuratorEditingArea\n- removeCuratorEditingArea\n- removeAllCuratorEditingAreas\n- curatorEditingArea\n- setCuratorEditingAreaType\n- allowCuratorLogicIgnoreAreas\n\nAreas can be circle only, and can be composed together to build much larger area. Mission designer can set whether editing is allowed only inside them, or only outside them.\nFor performance reasons, it is not possible to define it per individual area.\n\nFor curator, the area is visualized by blue (during day) and green (during night) \"walls\" in the scene and by black icons in the map. Players can't see it.\n\n*Table showing which actions are permitted **outside** of the editing area for each entity type:*\n\n|  | Place | Edit | Delete | Destroy | Group | Synchronize |\n|---|---|---|---|---|---|---|\n| Objects | Restricted | Restricted | Restricted | Allowed | Allowed | Allowed |\n| Modules | Based on allowCuratorLogicIgnoreAreas | N/A | N/A | Allowed |  |  |\n| Markers | Allowed | Allowed | Allowed | N/A | N/A | N/A |\n| Waypoints | Allowed | Allowed | Allowed | N/A | N/A | N/A |\n\n### Camera\n\n#### Camera Area\n\nCamera area defines where can curator move with the camera. It's not visualized in any way, but reaching the border will result in camera \"sliding\" along it, so it can be felt.\nAs with editing areas, camera ones can also be grouped into larger chunks, and designer can set whether they camera can operate only inside or only outside of them.\nAdditionally, it is possible to set maximal camera altitude.\n\nUse *Add Camera Area* or following scripting commands to set the area:\n- addCuratorCameraArea\n- removeCuratorCameraArea\n- removeAllCuratorCameraAreas\n- curatorCameraArea\n- setCuratorCameraAreaCeiling\n\n#### Camera Position\n\nYou can teleport curator camera to specific position using *Set Camera Positon*.\nThe module can be also use to set default camera position after opening curator interface, when *Use as default* module attribute is set to *Enabled*.\n\nIn scripts, you can move curatorCamera around like any other object. However, most camera commands won't work on it.\nThe camera is local to the curator owner, so any changes to it has to be executed locally as well.\n\n**Example:**\n\n```sqf\ncuratorCamera setPos [position player select 0, position player select 1, 30];\ncuratorCamera setVectorDirAndUp [[0, 1, -0.5], [0, 0, 1]];\n```\n\nYou can also call BIS_fnc_setCuratorCamera, which will also let you to transition the camera into desired position smoothly.\n\n### Attributes\n\nAttributes are specific settings available after double-clicking on an entity.\n\nYou can set which attributes will be available for entities by *Set Attributes* modules or using BIS_fnc_setCuratorAttributes. By default, all attributes are shown. Modules are using custom attributes.\n\nAvailable attributes for each entity type are:\n- **Object / Player**\n  - Skill\n  - UnitPos\n  - Rank\n  - Damage\n  - Fuel\n  - Lock\n  - RespawnVehicle\n  - RespawnPosition\n  - Exec *(visible only when debug console is available)*\n- **Group**\n  - GroupID\n  - Behaviour\n  - Formation\n  - UnitPos\n- **Marker**\n  - Text\n  - Color\n- **Waypoint**\n  - Behaviour\n  - Formation\n\n### Icons\n\nMission designer can show an icon visible only in curator interface\n- Use *Add Icon* module or BIS_fnc_addCuratorIcon and BIS_fnc_removeCuratorIcon to manage custom icons. Icon definition is the same as is used by drawIcon3D command\n- BIS_fnc_drawCuratorDeaths will show a skull icon on position where given unit died (useful for tracking where players are dying in PvP matches)\n- BIS_fnc_drawCuratorLocations shows names of nearby settlements, which can help with navigation on large terrains.\n- BIS_fnc_drawCuratorRespawnMarkers shows an icon on respawn markers\n\n### Compositions\n\nSince Arma 3 v2.06 is it possible to place custom compositions created in Eden Editor in Zeus.\nIn order to enable Zeus to spawn custom compositions *zeusCompositionScriptLevel* needs to be defined in Description.ext#zeusCompositionScriptLevel **or** Arma 3: Server Config File.\n\n#### Notes\n\n- Arma 3: Simple Objects are not supported. They will be placed as normal entities\n- Compositions that use non-whitelisted/non-loaded mods are not shown in the compositions list\n- Some objects cannot be edited after spawning (USS Liberty/Freedom ships), as they only create a dummy object, that then spawns the ship parts afterward\n- Mines are not \"supported\". You can place them but not edit/remove them after placing\n\n#### Shortcuts\n\n- Press <kbd>Ctrl</kbd> to make the composition follow the terrain\n- Press <kbd>Alt</kbd> to place the composition at its original location where it was created in Eden Editor\n\n### Misc\n\n- [Zeus logo PSD source file](http://temp.moricky.com/zeusLogo.psd)\n\nArma 3 Editing","sections":[{"heading":null,"level":1,"markdown":"**Curator** is a technical name for Arma 3 Zeus game master system. Every involved scripting command, event handler or class name contains the name.\nThe reason for it is to have a generic name which can be passed from project to project without any associations."},{"heading":"Setup","level":3,"markdown":"The central piece of every curator is Game Master module, otherwise referred to as Curator Logic. It stores every setting, like editing areas, available objects or their costs.\n\nYou can find the module in **Systems (F5) > Zeus > Game Master**\n\nIn module arguments, can set the curator unit (either specific unit, player with given UID or server admin) and that's all you need to add game master to your mission.\nWithout any further settings, all objects will be available for free and whole map will be editable.\n\nThere can be multiple modules present in a mission, each with its own settings. As a result, you can have for example two competing curators, or a group of allied curators, each with different abilities.\n\nIn every examples on this page, we'll call the module *myCurator*.\n\n> [!NOTE]\n> - Detailed module descriptions are available in the game after clicking on SHOW INFO button while editing a module.\n> - Function descriptions can be accessed in game using Functions Viewer.\n> - All curator related scripting commands can be found in the Curator command group."},{"heading":"Costs","level":3,"markdown":"Mission designer can assign cost to every object curator can interact with. The cost is applied when performing actions like placing, editing or deleting.\nIt affects curator's resources - **points** - which are in range from 0 (no points) to 1 (full points; can't be larger than this value).\nThe cost can be both negative and positive, so some actions can actually add points (e.g., deleting).\nPoints can be adjusted by addCuratorPoints and returned using curatorPoints, or you can use *Manage Resources* module.\n\nCosts for each entity type are calculated differently:\n- Object costs are defined in the event handler.\n- Modules are perceived as normal objects and are also defined in the handler.\n- Waypoint costs are set by setCuratorWaypointCost command.\n- Markers are always free."},{"heading":"Assigning","level":4,"markdown":""},{"heading":"Manual","level":5,"markdown":"You can assign individual cost for every object in the game using CuratorObjectRegistered event handler.\nIt's executed when player enters curator interface, so individual values cannot be changed on the fly.\nHowever, you can still tweak costs using action coefficients and available objects by unlocking addons.\n\n```sqf\nmyCurator addEventHandler [\"CuratorObjectRegistered\", { /* code here, see below */ }];\n```\n\nArguments passed into the handler are:\n- curator: Object\n- input: Array of Strings - all CfgVehicles classes\n\nExpected returned value is an Array of Arrays of the same size as the input array, with each item belonging to a class with the same array index. Missing or incorrect values will be replaced by default *[true,0,0]*.\n- Input: `[string1, string2, string3, ... classN]`\n- Output: `[array1, array2, array3, ... arrayN]`\n**Example**:\n- Input (3 classes): `[\"B_Soldier_F\", \"B_MRAP_01_F\", \"ModuleLightning_F\"]`\n- Output (3 arrays with settings): `[[true, 0.1], [true, 0.5, 0.6], [false, 0, 0]]`\n\nEvery item in the array is in the following format:\n [show, cost, (costWithCrew)]\n- show: Boolean - true to let the object appear in the CREATE list, false to hide it (costs will still be accepted if an object of the type is already present in the mission and made editable)\n- cost: Number - cost of the object\n- costWithCrew (Optional): Number - cost of the object with crew in it (affects only vehicles). When undefined, normal cost is used.\n\n**Example of the whole event handler:**\n\n```sqf\nmyCurator addEventHandler [\n    \"CuratorObjectRegistered\",\n    {\n        _classes = _this select 1;\n        _costs = [];\n        {\n            _cost = if (_x isKindOf \"Man\") then {[true,0.1]} else { [false, 0] }; // show only objects of type \"Man\", hide everything else\n            _costs pushBack _cost;\n        } forEach _classes; // go through all classes and assign cost for each of them\n        _costs\n    }\n];\n```\n\nAlternatively, you can set cost of specific objects by BIS_fnc_curatorObjectRegistered, with crew costs calculated automatically based on vehicle cost + cost of all crew members.\n- When the function is executed multiple times, results are combined together.\n  - Example:\n    - **Show** value of an object has to be true in all instances (e.g., one false will hide the object)\n    - **Cost** values are multiplied together (e.g., one 0 will set the cost to 0)"},{"heading":"Using Cost Tables","level":5,"markdown":"There's a scripted function which will export all objects from specified addons into spreadsheet format, where you can define individual costs and see additional data, like how many objects can be build at one or how long will it take to \"recharge\" points until the object is available. The table also automatically calculates costs of vehicles with crew and of whole groups. As such, it is invaluable tool for balancing curator missions.\n\nSteps how to create the table:\n1. Call BIS_fnc_exportCuratorCostTable to generate the table based on given addons into clipboard\n**Example:** `[\"A3_Characters_F_BLUFOR\", \"A3_Soft_F_MRAP_01\"], \"ods\"] spawn BIS_fnc_exportCuratorCostTable;`\n1. Run OpenOffice Calc (or Microsoft Excel; use \"xls\" as a second param when calling the functions, as both programs are using different formula formatting)\n1. Paste the generated text into the spreadsheet\n\nNow when the table is generated, you can assign specific costs to each objects and watch how it affects vehicles and groups involving the object./\n- Class names in the second column leads to Arma 3 Assets page with further details, like weapons or magazines the object can carry.\n- Display names in the third column are links directly to object preview images.\n\nWhen finished, export the result into the game by following these steps:\n1. Scroll down to \"Export\" field\n1. Copy all cells between *// Generated by BIS_fnc_exportCuratorCostTable* and the document end.\n**Example:**\n\n```sqf\n// Generated by BIS_fnc_exportCuratorCostTable\n// [[\"A3_Characters_F_BLUFOR\",\"A3_Soft_F_MRAP_01\"],\"ods\"] call BIS_fnc_exportCuratorCostTable;\n_BLUFOR_A3_Characters_F_BLUFOR = ['B_Soldier_GL_F',1,'B_soldier_AR_F',1,'B_Soldier_TL_F',1,'B_soldier_LAT_F',1,,0];\n_BLUFOR_A3_Soft_F_MRAP_01 = ['B_MRAP_01_F',3,,0];\n_BLUFOR = _BLUFOR_A3_Characters_F_BLUFOR + _BLUFOR_A3_Soft_F_MRAP_01 + [];\n```\n\n1. Import the result in the game again using BIS_fnc_curatorObjectRegisteredTable\n**Example:**\n\n```sqf\n[myCurator,_BLUFOR] call BIS_fnc_curatorObjectRegisteredTable;\n```"},{"heading":"Action Coefficients","level":4,"markdown":"Once you assigned cost to every object, you can now use it for every action curator can perform.\n\n```sqf\nmyCurator setCuratorCoef [\"place\", -0.2];\n```\n\nIf some object, for example BLUFOR soldier \"B_Soldier_F\" from the previous example, will have assigned cost 0.1, cost for placing will be:\n\n*0.1 * -0.2 = -0.02*\n\nIf curator have full points (value is 1), it means he can build 50 BLUFOR soldiers (*-1 * -0.02 = 50*). While individual object costs cannot be changed on the fly, coefficient can be easily used to tweak all costs.\n\nAvailable actions are:\n- \"place\"\n- \"edit\"\n- \"delete\"\n- \"destroy\"\n- \"group\"\n- \"synchronize\"\n\nAdditionally, while action can be disabled by assigning large negative coefficient, e.g., -10000. Trying to perform the action will then result in onscreen warning for curator.\n\nCoefficients can be also assigned in *Set Editing Costs* module."},{"heading":"Unlocking Addons","level":3,"markdown":"You can set which objects will be available curator by toggling specific addons. This can be done on the fly, and it is primary way how to unlock content for curator during a mission.\n\nSee Arma 3 assets to check which objects belongs to which addon, or use unitAddons to get addons of specific object class.\n\n> [!NOTE]\n> Only activated addons can be added (i.e., addons preloaded by the mission).\n> All official addons are activated by default, but unofficial ones are activated only when an object contained in such addon is present in the mission.\n> If that's not the case, you can use activateAddons or BIS_fnc_activateAddons to activate them. This is however possible only at the mission start - on the fly activation is not possible.\n\nInitial addons can be adjusted in *Game Master* module attributes, with available values being:\n- **All official addons** - default state, includes all activeted addons\n- **Addons present in the mission** - only addons of objects present in the mission upon mission start. E.g., if you inserted only BLUFOR soldiers and MRAPs in the mission, addons will be [\"A3_Characters_F_BLUFOR\",\"A3_Soft_F_MRAP_01\"]\n- **None** - no addons are enabled by the module, mission designer has to add them manually.\n\nDuring the missions, use *Manage Addons* module or scripting commands to toggle addons:\n- addCuratorAddons\n- removeCuratorAddons\n- removeAllCuratorAddons\n- curatorAddons\n\n**Example:**\n\n```sqf\nmyCurator addCuratorAddons [\"A3_Armor_F_AMV\", \"A3_Armor_F_Panther\"];\nmyCurator removeCuratorAddons [\"A3_Soft_F_MRAP_01\"];\n```"},{"heading":"Community Addons","level":4,"markdown":"Curator system relies on correct configuration of object. When you unlock an addon, it will in turn enable all objects defined in *units* array of *CfgPatches*.\nIf the addon author didn't do this, his objects won't be available.\n\n```cpp\nclass CfgPatches\n{\n    class TAG_MyAddon\n    {\n        units[] = { \"TAG_MyObject1\", \"TAG_MyObject2\" }; // here\n        weapons[] = {};\n        requiredVersion = 1;\n        requiredAddons[] = {};\n    };\n};\n```"},{"heading":"Editable Objects","level":3,"markdown":"By default, every object placed by curator is immediately made editable. Any other object can be added by *Add Editable Objects* module or using\nscripting commands:\n- addCuratorEditableObjects\n- removeCuratorEditableObjects\n- curatorEditableObjects\n\nEditable players are marked by a red color in the EDIT list and by red circle displayed over their icon. They cannot be moved, rotated, deleted or destroyed, but grouping, syncing and setting attributes works.\nEditable players can also ping their curator by pressing Zeus key (<kbd>Y</kbd> by default), which results in their name and icon flashing for a short moment.\nCurator can press <kbd>Space</kbd> to quickly move the camera to their location."},{"heading":"Editing Areas","level":3,"markdown":"Editing area is a zone in which curator can modify entities. It's used to limit curator into specific area, or restrict him from other (e.g., around players).\n\nIt can be set using *Add Editing Area* and *Restrict Editing Around Players* modules or by following scripting commands:\n- addCuratorEditingArea\n- removeCuratorEditingArea\n- removeAllCuratorEditingAreas\n- curatorEditingArea\n- setCuratorEditingAreaType\n- allowCuratorLogicIgnoreAreas\n\nAreas can be circle only, and can be composed together to build much larger area. Mission designer can set whether editing is allowed only inside them, or only outside them.\nFor performance reasons, it is not possible to define it per individual area.\n\nFor curator, the area is visualized by blue (during day) and green (during night) \"walls\" in the scene and by black icons in the map. Players can't see it.\n\n*Table showing which actions are permitted **outside** of the editing area for each entity type:*\n\n|  | Place | Edit | Delete | Destroy | Group | Synchronize |\n|---|---|---|---|---|---|---|\n| Objects | Restricted | Restricted | Restricted | Allowed | Allowed | Allowed |\n| Modules | Based on allowCuratorLogicIgnoreAreas | N/A | N/A | Allowed |  |  |\n| Markers | Allowed | Allowed | Allowed | N/A | N/A | N/A |\n| Waypoints | Allowed | Allowed | Allowed | N/A | N/A | N/A |"},{"heading":"Camera","level":3,"markdown":""},{"heading":"Camera Area","level":4,"markdown":"Camera area defines where can curator move with the camera. It's not visualized in any way, but reaching the border will result in camera \"sliding\" along it, so it can be felt.\nAs with editing areas, camera ones can also be grouped into larger chunks, and designer can set whether they camera can operate only inside or only outside of them.\nAdditionally, it is possible to set maximal camera altitude.\n\nUse *Add Camera Area* or following scripting commands to set the area:\n- addCuratorCameraArea\n- removeCuratorCameraArea\n- removeAllCuratorCameraAreas\n- curatorCameraArea\n- setCuratorCameraAreaCeiling"},{"heading":"Camera Position","level":4,"markdown":"You can teleport curator camera to specific position using *Set Camera Positon*.\nThe module can be also use to set default camera position after opening curator interface, when *Use as default* module attribute is set to *Enabled*.\n\nIn scripts, you can move curatorCamera around like any other object. However, most camera commands won't work on it.\nThe camera is local to the curator owner, so any changes to it has to be executed locally as well.\n\n**Example:**\n\n```sqf\ncuratorCamera setPos [position player select 0, position player select 1, 30];\ncuratorCamera setVectorDirAndUp [[0, 1, -0.5], [0, 0, 1]];\n```\n\nYou can also call BIS_fnc_setCuratorCamera, which will also let you to transition the camera into desired position smoothly."},{"heading":"Attributes","level":3,"markdown":"Attributes are specific settings available after double-clicking on an entity.\n\nYou can set which attributes will be available for entities by *Set Attributes* modules or using BIS_fnc_setCuratorAttributes. By default, all attributes are shown. Modules are using custom attributes.\n\nAvailable attributes for each entity type are:\n- **Object / Player**\n  - Skill\n  - UnitPos\n  - Rank\n  - Damage\n  - Fuel\n  - Lock\n  - RespawnVehicle\n  - RespawnPosition\n  - Exec *(visible only when debug console is available)*\n- **Group**\n  - GroupID\n  - Behaviour\n  - Formation\n  - UnitPos\n- **Marker**\n  - Text\n  - Color\n- **Waypoint**\n  - Behaviour\n  - Formation"},{"heading":"Icons","level":3,"markdown":"Mission designer can show an icon visible only in curator interface\n- Use *Add Icon* module or BIS_fnc_addCuratorIcon and BIS_fnc_removeCuratorIcon to manage custom icons. Icon definition is the same as is used by drawIcon3D command\n- BIS_fnc_drawCuratorDeaths will show a skull icon on position where given unit died (useful for tracking where players are dying in PvP matches)\n- BIS_fnc_drawCuratorLocations shows names of nearby settlements, which can help with navigation on large terrains.\n- BIS_fnc_drawCuratorRespawnMarkers shows an icon on respawn markers"},{"heading":"Compositions","level":3,"markdown":"Since Arma 3 v2.06 is it possible to place custom compositions created in Eden Editor in Zeus.\nIn order to enable Zeus to spawn custom compositions *zeusCompositionScriptLevel* needs to be defined in Description.ext#zeusCompositionScriptLevel **or** Arma 3: Server Config File."},{"heading":"Notes","level":4,"markdown":"- Arma 3: Simple Objects are not supported. They will be placed as normal entities\n- Compositions that use non-whitelisted/non-loaded mods are not shown in the compositions list\n- Some objects cannot be edited after spawning (USS Liberty/Freedom ships), as they only create a dummy object, that then spawns the ship parts afterward\n- Mines are not \"supported\". You can place them but not edit/remove them after placing"},{"heading":"Shortcuts","level":4,"markdown":"- Press <kbd>Ctrl</kbd> to make the composition follow the terrain\n- Press <kbd>Alt</kbd> to place the composition at its original location where it was created in Eden Editor"},{"heading":"Misc","level":3,"markdown":"- [Zeus logo PSD source file](http://temp.moricky.com/zeusLogo.psd)\n\nArma 3 Editing"}],"categories":["Arma 3: Editing"],"groups":["Scripting"]},{"name":"Arma 3: Event Handlers","title":"Arma 3: Event Handlers","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Event_Handlers","revid":378964,"updated":"2026-09-07T08:29:27Z","aliases":["ArmA 3: Event Handlers"],"markdown":"An Event Handler (abbreviated to EH) allows you to automatically monitor and then execute custom code upon particular events being triggered.\n\nSee also Event Scripts for special event triggered scripts.\n\n### Basic Event Handlers\n\nThe object-based Event Handler is always executed on the computer where it was added.\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers\n\n#### AmmoExplodedNear (Arma 3 v2.22)\n\nTriggers when ammo explodes in some damage range of the object. This EH triggers where the ammo is 'real', similar to HitPart.\n\n```sqf\nthis addEventHandler [\"AmmoExplodedNear\", {\n    params [\"_object\", \"_shot\", \"_position\", \"_velocity\", \"_ammo\", \"_explosive\", \"_indirectHit\", \"_invArmor\", \"_damage\"];\n}];\n```\n\n- object: Object - object the event handler is assigned to\n- shot: Object - shot that has exploded\n- position: Array - world position of the shot\n- velocity: Array - world velocity of the shot\n- ammmo: String - config ammo class name\n- explosive: Number - config value for 'explosive'\n- indirectHit: Number - config value for 'indirectHit'\n- invArmor: Number - calculated inverse armor from config value\n- damage: Number - a rough estimate of the potential damage to the center of the object based on config values and the distance\n\n#### AnimChanged\n\nGlobal Argument\n\nTriggered every time a new animation is started. This EH is only triggered for the 1st animation state in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimChanged\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that is started\n\n#### AnimDone\n\nGlobal Argument\n\nTriggered every time an animation is finished. Triggered for all animation states in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimDone\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that has been finished\n\n#### AnimStateChanged\n\nGlobal Argument\n\nTriggered every time an animation state changes. Triggered for all animation states in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimStateChanged\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that has been started\n\n#### Assembled (Arma 3 v2.18)\n\nLocal Argument\n\nTriggers when weapon that is moved out of the world is assembled again. EH should be attached to the entity.\n\n```sqf\nthis addEventHandler [\"Assembled\", {\n    params [\"_entity\", \"_unit\", \"_primaryBag\", \"_secondaryBag\"];\n}];\n```\n\n- entity: Object - weapon this event is assigned to\n- unit: Object - person who assembled the weapon\n- primaryBag: Object - first backpack object which was entity disassembled into (just before it is deleted)\n- secondaryBag: Object - second backpack object which was entity disassembled into (just before it is deleted)\n\n#### Attached (Arma 3 v2.18)\n\nTriggered after an object has been attached to another object (see attachTo).\n\n```sqf\nthis addEventHandler [\"Attached\", {\n    params [\"_attachedObj\", \"_parentObj\", \"_isReattach\", \"_offset\", \"_memoryPointIndex\", \"_followBoneRotation\"];\n}];\n```\n\n- attachedObj: Object\n- parentObj: Object\n- isReattach: Boolean - true if `attachedObj` was already attached to `parentObj`, e.g. if only the offset was changed\n- offset: Array format PositionRelative\n- memoryPointIndex: Number\n- followBoneRotation: Boolean\n\n#### CargoLoaded (Arma 3 v2.06)\n\nGlobal Argument\n\nTriggered when a vehicle is loaded into another vehicle (ViV).\n\nIt can be added to either the transport vehicle, or the cargo vehicle, and will fire for both cases.\n\n```sqf\nthis addEventHandler [\"CargoLoaded\", {\n    params [\"_parentVehicle\", \"_cargoVehicle\"];\n}];\n```\n\n- parentVehicle: Object - the transport (parent) vehicle\n- cargoVehicle: Object - the cargo (child) vehicle\n\n#### CargoUnloaded (Arma 3 v2.06)\n\nGlobal Argument\n\nTriggered when a vehicle is unloaded from another vehicle (ViV).\n\nIt can be added to either the transport vehicle, or the cargo vehicle, and will fire for both cases.\n\n```sqf\nthis addEventHandler [\"CargoUnloaded\", {\n    params [\"_parentVehicle\", \"_cargoVehicle\"];\n}];\n```\n\n- parentVehicle: Object - the transport (parent) vehicle\n- cargoVehicle: Object - the cargo (child) vehicle\n\n#### ContainerClosed (Arma 3 v1.32)\n\nGlobal Argument\n\nTriggers when player finished accessing cargo container.\nThis event handler is similar to InventoryClosed EH, but needs to be assigned to the container rather than the player.\n\n**Note:** will trigger only for the unit opening container.\n\n```sqf\nthis addEventHandler [\"ContainerClosed\", {\n    params [\"_container\", \"_unit\"];\n}];\n```\n\n- container: Object - cargo container.\n- unit: Object - unit who accessed the container\n\n#### ContainerOpened (Arma 3 v1.32)\n\nGlobal Argument\n\nTriggers when cargo container is accessed by player.\nThis event handler is similar to InventoryOpened EH, but needs to be assigned to the container rather than the player and cannot be overridden.\n\n**Note:** will trigger only for the unit opening container.\n\n```sqf\nthis addEventHandler [\"ContainerOpened\", {\n    params [\"_container\", \"_unit\"];\n}];\n```\n\n- container: Object - cargo container\n- unit: Object - unit who accessed the container\n\n#### ControlsShifted (Arma 3 v1.00)\n\nGlobal ArgumentLocal Effect\n\nTriggers when control of a vehicle is shifted (pilot->co-pilot, co-pilot->pilot), usually when user performs an action such as TakeVehicleControl, SuspendVehicleControl, UnlockVehicleControl, LockVehicleControl, or when enableCopilot command is used. This event handler will always fire on the PC where action is triggered as well as where the vehicle is local at the time. When control of the vehicle is shifted, the locality of the vehicle changes to the locality of the new controller. For example, if helicopter is local to the server and co-pilot takes controls, the helicopter changes locality to co-pilot PC.\nThis means that if \"ControlsShifted\" EH was added on both server and client, \"Take Controls\" action will trigger EH on both, client and server PC, but subsequent co-pilot \"Release Controls\" action will trigger only on co-pilot's PC, because vehicle will be local to co-pilot at this point. There is also a slightly better mission version of ControlsShifted event handler.\n\n```sqf\nthis addEventHandler [\"ControlsShifted\", {\n    params [\"_vehicle\", \"_activeCoPilot\", \"_oldController\"];\n}];\n```\n\n- vehicle: Object - vehicle which controls were shifted\n- activeCoPilot: Object - co-pilot unit which controls vehicle after this event. objNull if co-pilot is not controlling the vehicle\n- oldController: Object - unit who controlled vehicle before this event\n\n#### Dammaged\n\nGlobal Argument\n\nTriggered when the unit is damaged. In ArmA works with all vehicles not only men like in OFP.\n\n**Notes:**\n- The typo is \"intentional\": it is Da**mm**aged with two \"m\".\n- If simultaneous damage occured (e.g. via grenade) EH might be triggered several times.\n- The Dammaged EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\n\n```sqf\nthis addEventHandler [\"Dammaged\", {\n    params [\"_unit\", \"_hitSelection\", \"_damage\", \"_hitPartIndex\", \"_hitPoint\", \"_shooter\", \"_projectile\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- hitSelection: String - name of the selection where the unit was damaged\n- damage: Number - resulting level of damage\n- Arma 3 v1.68 hitPartIndex: Number - hit index of the hit selection\n- Arma 3 v1.68 hitPoint: String - hit point Cfg name\n- Arma 3 v1.70 shooter: Object - shooter reference (to get instigator use getShotParents on projectile)\n- Arma 3 v1.70 projectile: Object - the projectile that caused damage\n\n#### Deleted (Entity) (Arma 3 v1.68)\n\nGlobal Argument\n\nTriggered just before the assigned entity is deleted.\n\n```sqf\nthis addEventHandler [\"Deleted\", {\n    params [\"_entity\"];\n}];\n```\n\n- entity: Object - object the event handler is assigned to\n\n#### Detached (Arma 3 v2.18)\n\nTriggered after an object has been detached from its parent object (see detach). Does not fire if the parent object was deleted.\n\n```sqf\nthis addEventHandler [\"Detached\", {\n    params [\"_attachedObj\", \"_parentObj\"];\n}];\n```\n\n- attachedObj: Object\n- parentObj: Object\n\n#### Disassembled (Arma 3 v2.00)\n\nLocal Argument\n\nTriggers when entity such as weapon/backpack gets disassembled. EH should be attached to the entity.\n\n```sqf\nthis addEventHandler [\"Disassembled\", {\n    params [\"_entity\", \"_primaryBag\", \"_secondaryBag\", \"_unit\"];\n}];\n```\n\n- entity: Object - weapon this event is assigned to (just before is is moved out of the world)\n- primaryBag: Object - first backpack object which was entity disassembled into\n- secondaryBag: Object - second backpack object which was entity disassembled into\n- Arma 3 v2.18 unit: Object - person who disassembled the weapon\n\n#### Engine\n\nGlobal Argument\n\nTriggered when the engine of the unit is turned on/off.\n\n> [!NOTE]\n> Although the event is global, on clients (non-server) and applied to remote vehicles, it will fire only if the vehicle is closer than about 6 km from the camera.\n> Should the vehicle be far away, it will fire as soon as the camera and vehicle are close enough together, alongside the isEngineOn flag change.\n\n```sqf\nthis addEventHandler [\"Engine\", {\n    params [\"_vehicle\", \"_engineState\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- engineState: Boolean - true when the engine is turned on, false when turned off\n\n#### EpeContact (Arma 3 v1.00)\n\nGlobal Argument\n\nTriggered when object collision (PhysX) is in progress.\n\n```sqf\nthis addEventHandler [\"EpeContact\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\", \"_reactVect\", \"_worldPos\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- selection1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- selection2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision\n- Arma 3 v2.12 reactVect: Array - impact reaction force vector\n- Arma 3 v2.12 worldPos: PositionWorld - point of impact in world coordinates\n\n#### EpeContactEnd (Arma 3 v1.00)\n\nGlobal Argument\n\nTriggered when object collision (PhysX) ends.\n\n```sqf\nthis addEventHandler [\"EpeContactEnd\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- selection1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- selection2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision\n\n#### EpeContactStart (Arma 3 v1.00)\n\nGlobal Argument\n\nTriggered when object collision (PhysX) starts.\n\n```sqf\nthis addEventHandler [\"EpeContactStart\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\", \"_reactForce\", \"_worldPos\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- select1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- select2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision\n- Arma 3 v2.12 reactForce: Array - impact reaction force vector\n- Arma 3 v2.12 worldPos: PositionWorld - point of impact in world coordinates\n\n#### Explosion (Arma 3 v0.76)\n\nGlobal Argument\n\nTriggered when a vehicle or unit is damaged by a nearby explosion.\nIt can be assigned to a remote unit or vehicle but will only fire on the PC where EH is added and explosion is local, i.e. it really needs to be added on every PC and JIP and will fire only where the explosion is originated.\n\n```sqf\nthis addEventHandler [\"Explosion\", {\n    params [\"_vehicle\", \"_damage\", \"_explosionSource\"];\n}];\n```\n\n- vehicle: Object - object the event handler is assigned to\n- damage: Number - damage inflicted to the object\n- Arma 3 v2.10 explosionSource: Object - the exploding object (NOT the shooter) - may be objNull in some cases\n\n> [!NOTE]\n> This event will fire even for tiniest of explosion damage (which appears as 0 damage argument), while #HitPart (Entity) could ignore such damage and not fire.\n> Example of such event would be a tank firing AP round and hitting ground a meter away from the vehicle, it does not produce an explosion yet its indirectHit could still cause tiny amount of damage to weak hit points (car wheels, headlights, etc.).\n> In such case you might not get any #HitPart (Entity) event fires, get some #HandleDamage events if target is local, and get this Explosion event.\n\n#### Fired\n\nGlobal Argument\n\nTriggered when the unit fires a weapon.\n\nThis EH will not trigger if a unit fires out of a vehicle. For those cases an EH has to be attached to that particular vehicle.\nWhen \"Manual Fire\" is used, the *gunner* is objNull if gunner is not present or the *gunner* is not the one who fires.\nTo check if \"Manual Fire\" is on, use isManualFire. The actual shot instigator could be retrieved with getShotParents command.\n\n> [!WARNING]\n> **Special multiplayer behaviour:** When added to a remote unit or vehicle, this EH will only fire if said entity is within range of the camera.\n> That range is determined by the fired ammo's highest visibleFire and audibleFire config value.\n> In case of units, muzzle attachment coefficients are applied too.\n\n```sqf\nthis addEventHandler [\"Fired\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_magazine\", \"_projectile\", \"_gunner\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- magazine: String - magazine name which was used\n- projectile: Object - object of the projectile that was shot out\n- Arma 3 v1.66 gunner: Object - gunner whose weapons are firing.\n\n#### FiredMan (Arma 3 v1.66)\n\nGlobal Argument\n\nTriggered when the unit fires a weapon. This EH must be attached to a soldier and unlike with \"Fired\" EH, it will fire regardless of whether the soldier is on foot or firing vehicle weapon.\nFor remoteControled unit use \"Fired\" EH instead.\n\n> [!WARNING]\n> **Special multiplayer behaviour:** When added to a remote unit or vehicle, this EH will only fire if said entity is within range of the camera.\n> That range is determined by the fired ammo's highest visibleFire and audibleFire config value.\n> In case of units, muzzle attachment coefficients are applied too.\n\n```sqf\nthis addEventHandler [\"FiredMan\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_magazine\", \"_projectile\", \"_vehicle\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to (the instigator)\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- magazine: String - magazine name which was used\n- projectile: Object - object of the projectile that was shot out\n- vehicle: Object - vehicle, if weapon is vehicle weapon, otherwise objNull\n\n#### FiredNear\n\nGlobal Argument\n\nTriggered when a weapon is fired somewhere *near* the unit or vehicle. It is also triggered if the unit itself is firing.\n\nWhen \"Manual Fire\" is used, the *gunner* is objNull if gunner is not present or the *gunner* is not the one who fires.\nTo check if \"Manual Fire\" is on, use isManualFire. The actual shot instigator can be retrieved with getShotParents command.\n\nArma 3 v1.30 Works with thrown weapons (using the \"Throw\" weapon) like grenades.\n\n```sqf\nthis addEventHandler [\"FiredNear\", {\n    params [\"_unit\", \"_firer\", \"_distance\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_gunner\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- firer: Object - object which fires a weapon near the unit\n- distance: Number - distance in meters between the *unit* and *firer* (max. distance ~69m)\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- Arma 3 v1.66 gunner: Object - gunner, whose weapons are fired\n\n#### Fuel\n\nGlobal Argument\n\nTriggered when the vehicle's fuel status changes between non-empty and empty or between empty and non-empty.\n\n```sqf\nthis addEventHandler [\"Fuel\", {\n    params [\"_vehicle\", \"_hasFuel\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- hasFuel: Boolean - false when has no fuel, true when has some fuel\n\n#### Gear\n\nGlobal Argument\n\nTriggered when the unit lowers/retracts the landing gear, whether it is a helicopter or a plane.\nAlso triggered for helicopters in landing mode, regardless if they have retractable gear or not.\n\n> [!NOTE]\n> Not to be confused with *InventoryOpened* and *InventoryClosed* events, *Gear* fires when the landing gear state on an aircraft has changed.\n\n```sqf\nthis addEventHandler [\"Gear\", {\n    params [\"_vehicle\", \"_gearState\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- gearState: Boolean - true when the gear is lowered, false when retracted\n\n#### GestureChanged (Arma 3 v2.06)\n\nGlobal Argument\n\nTriggered every time a new gesture is played.\n\n```sqf\nthis addEventHandler [\"GestureChanged\", {\n    params [\"_unit\", \"_gesture\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- gesture: String - name of the gesture that has started playing\n\n#### GestureDone (Arma 3 v2.06)\n\nGlobal Argument\n\nTriggered every time a gesture is finished.\n\n```sqf\nthis addEventHandler [\"GestureDone\", {\n    params [\"_unit\", \"_gesture\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- gesture: String - name of the gesture that has been finished\n\n#### GetIn\n\nGlobal Argument\n\nTriggers when a unit enters the vehicle to which this EH has been added. This EH is triggered by moveInXXXX commands and \"GetInXXXX\" actions, but not upon a seat change within the same vehicle.\n\nIn vehicles with multi-turret setup, entering any turret will show \"gunner\" for position.\n\n```sqf\nthis addEventHandler [\"GetIn\", {\n    params [\"_vehicle\", \"_role\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- unit: Object - unit that entered the vehicle\n- Arma 3 v1.36 turret: Array - turret path\n\n#### GetInMan (Arma 3 v1.58)\n\nGlobal Argument\n\nTriggers when a unit enters a vehicle. Similar to \"GetIn\" but must be assigned to a unit and not vehicle.\nPersistent on respawn if assigned where unit was local. This EH is triggered by moveInXXXX commands and \"GetInXXXX\" actions.\n\n```sqf\nthis addEventHandler [\"GetInMan\", {\n    params [\"_unit\", \"_role\", \"_vehicle\", \"_turret\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- vehicle: Object - vehicle the unit entered\n- turret: Array - turret path\n\n#### GetOut\n\nGlobal Argument\n\nTriggers when a unit gets out from the vehicle to which this EH has been added.\nThis EH is triggered by moveOut, \"GetOut\" & \"Eject\" actions, if an alive crew member disconnects or is deleted, but not upon a seat change within the same vehicle.\n\n```sqf\nthis addEventHandler [\"GetOut\", {\n    params [\"_vehicle\", \"_role\", \"_unit\", \"_turret\", \"_isEject\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- unit: Object - unit that left the vehicle\n- Arma 3 v1.36 turret: Array - turret path\n- Arma 3 v2.14 isEject: Boolean - true if unit used 'Eject' action\n\n#### GetOutMan (Arma 3 v1.58)\n\nGlobal Argument\n\nTriggers when a unit exits a vehicle. Similar to \"GetOut\" but must be assigned to a unit and not vehicle.\nPersistent on respawn if assigned where unit was local. This EH is triggered by moveOut and \"GetOut\" & \"Eject\" actions.\n\n```sqf\nthis addEventHandler [\"GetOutMan\", {\n    params [\"_unit\", \"_role\", \"_vehicle\", \"_turret\", \"_isEject\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- vehicle: Object - vehicle that the unit left\n- turret: Array - turret path\n- Arma 3 v2.14 isEject: Boolean - true if unit used 'Eject' action\n\n#### HandleDamage\n\nGlobal Argument\n\nTriggers when the unit is damaged and fires for each damaged selection separately\nWorks with all vehicles.\nThis EH can accept a remote unit as argument however it will only fire when the unit is local to the PC this event handler was added on.\nFor example, you can add this event handler to one particular vehicle on every PC.\nWhen this vehicle gets hit, only EH on PC where the vehicle is currently local will fire.\n\nIf the provided code returns a numeric value, this value will overwrite the default damage of given selection after processing.\nIf no value is returned, the default damage processing will be done - this allows for safe stacking of this event handler.\nOnly the return value of the last added \"HandleDamage\" EH is considered.\n\n> [!IMPORTANT]\n> A return value of 0 will make the unit **invulnerable** if damage is not scripted in other ways (i.e using setDamage and/or setHit for additional damage handling).\n> The return value is the hit zone's **absolute damage value**, **not** the damage to be *added* to it.\n\n**Notes:**\n- Multiple \"HandleDamage\" EHs can be added to the same unit. If multiple EHs return damage value for custom damage handling, only last returned value will be considered by the engine.\nEHs that do not return value can be safely added after EHs that do return value.\n- You can save the last event as timestamp (diag_tickTime) onto the unit, as well as the current health of the unit/its selections, with setVariable and query it on each \"HandleDamage\" event with getVariable to define a system how to handle the \"HandleDamage\" event.\n- \"HandleDamage\" will continue to trigger even if the unit is already dead.\n- \"HandleDamage\" is persistent. If you add it to the player object, it will continue to exist after player respawned.\n- \"HandleDamage\" can trigger \"twice\" per damage event. Once for direct damage, once for indirect damage (explosive damage). This can happen even in the same frame, but is unlikely.\n- Use setMissionOptions to filter out no damage calls or fake head hit.\n\nAdditional [Celery's explanation (Updated by ShadowRanger for Arma 3)](https://forums.bistudio.com/forums/topic/205515-handledamage-event-handler-explained/).\n\n```sqf\nthis addEventHandler [\"HandleDamage\", {\n    params [\"_unit\", \"_selection\", \"_damage\", \"_source\", \"_projectile\", \"_hitPartIndex\", \"_instigator\", \"_hitPoint\", \"_directHit\", \"_context\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- selection: String - name of the selection where the unit was damaged.\n  - \"\" for overall structural damage\n  - \"?\" for unknown selections\n- damage: Number - resulting level of damage for the selection\n- source: Object - the source unit that caused the damage\n- projectile: String - classname of the projectile that caused inflicted the damage. (\"\" for unknown, such as fall damage)\n- Arma 3 v1.50 hitPartIndex: Number - hit part index of the hit point, -1 otherwise\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 hitPoint: String - hit point Cfg name\n- Arma 3 v2.12 directHit: Boolean - true for direct projectile damage, false for explosion splash damage and all other kinds of damage like fall damage, fire damage, collision damage, etc.\n- Arma 3 v2.16 context: Number - some additional context for the event:\n\n0 : TotalDamage - total damage adjusted before iteration through hitpoints\n\n1 : HitPoint - some hit point processed during iteration\n\n2 : LastHitPoint - the last hitpoint from iteration is processed\n\n3 : FakeHeadHit - head hit that is added/adjusted\n\n4 : TotalDamageBeforeBleeding - total damage is adjusted before calculating bleeding\n\n> [!NOTE]\n> Between an unknown version (confirmed in Arma 3 v1.70) until v1.78 HandleDamage event triggered for every selection of a vehicle, no matter if the section was damaged or not.\n\n#### HandleHeal\n\nGlobal Argument\n\nTriggered when unit starts healing process (player using heal action on self or other unit, scripted action or AI heals after being ordered or on its own).\nThis event handler must be added to the 'injured' (could be added to Init field in editor) and in multiplayer will trigger only on PC where 'healer' is local. If code returns anything but true, engine side healing follows, otherwise healing is aborted.\n\n> [!IMPORTANT]\n> When AI unit is ordered (or acts at own accord) to heal at a medical vehicle and the event handler returns true, the healing is canceled but AI will try again and again and again. The event handler in this case will fire every second until AI unit is healed by other means.\n\n**NOTE**: This Event Handler was broken before Arma 3 v2.18.\n\n```sqf\nthis addEventHandler [\"HandleHeal\", {\n    _this spawn {\n        params [\"_injured\", \"_healer\", \"_isMedic\", \"_atVehicle\", \"_action\"];\n        private _damage = damage _injured;\n        if (_injured == _healer) then\n        {\n            waitUntil { damage _injured != _damage };\n            if (damage _injured < _damage) then\n            {\n                _injured setDamage 0;\n            };\n        };\n    };\n}];\n```\n\n```sqf\nthis addEventHandler [\"HandleHeal\", {\n    params [\"_injured\", \"_healer\", \"_isMedic\", \"_atVehicle\", \"_action\"];\n}];\n```\n\n- injured: Object - unit EH is attached to\n- healer: Object - unit that does the healing (could be the same unit as 'injured')\n- isMedic: Boolean - true when healer is 'Medic'\n- Arma 3 v2.18 atVehicle: Object - when healing at medical vehicle, this is the vehicle\n- Arma 3 v2.18 action: String - the action that triggered the event handler, for example \"SoldierHealSelf\"\n\n#### HandleIdentity\n\nGlobal Argument\n\nTriggered whenever an entity is created. Can be used in scripts if EH is added immediately after unit is created in unscheduled environment.\nDoesn't trigger for editor placed units. Does not work in Multiplayer. If EH scope returns true, the default engine identity application is overridden.\n\n```sqf\nbob = group player createUnit [typeOf player, position player, [], 0, \"NONE\"];\nbob addEventHandler [\"HandleIdentity\", {\n    params [\"_unit\"];\n    hint str _unit;\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n\n#### HandleRating (Arma 3 v1.32)\n\nLocal Argument\n\nTriggered when engine adds rating to overall rating of the unit, usually after a kill or a friendly kill.\nIf EH code returns Number, this will override default engine behaviour and the resulting value added will be the one returned by EH code.\n\n```sqf\nthis addEventHandler [\"HandleRating\", {\n    params [\"_unit\", \"_rating\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- rating: Number - rating to be added\n\n#### HandleScore (Arma 3 v1.32)\n\nGlobal ArgumentServer Execution\n\nTriggered when engine adds score to overall score of the unit, usually after a kill.\nIf the EH code returns Nothing or true, the default engine scoreboard update (score, vehicle kills, infantry kills, etc) is applied, if it returns false, the engine update is cancelled. To add or modify score, use addScore and addScoreSide commands.\nFor remote units like players, the event does not persist after respawn, and must be re-added to the new unit.\n\n**Note:** MP only.\n\n```sqf\nthis addEventHandler [\"HandleScore\", {\n    params [\"_unit\", \"_object\", \"_score\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- object: Object - object for which score was awarded\n- score: Number - score to be added\n\n#### Hit\n\nLocal Argument\n\nTriggered when the unit is hit/damaged.\n\nIs *not* always triggered when unit is killed by a hit.\n\nMost of the time only the killed event handler is triggered when a unit dies from a hit.\n\nThe hit EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\n\nDoes not fire when a unit is set to allowDamage false.\n\n```sqf\nthis addEventHandler [\"Hit\", {\n    params [\"_unit\", \"_source\", \"_damage\", \"_instigator\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- source: Object - object that caused the damage – contains *unit* in case of collisions\n- damage: Number - level of damage caused by the hit\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n\n#### HitPart (Entity)\n\nGlobal Argument\n\nTriggered when the object it was added to gets damaged.\nIt returns the position and component that was hit on the object within a nested array, this is because the model may have more than one selection name for the hit component (i.e. a single piece of geometry can be simultaneously part of multiple, overlapping named selections).\n\nWhile you can add \"HitPart\" handler to a remote unit, the respective addEventHandler command must be executed on the shooter's PC and will only fire on shooter's PC as well.\nThe event will not fire if the shooter is not local, even if the target itself is local.\nAdditionally, if the unit gets damaged by any means other than ammunition or explosions, such as fall damage and burning, \"HitPart\" will not fire.\nBecause of this, this event handler is most suitable for when the shooter needs feedback on his shooting, such as target practicing or hitmarker creation.\n\nThis EH returns an array of arrays. Each sub-array contains data for the part that was hit as usually multiple parts are hit at the same time (see HitPart Sample). The structure of the sub-arrays is listed below.\n\n```sqf\nthis addEventHandler [\"HitPart\", {\n    {\n        _x params [\n            \"_target\", \"_shooter\", \"_projectile\", \"_position\", \"_velocity\",\n            \"_selection\", \"_ammo\", \"_vector\", \"_radius\", \"_surfaceType\",\n            \"_isDirect\", \"_instigator\"\n        ];\n    } forEach _this;\n}];\n```\n\n- target: Object - object that was damaged\n- shooter: Object - Unit or vehicle that inflicted the damage. If injured by a vehicle collision, the target itself is returned, or objNull in case of explosions. In case of explosives that were planted by someone (e.g. satchel charges), that unit is returned.\n- projectile: Object - object that was fired\n- position: Array format PositionASL - position the bullet impacted\n- velocity: Vector3D - 3D speed at which the bullet impacted\n- selection: Array - array of Strings with named selection of the object that were hit, in the FireGeometry LOD\n- ammo:\n  - Array in format [hitValue, indirectHitValue, indirectHitRange, explosiveDamage, ammoClassName] - If the damage was directly or indirectly inflicted by a projectile. Hit and damage values are derived from the projectile's CfgAmmo class, and do not match the actual damage inflicted, which is usually lower due to armor and other factors.\n  - Array in format [impulseValue, 0, 0, 0] - if the damage was inflicted by a vehicle collision\n- vector: Vector3D - Vector that is orthogonal (perpendicular) to the surface struck. For example, if a wall was hit, the vector would be pointing out of the wall at a 90 degree angle.\n- radius: Number - radius (size) of component hit\n- surfaceType: String - surface type struck\n- isDirect: Boolean - true if object was directly hit, false if it was hit by indirect / splash damage\n- Arma 3 v2.18 instigator: Object - shot instigator\n\n> [!NOTE]\n> See #HitPart (Projectile) for a similar event handler that is attached to the projectile instead of the entity.\n\n> [!NOTE]\n> This event does not fire when miniscule explosive damage is dealt to the target entity, but the Explosion event will still fire.\n\n#### IncomingMissile\n\nGlobal Argument\n\nTriggered when a unit fires a missile or rocket at the target. For projectiles fired by players this EH only triggers for guided missiles that have locked onto the target.\n\n```sqf\nthis addEventHandler [\"IncomingMissile\", {\n    params [\"_target\", \"_ammo\", \"_vehicle\", \"_instigator\", \"_missile\"];\n}];\n```\n\n- target: Object - object the event handler is assigned to\n- ammo: String - ammo type that was fired on the target\n- Arma 3 v1.42 vehicle: Object - vehicle that fired the weapon. In case of soldier, unit is returned\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v2.10 missile: Object - the incoming missile\n\n#### Init (Entity)\n\nGlobal Argument\n\nTriggered whenever an entity is created. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n> [!IMPORTANT]\n> It is recommended to use the #PostInit event handler instead of this one when setting entity textures (setObjectTexture, BIS_fnc_initVehicle etc) to avoid networking issues.\n\ne.g:\n\n```cpp\ninit = \"params ['_entity'];\";\n```\n\n```sqf\nparams [\"_entity\"];\n```\n\n- entity: Object - object the event handler is assigned to\n\n#### InventoryClosed (Arma 3 v1.22)\n\nGlobal Argument\n\nTriggered when the unit closes inventory. Said unit can be non-local when adding the EH, but **must** be local for the EH to trigger.\n\n```sqf\nthis addEventHandler [\"InventoryClosed\", {\n    params [\"_unit\", \"_container\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- container: Object - connected container or weaponholder\n\n```sqf\n// Delete dropped items when inventory closed\nplayer addEventHandler [\"InventoryClosed\", {\n    params [\"_unit\", \"_container\"];\n    if (_container isKindOf \"WeaponHolder\") then\n    {\n        deleteVehicle _container;\n    };\n}];\n```\n\n#### InventoryOpened (Arma 3 v1.22)\n\nGlobal Argument\n\nTriggered when unit opens inventory. Said unit can be non-local when adding the EH, but **must** be local for the EH to trigger. End EH main scope with true to override the opening of the inventory in case you wish to handle it yourself:\n\n```sqf\n// Create and open an ammo box when \"Inventory\" button is pressed\nplayer addEventHandler [\"InventoryOpened\", {\n    player removeAllEventHandlers \"InventoryOpened\";\n    _box = \"Box_NATO_Ammo_F\" createVehicle [0,0,0];\n    _box setPosASL (player modelToWorldVisualWorld [0,1.5,0.5]);\n    player action [\"Gear\", _box];\n    true; // <-- inventory override\n}];\n```\n\nTo return all nearby containers use nearSupplies command.\n\n```sqf\nthis addEventHandler [\"InventoryOpened\", {\n    params [\"_unit\", \"_primaryContainer\", \"_secondaryContainer\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- primaryContainer: Object - connected container or weaponholder\n- Arma 3 v1.66 secondaryContainer: Object - second connected container or weaponholder or objNull\n\n#### Killed\n\nLocal Argument\n\nTriggered when the unit is killed.\n\n```sqf\nthis addEventHandler [\"Killed\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\", \"_shot\", \"_real\"];\n}];\n```\n\n- unit: Object - the object the event handler is assigned to\n- killer: Object - the object that killed the unit. Contains the unit itself in case of collisions.\n- Arma 3 v1.66 instigator: Object - the person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n- Arma 3 v2.22 shot: Object - shot that caused damage\n- Arma 3 v2.22 real: Boolean - true when the shot was 'real' where the event handler triggered\n\n#### LandedStopped\n\nGlobal Argument\n\nTriggered when an AI pilot would get out usually. Not executed for player.\n\n```sqf\nthis addEventHandler [\"LandedStopped\", {\n    params [\"_plane\", \"_airportID\", \"_airportObject\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number - ID of the airport (-1 for anything else)\n- Arma 3 v2.12 airportObject: Object - airport object in the event of a Dynamic Airport, otherwise objNull\n\n#### LandedTouchDown\n\nGlobal Argument\n\nTriggered when a plane (AI or player) touches the ground.\n\n```sqf\nthis addEventHandler [\"LandedTouchDown\", {\n    params [\"_plane\", \"_airportID\", \"_airportObject\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number - ID of the airport (-1 for anything else)\n- Arma 3 v2.12 airportObject: Object - airport object in the event of a Dynamic Airport, otherwise objNull\n\n#### Landing (Arma 3 v1.70)\n\nGlobal Argument\n\nTriggered when an AI pilot (or auto-pilot) is preparing for landing. The exact moment of triggering coincides with lowering of the gear (\"Gear\" EH)\n\n```sqf\nthis addEventHandler [\"Landing\", {\n    params [\"_plane\", \"_airportID\", \"_isCarrier\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number or Object - ID of the airport or aircraft carrier object\n- isCarrier: Boolean - true if landing on aircraft carrier\n\n#### LandingCanceled (Arma 3 v1.70)\n\nGlobal Argument\n\nTriggered when AI pilot landing is cancelled (for example new order received to land elsewhere).\nThe exact moment of triggering coincides with retracting of the gear (\"Gear\" EH).\n\n**Note**: Does not trigger if player switches off auto-pilot. Canceled is spelled with one `L`\n\n```sqf\nthis addEventHandler [\"LandingCanceled\", {\n    params [\"_plane\", \"_airportID\", \"_isCarrier\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number or Object - ID of the airport or aircraft carrier object (-1 no airport)\n- isCarrier: Boolean - true if landing on aircraft carrier\n\n#### LaserTargetChanged (Arma 3 v2.22)\n\nTriggered when the laser target changes.\n\n```sqf\nthis addEventHandler [\"LaserTargetChanged\", {\n    params [\"_unit\", \"_laserTarget\", \"_designatedTarget\", \"_turretPath\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- laserTarget: Object - the laser target entity that got created at impact point\n- designatedTarget: Object - the object that is targeted by the laser\n- turretPath: Turret Path - the path to the turret that activated the laser. It is empty when the event is triggered by a unit\n\n#### LeaningChanged (Arma 3 v2.18)\n\nGlobal Argument\n\nTriggered when a soldier leaning factor is changed between -1 (extreme left), 0 (not leaning) and 1 (extreme right)\n\n```sqf\nthis addEventHandler [\"LeaningChanged\", {\n    params [\"_unit\", \"_newLeaning\", \"_oldLeaning\"];\n}];\n```\n\n- unit: Object - soldier\n- newLeaning: Number from -1 to 1\n- oldLeaning: Number from -1 to 1\n\n#### Local (Entity)\n\nGlobal Argument\n\nTriggers when locality of object in MP is changed. The event handler only triggers on the computers that are directly involved in change of locality.\nSo if EH is added to every computer on network, it will only trigger on 2 computers, on the computer that receives ownership of the object (new owner), in which case _this select 1 will be true,\nand on the computer from which ownership is transferred (old owner), in which case _this select 1 will be false.\n\n```sqf\nthis addEventHandler [\"Local\", {\n    params [\"_entity\", \"_isLocal\"];\n}];\n```\n\n- entity: Object - the object that changed locality\n- isLocal: Boolean - if the object is local on given computer\n\n#### MagazineReloading (Arma 3 v2.18)\n\nLocal Argument\n\nTriggers when reloading starts.\n\n```sqf\nthis addEventHandler [\"MagazineReloading\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_magazine\", \"_magazineClass\", \"_ammoCount\", \"_magazineID\", \"_magazineCreator\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got unloaded\n- muzzle: String - weapon's muzzle that got unloaded\n- magazine: Array - magazine info in format [magazineClass, ammoCount, magazineID, magazineCreator], where:\n  - magazineClass: String - class name of the magazine\n  - ammoCount: Number - amount of ammo in magazine\n  - magazineID: Number - global magazine id\n  - magazineCreator: Number - owner of the magazine creator\n\n#### MagazineUnloaded (Arma 3 v2.18)\n\nLocal Argument\n\nTriggers when a magazine is removed from a weapon manually or via script.\n\n```sqf\nthis addEventHandler [\"MagazineUnloaded\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_magazine\", \"_magazineClass\", \"_ammoCount\", \"_magazineID\", \"_magazineCreator\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got unloaded\n- muzzle: String - weapon's muzzle that got unloaded\n- magazine: Array - magazine info in format [magazineClass, ammoCount, magazineID, magazineCreator], where:\n  - magazineClass: String - class name of the magazine\n  - ammoCount: Number - amount of ammo in magazine\n  - magazineID: Number - global magazine id\n  - magazineCreator: Number - owner of the magazine creator\n\n#### OpticsModeChanged (Arma 3 v2.10)\n\nLocal Argument\n\nTriggers everytime a local unit changes optic mode. This could be either through the setOpticsMode command or by the player switching to the next optic mode using e.g <kbd>NUM /</kbd> or <kbd>Ctrl</kbd>+<kbd>RMB</kbd>.\n\n```sqf\nthis addEventHandler [\"OpticsModeChanged\", {\n    params [\"_unit\", \"_opticsClass\", \"_newMode\", \"_oldMode\", \"_isADS\"];\n}];\n```\n\n- unit: Object - the unit\n- opticsClass: String\n- newMode: String\n- oldMode: String\n- isADS: Boolean - if the new view is GUNNER\n\n#### OpticsSwitch (Arma 3 v2.10)\n\nLocal Argument\n\nTriggers at the start of the camera transition from GUNNER to INTERNAL/EXTERNAL and vice-versa.\nSo anytime the right mouse button is pressed and there is a GUNNER view available or are currently in it, this triggers.\nWorks in vehicles and FFV as well. See also cameraView.\n\n```sqf\nthis addEventHandler [\"OpticsSwitch\", {\n    params [\"_unit\", \"_isADS\"];\n}];\n```\n\n- unit: Object - the unit\n- isADS: Boolean - if the new view is GUNNER\n\n#### PathCalculated (Arma 3 v1.94)\n\nLocal Argument\n\nTriggers when a path has been calculated for the unit. Works for both agents and normal AI units.\n\nNote that paths to far destinations are typically calculated in segments.\nWhen the unit completes a segment, a new path is calculated and this is continued until the unit reaches its destination.\n\n```sqf\nthis addEventHandler [\"PathCalculated\", {\n    params [\"_unit\", \"_path\"];\n}];\n```\n\n- unit: Object - the unit/agent for which the path was calculated\n- path: Array - the array of positions representing the path (PositionASL)\n\n#### PeriscopeElevationChanged (Arma 3 v2.00)\n\nFires every frame during periscope elevation animation.\n\n```sqf\nthis addEventHandler [\"PeriscopeElevationChanged\", {\n    params [\"_vehicle\", \"_turret\", \"_elevation\", \"_direction\", \"_userIsBlocked\"];\n}];\n```\n\n- vehicle: Object - the vehicle this EH is assigned to\n- turret: Array - the turret which periscope is changing elevation\n- elevation: Number - current periscope elevation (changes with each simulation). See also periscopeElevation, elevatePeriscope\n- direction: Number - 1: moves up, 0: stopped, -1: moves down; when `direction` returns 0, this also means the event handler fired for the last time for this elevation.\n- userIsBlocked: Boolean - whether or not the user ability to override is blocked. See also periscopeElevation, elevatePeriscope\n\n#### PostInit (Arma 3 v2.06)\n\nGlobal Argument\n\nTriggered whenever an entity is created and initialized. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n> [!IMPORTANT]\n> It is recommended to use this event handler instead of the #Init one when setting entity textures (setObjectTexture, BIS_fnc_initVehicle etc) to avoid networking issues.\n\ne.g:\n\n```cpp\npostInit = \"params ['_entity'];\";\n```\n\n```cpp\npostinit = \"params ['_entity']; if (local _entity) then { [_entity, '', [], false] call BIS_fnc_initVehicle };\";\n```\n\n```sqf\nparams [\"_entity\"];\n```\n\n- entity: Object - object the event handler is assigned to\n\n#### PostReset\n\n**Obsolete** - triggers after PP effects have been reset by the engine.\n\n#### Put (Arma 3 v0.56)\n\nGlobal Argument\n\nTriggers when a unit puts an item in a container.\n\nArma 3 v2.14 This event handler can be added to a container.\n\n```sqf\nthis addEventHandler [\"Put\", {\n    params [\"_unit\", \"_container\", \"_item\"];\n}];\n```\n\n- unit: Object - unit who put the item in the container\n- container: Object - the container into which the item was placed (vehicle, box, etc.)\n- item: String - the class name of the moved item\n\n> [!NOTE]\n> This EH could also trigger when unit replaces magazine in weapon with another magazine from unit containers (uniform, vest, backpack) during reload.\n\n#### PylonChanged (Arma 3 v2.20)\n\nLocal Argument\n\nTriggers when an aircraft's pylon changes magazine type:\n\n```sqf\nvehicle player addEventHandler [\"PylonChanged\", {\n    params [\"_vehicle\", \"_pylonIndex\", \"_oldMagazine\", \"_newMagazine\"];\n}];\n```\n\n- vehicle: Object\n- pylonIndex: Number\n- oldMagazine: String\n- newMagazine: String\n\n> [!IMPORTANT]\n> This event generally triggers **twice** for a swap, first unload then load, e.g:\n>\n> ```sqf\n> // [myVehicle, 1, \"oldMagClass\", \"\"]\n> // [myVehicle, 1, \"\", \"newMagClass\"]\n> ```\n\n#### Reloaded (Arma 3 v1.58)\n\nLocal Argument\n\nTriggers once a weapon is reloaded with a new magazine. For more information, see Reloaded.\n\n```sqf\nthis addEventHandler [\"Reloaded\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_newMagazine\", \"_oldMagazine\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got reloaded\n- muzzle: String - weapon's muzzle that got reloaded\n- newMagazine: Array - new magazine info\n- oldMagazine: Array or Nothing - old magazine info\n\n#### Respawn\n\nLocal Argument\n\nTriggered when a unit respawns.\n\n```sqf\nthis addEventHandler [\"Respawn\", {\n    params [\"_unit\", \"_corpse\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- corpse: Object - object the event handler was assigned to, aka the corpse/unit player was previously controlling\n\n#### RopeAttach (Arma 3 v1.34)\n\nTriggered when a rope is attached to an object.\n\nIn the case of sling loading, this event handler must be assigned to the helicopter and will trigger for each attached rope.\n\n```sqf\nthis addEventHandler [\"RopeAttach\", {\n    params [\"_object1\", \"_rope\", \"_object2\"];\n}];\n```\n\n- object1: Object - object to which the event handler is assigned.\n- rope: Object - the rope being attached between object 1 and object 2.\n- object2: Object - the object that is being attached to object 1 via rope.\n\n#### RopeBreak (Arma 3 v1.34)\n\nTriggered when a rope is detached from an object.\n\nIn the case of sling loading, this event handler must be assigned to the helicopter and will trigger for each detached rope.\n\n```sqf\nthis addEventHandler [\"RopeBreak\", {\n    params [\"_object1\", \"_rope\", \"_object2\"];\n}];\n```\n\n- object1: Object - object to which the event handler is assigned.\n- rope: Object - the rope that connected object 1 and object 2.\n- object2: Object - the object that was connected to object 1 with a rope.\n\n#### SeatSwitched (Arma 3 v1.50)\n\nGlobal Argument\n\nTriggered when unit changes seat within vehicle. EH returns both units switching seats.\nIf switching seats with an empty seat, one of the returned units will be objNull.\nThe new position can be obtained with assignedVehicleRole.\nThis EH must be assigned to a vehicle.\n\n```sqf\nthis addEventHandler [\"SeatSwitched\", {\n    params [\"_vehicle\", \"_unit1\", \"_unit2\"];\n}];\n```\n\n- vehicle: Object - vehicle to which the event handler is assigned.\n- unit1: Object - unit switching seat.\n- unit2: Object - unit switching seat.\n\n#### SeatSwitchedMan (Arma 3 v1.58)\n\nGlobal Argument\n\nTriggered when unit changes seat within vehicle. EH returns both units switching seats.\nIf switching seats with an empty seat, one of the returned units will be objNull.\nThe new position can be obtained with assignedVehicleRole <unit>. This EH must be assigned to a unit and not a vehicle.\nThis EH is persistent and will be transferred to the new unit after respawn, but only if it was assigned where unit was local.\n\n```sqf\nthis addEventHandler [\"SeatSwitchedMan\", {\n    params [\"_unit1\", \"_unit2\", \"_vehicle\"];\n}];\n```\n\n- unit1: Object - unit switching seat.\n- unit2: Object - unit with which unit1 is switching seat.\n- vehicle: Object - vehicle where switching seats is taking place.\n\n#### SelectedActionChanged\n\nRTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality.\n\n#### SelectedActionPerformed\n\nRTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality.\n\n#### SelectedRotorLibActionChanged\n\nRTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedRotorLibActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality.\n\n#### SelectedRotorLibActionPerformed\n\nRTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedRotorLibActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Works only for key press combination <kbd>RCtrl</kbd>+<kbd>W</kbd>, which is the binding for helicopter wheels brakes.\n> It fires with or without Advanced Flight Model enabled. The enum number returned is 4 and 5, probably because the enum is structured like this:\n> - 0: HelicopterAutoTrimOn\n> - 1: HelicopterAutoTrimOff\n> - 2: HelicopterTrimOn\n> - 3: HelicopterTrimOff\n> - 4: WheelsBrakeOn\n> - 5: WheelsBrakeOff\n\n#### SlotItemChanged (Arma 3 v2.14)\n\nGlobal Argument\n\nTriggered when any of the following slots get assigned or unassigned: *Items* - Map, GPS, Radio, Watch, Compass, Helmet, Goggles, NVG; *Weapon* - Binoculars; *Containers* - Uniform, Vest, Backpack.\n\n```sqf\nthis addEventHandler [\"SlotItemChanged\", {\n    params [\"_unit\", \"_name\", \"_slot\", \"_assigned\", \"_weapon\"];\n}];\n```\n\n- unit: Object - unit EH assigned to.\n- name: String - name of the item/weapon/container (see getSlotItemName).\n- slot: Number - slot id (see getSlotItemName).\n- assigned: Boolean - true assign action, false unassign action.\n- Arma 3 v2.18 weapon: String - name of weapon in event that slot changed is a weapon attachment slot\n\n#### SoundPlayed (Arma 3 v0.56)\n\nLocal Argument\n\nTriggered when player is making noises when injured or fatigued for example. The number param passed to the EH code points to the sound origin:\n1. Breath\n1. Breath Injured\n1. Breath Scuba\n1. Injured\n1. Pulsation\n1. Hit Scream\n1. Burning\n1. Drowning\n1. Drown\n1. Gasping\n1. Stabilizing\n1. Healing\n1. Healing With Medikit\n1. Recovered\n1. Breath Held\n\n```sqf\nthis addEventHandler [\"SoundPlayed\", {\n    params [\"_unit\", \"_soundID\"];\n}];\n```\n\n- unit: Object - unit to which the event handler is assigned\n- soundID: Number - sound origin\n\n> [!NOTE]\n> Since Arma 3 v2.12 returning a Number from last added EH in range from 0 to 5 will alter the volume of played sound from mute to max volume.\n\n#### Suppressed (Arma 3 v2.02)\n\nLocal Argument\n\nTriggers when enemy projectile is passing by closer than defined suppression radius ammo value in config.\nCan be made to trigger for the same side if the side is set as enemy to itself (with setFriend). For more information see Arma 3: Suppression.\n\n```sqf\nthis addEventHandler [\"Suppressed\", {\n    params [\"_unit\", \"_distance\", \"_shooter\", \"_instigator\", \"_ammoObject\", \"_ammoClassName\", \"_ammoConfig\"];\n}];\n```\n\n- unit: Object - unit to which the event is assigned\n- distance: Number - distance of the projectile pass-by\n- shooter: Object - who (or what) fired - vehicle or drone\n- instigator: Object - who pressed the trigger. Instigator is different from the shooter when player is operator of UAV for example\n- ammoObject: Object - the ammunition itself\n- ammoClassName: String - the ammunition's classname\n- ammoConfig: Config - the ammunition's CfgAmmo config path\n\n#### Take (Arma 3 v0.56)\n\nGlobal Argument\n\nTriggers when a unit takes an item from a container.\n\nArma 3 v2.14 This event handler can be added to a container.\n\n```sqf\nthis addEventHandler [\"Take\", {\n    params [\"_unit\", \"_container\", \"_item\"];\n}];\n```\n\n- unit: Object - unit who took the item from the container\n- container: Object - the container from which the item was taken (vehicle, box, etc.)\n- item: String - the class name of the taken item\n\n> [!NOTE]\n> This EH could also trigger when unit replaces magazine in weapon with another magazine from unit containers (uniform, vest, backpack) during reload.\n\n#### TaskSetAsCurrent (Arma 3 v1.32)\n\nTriggers when player's current task changes\n\n```sqf\nthis addEventHandler [\"TaskSetAsCurrent\", {\n    params [\"_unit\", \"_task\"];\n}];\n```\n\n- unit: Object - the player to whom the event handler is assigned\n- task: Task - the new current task\n\n#### TurnIn (Arma 3 v1.66)\n\nTriggers when member of crew in a vehicle uses Turn In action\n\n```sqf\nthis addEventHandler [\"TurnIn\", {\n    params [\"_vehicle\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - the vehicle the event handler is assigned to\n- unit: Object - the unit performing the Turn In action\n- turret: Array - turret path\n\n#### TurnOut (Arma 3 v1.66)\n\nTriggers when member of crew in a vehicle uses Turn Out action\n\n```sqf\nthis addEventHandler [\"TurnOut\", {\n    params [\"_vehicle\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - the vehicle the event handler is assigned to\n- unit: Object - the unit performing the Turn Out action\n- turret: Array - turret path\n\n#### VisionModeChanged (Arma 3 v2.08)\n\nTriggers when the assigned vehicle/unit's vision mode has changed.\n\n```sqf\nplayer addEventHandler [\"VisionModeChanged\", {\n    params [\"_person\", \"_visionMode\", \"_TIindex\", \"_visionModePrev\", \"_TIindexPrev\", \"_vehicle\", \"_turret\"];\n}];\n```\n\n- person: Object - unit for whom the vision mode changes\n- visionMode: Number - vision mode index\n- TIindex: Number - thermal vision mode index; will return -1 when *visionMode* is not 2\n- visionModePrev: Number - last vision mode\n- TIindexPrev: Number - last TI mode; will return -1 when *visionModePrev* is not 2\n- vehicle: Object - if unit is in a vehicle or controlling a UAV, this will be the vehicle\n- turret: Array - turret path to the turret occupied by the unit, or [] if not on turret\n\n#### WeaponAssembled\n\nGlobal Argument\n\nTriggers when a weapon gets assembled. EH must be attached to the unit and not the weapon.\n\n```sqf\nthis addEventHandler [\"WeaponAssembled\", {\n    params [\"_unit\", \"_weapon\", \"_primaryBag\", \"_secondaryBag\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- weapon: Object - object of the assembled weapon\n- Arma 3 v2.18 primaryBag: Object - primary bag (just before it is deleted)\n- Arma 3 v2.18 secondaryBag: Object - secondary bag (just before it is deleted)\n\n#### WeaponChanged (Arma 3 v2.18)\n\nFires on weapon switch and firemode switch. Does not fire for player units inside vehicles (but does fire for vehicles with players in them).\n\nThe locality is unknown, but it is known that this EH behaves like currentWeapon, currentWeaponMode and currentMuzzle in terms of locality.\n\nArma 3 v2.22 Fires for \"Throw\" muzzle changes too.\n\n```sqf\nthis addEventHandler [\"WeaponChanged\", {\n    params [\"_object\", \"_oldWeapon\", \"_newWeapon\", \"_oldMode\", \"_newMode\", \"_oldMuzzle\", \"_newMuzzle\", \"_turretIndex\"];\n}];\n```\n\n- object: Object - the unit or vehicle the event handler is assigned to\n- oldWeapon: String - the class name of the previous weapon\n- newWeapon: String - the class name of the new weapon (same as currentWeapon)\n- oldMode: String - the previous weapon mode\n- newMode: String - the new weapon mode (same as currentWeaponMode)\n- oldMuzzle: String - the previous weapon muzzle\n- newMuzzle: String - the new weapon muzzle (same as currentMuzzle)\n- turretIndex: Array format Turret Path - the turret path, or empty array if `object` is not a transport vehicle\n\n#### WeaponDeployed (Arma 3 v1.44)\n\nGlobal Argument\n\nTriggers when the deployed state of a weapon or bipod changes.\n\n**Note:** A weapon cannot be rested and deployed at the same time.\n\n```sqf\nthis addEventHandler [\"WeaponDeployed\", {\n    params [\"_unit\", \"_isDeployed\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- isDeployed: Boolean - true if deployed\n\n#### WeaponDisassembled\n\nGlobal Argument\n\nTriggers when a weapon gets disassembled. EH must be attached to the unit and not the weapon.\n\n**Note:** As of Arma 3 v1.32, this event does not fire if the weapon is not local.\n\n```sqf\nthis addEventHandler [\"WeaponDisassembled\", {\n    params [\"_unit\", \"_primaryBag\", \"_secondaryBag\", \"_weapon\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- primaryBag: Object - first backpack object which was weapon disassembled into\n- secondaryBag: Object - second backpack object which was weapon disassembled into\n- Arma 3 v2.18 weapon: Object - disassembled weapon (just before it is moved out of the world)\n\n#### WeaponRested (Arma 3 v1.44)\n\nLocal Argument\n\nTriggers when weapon rested state changes (weapon near a surface that can provide weapon support).\n\n**Note:** A weapon cannot be rested and deployed at the same time.\n\n```sqf\nthis addEventHandler [\"WeaponRested\", {\n    params [\"_unit\", \"_isRested\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- isRested: Boolean - true if rested\n\n### Multiplayer Event Handlers\n\nGlobal object event handler, executed on every connected machine.\n\nCommands:\n- addMPEventHandler\n- removeMPEventHandler\n- removeAllMPEventHandlers\n\n> [!IMPORTANT]\n> A Multiplayer Event Handler is **not** saved in a save file and therefore will not be restored on load - use it accordingly.\n\n#### MPHit\n\nGlobal ArgumentGlobal Effect\n\nTriggered when the unit is hit/damaged. EH can be added on any machine and EH code will trigger globally on every connected client and server.\nThis EH is clever enough to be triggered globally only once even if added on all clients or a single client that is then disconnected, EH will still trigger globally only once.\n\nIs *not* always triggered when unit is killed by a hit.\nMost of the time only the killed event handler is triggered when a unit dies from a hit.\nThe hit EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\nCan also trigger several times for an explosion (direct and indirect damage). Does not fire when a unit is set to allowDamage false.\nHowever it will fire with \"HandleDamage\" EH added alongside stopping unit from taking damage (`unit addEventHandler [\"HandleDamage\", { 0 }];`.\nWill not trigger once the unit is dead.\n\n**Note:** call a function from the MPHit EH code space rather than defining the full code in there directly.\nThe reason is the code space will be transferred over network on each event activation - so keep the data as small as possible!\n\n```sqf\nthis addMPEventHandler [\"MPHit\", {\n    params [\"_unit\", \"_causedBy\", \"_damage\", \"_instigator\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n\n- causedBy: Object - object that caused the damage. Contains the unit itself in case of collisions.\n\n- damage: Number - level of damage caused by the hit\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n\n#### MPKilled\n\nGlobal ArgumentGlobal Effect\n\nTriggered when the unit is killed. EH can be added on any machine and EH code will trigger globally **on every connected client and server**.\nThis EH has a safeguard measure so that even if it's added on all clients or a single client that is then disconnected, EH will still trigger globally only once per client.\n\n```sqf\nthis addMPEventHandler [\"MPKilled\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- killer: Object - object that killed the unit. Contains the unit itself in case of collisions\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n\n#### MPRespawn\n\nGlobal ArgumentLocal Effect\n\nTriggered when a unit, it is assigned to, respawns. This EH does not work as one would expect MP EH should work like.\nIt is only triggered on one machine where the unit it was assigned to is local.\nThe only difference between **Respawn** and **MPRespawn** is that **MPRespawn** can be assigned from anywhere while **Respawn** requires the unit to be local.\n\nMPRespawn EH expects the EH code to return an array in Position format which will be used to place the respawned unit at the desired coordinates.\n\nFor example: `player addMPEventHandler [\"MPRespawn\", { [1234, 1234, 0] }];` will place player at [1234,1234,0] immediately on respawn.\n\n```sqf\nthis addMPEventHandler [\"MPRespawn\", {\n    params [\"_unit\", \"_corpse\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- corpse: Object - object the event handler was assigned to, aka the corpse/unit player was previously controlling.\n\n### Mission Event Handlers\n\nMission Event Handlers are specific EHs that are anchored to the running mission and automatically removed when mission is over.\n\nCommands:\n- addMissionEventHandler\n- removeMissionEventHandler\n\n> [!NOTE]\n> See Arma 3: Mission Event Handlers.\n\n### Curator Event Handlers (Arma 3 v1.16)\n\nLocal ArgumentLocal Effect\n\nArma 3: Curator Event Handlers are also added with the addEventHandler command. They are executed only where the curator is local - on the machine that is in control of it.\n\n> [!IMPORTANT]\n> These Event Handlers must be added to the curator object/module, **not** the player!\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers\n\n#### CuratorFeedbackMessage\n\nLocal Argument\n\nTriggered when curator attempts invalid action in curator interface.\n\nEach error has its own unique ID, recognized values are:\n\n- 003 - when trying to teleport camera outside of curatorCameraArea\n- 101 - trying to place an object when placing is disabled using setCuratorCoef \"place\"\n- 102 - trying to place an object which is too expensive (cost set in *curatorObjectRegistered* multiplied by setCuratorCoef \"place\" is larger than curatorPoints)\n- 103 - trying to place an object outside of curatorEditingArea\n- 104 - items of a placed composition were skipped / could not be placed (since Arma 3 v2.06)\n- 201 - trying to place a waypoint when waypoint placing is disabled\n- 202 - trying to place a waypoint which is too expensive (cost set by setCuratorWaypointCost multiplied by setCuratorCoef \"place\" is larger than curatorPoints)\n- 206 - trying to place a waypoint when no AI unit is selected\n- 301 - trying to move or rotate an entity when editing is disabled using setCuratorCoef \"edit\"\n- 302 - trying to move or rotate an entity when it is too expensive (entity cost multiplied by setCuratorCoef \"edit\" is larger than curatorPoints)\n- 303 - trying to move an entity outside of curatorEditingArea\n- 304 - trying to move or rotate an entity which is outside of curatorEditingArea\n- 307 - trying to move or rotate a player (players cannot be manipulated with)\n- 401 - trying to delete an entity when deleting is disabled using setCuratorCoef \"delete\"\n- 402 - trying to delete an entity which is too expensive (cost multiplied by setCuratorCoef \"delete\" is larger than curatorPoints)\n- 404 - trying to delete an entity which is outside of curatorEditingArea\n- 405 - trying to delete an entity which has non-editable crew in it\n- 407 - trying to delete a player (players cannot be manipulated with)\n- 501 - trying to destroy an object when destroying is disabled using setCuratorCoef \"destroy\"\n- 502 - trying to destroy an object which is too expensive (cost multiplied by setCuratorCoef \"destroy\" is larger than curatorPoints)\n- 504 - trying to destroy an object which is outside of curatorEditingArea\n- 505 - trying to destroy an object which has non-editable crew in it\n- 506 - trying to destroy an object when no object is selected\n- 507 - trying to destroy a player (players cannot be manipulated with)\n\n```sqf\nthis addEventHandler [\"CuratorFeedbackMessage\", {\n    params [\"_curator\", \"_errorID\"];\n}];\n```\n\n- curator: Object\n- errorID: Number\n\n#### CuratorGroupDoubleClicked\n\nLocal Argument\n\nTriggered when a group is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupDoubleClicked\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group\n\n#### CuratorGroupPlaced\n\nLocal Argument\n\nTriggered when new group is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupPlaced\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group\n\n#### CuratorGroupSelectionChanged\n\nLocal Argument\n\nTriggered when a group is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupSelectionChanged\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group\n\n#### CuratorMarkerDeleted\n\nLocal Argument\n\nTriggered when a marker is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerDeleted\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String\n\n#### CuratorMarkerDoubleClicked\n\nLocal Argument\n\nTriggered when a marker is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerDoubleClicked\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String\n\n#### CuratorMarkerEdited\n\nLocal Argument\n\nTriggered when a marker is moved in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerEdited\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String\n\n#### CuratorMarkerPlaced\n\nLocal Argument\n\nTriggered when new marker is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerPlaced\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String\n\n#### CuratorMarkerSelectionChanged\n\nLocal Argument\n\nTriggered when a marker is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerSelectionChanged\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String\n\n#### CuratorObjectDeleted\n\nLocal Argument\n\nTriggered when an object is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectDeleted\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object\n\n#### CuratorObjectDoubleClicked\n\nLocal Argument\n\nTriggered when an object is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectDoubleClicked\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object\n\n#### CuratorObjectEdited\n\nLocal Argument\n\nTriggered when an object is moved or rotated in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectEdited\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object\n\n#### CuratorObjectPlaced\n\nLocal Argument\n\nTriggered when new object is placed in curator interface.\nThis event handler will trigger individually for each unit in a placed group - excluding the crew in vehicles.\n\n```sqf\nthis addEventHandler [\"CuratorObjectPlaced\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object\n\n#### CuratorObjectRegistered\n\nLocal Argument\n\nTriggered when player enters curator interface. Assign curator cost to every object in the game.\nThis is the primary method that a mission designer can use to limit the objects a curator can place.\n\n> [!NOTE]\n> See Curator#Manual Assigning.\n\n```sqf\nthis addEventHandler [\"CuratorObjectRegistered\", {\n    params [\"_curator\", \"_input\"];\n}];\n```\n\n- curator: Object\n- input: Array of Strings - all CfgVehicles classes\n\n#### CuratorObjectSelectionChanged\n\nLocal Argument\n\nTriggered when an object is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectSelectionChanged\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object\n\n#### CuratorPinged\n\nLocal Argument\n\nTriggered when a player pings his curator(s) by pressing the *Zeus* key.\n\n```sqf\nthis addEventHandler [\"CuratorPinged\", {\n    params [\"_curator\", \"_player\"];\n}];\n```\n\n- curator: Object\n- player: Object\n\n#### CuratorSelectionPresetLoaded (Arma 3 v2.14)\n\nLocal Argument\n\nTriggered when a selection preset is loaded using the respective number key or through script.\n\n```sqf\nthis addEventHandler [\"CuratorSelectionPresetLoaded\", {\n    params [\"_curator\", \"_numkey\"];\n}];\n```\n\n- curator: Object\n- numkey: Number\n\n#### CuratorSelectionPresetSaved (Arma 3 v2.14)\n\nLocal Argument\n\nTriggered when a selection preset is saved using the respective CTRL + number key or set through script.\n\n```sqf\nthis addEventHandler [\"CuratorSelectionPresetSaved\", {\n    params [\"_curator\", \"_numkey\"];\n}];\n```\n\n- curator: Object\n- numkey: Number\n\n#### CuratorWaypointDeleted\n\nLocal Argument\n\nTriggered when a waypoint is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointDeleted\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array\n\n#### CuratorWaypointDoubleClicked\n\nLocal Argument\n\nTriggered when a waypoint is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointDoubleClicked\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array\n\n#### CuratorWaypointEdited\n\nLocal Argument\n\nTriggered when a waypoint is moved in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointEdited\", {\n    params [\"_curator\", \"_group\", \"_waypointID\"];\n}];\n```\n\n- curator: Object\n- group: Group\n- waypointID: Number\n\n#### CuratorWaypointPlaced\n\nLocal Argument\n\nTriggered when new waypoint is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointPlaced\", {\n    params [\"_curator\", \"_group\", \"_waypointID\"];\n}];\n```\n\n- curator: Object\n- group: Group\n- waypointID: Number\n\n#### CuratorWaypointSelectionChanged\n\nLocal Argument\n\nTriggered when a waypoint is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointSelectionChanged\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array\n\n### UserAction Event Handlers (Arma 3 v2.06)\n\nUserAction Event Handlers are events that trigger on user action.\n\nCommands:\n- addUserActionEventHandler\n- removeUserActionEventHandler\n\n> [!NOTE]\n> See Arma 3: Modded Keybinding.\n\n#### Activate\n\n```sqf\naddUserActionEventHandler [\"KeyName\", \"Activate\", {\n    params [\"_activated\"];\n}];\n```\n\n- activated: Boolean - always returns true\n\n#### Deactivate\n\n```sqf\naddUserActionEventHandler [\"KeyName\", \"Deactivate\", {\n    params [\"_activated\"];\n}];\n```\n\n- activated: Boolean - always returns false\n\n#### Analog\n\n```sqf\naddUserActionEventHandler [\"KeyName\", \"Analog\", {\n    params [\"_value\"];\n}];\n```\n\n- value: Number - input device's analog value\n\n### Projectile Event Handlers (Arma 3 v2.10)\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers\n\n#### Deleted (Projectile)\n\n```sqf\n_projectile addEventHandler [\"Deleted\", {\n    params [\"_projectile\"];\n}];\n```\n\n- projectile: Object\n\n#### Deflected\n\n```sqf\n_projectile addEventHandler [\"Deflected\", {\n    params [\"_projectile\", \"_position\", \"_velocity\", \"_hitObject\"];\n}];\n```\n\n- projectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D\n- hitObject: Object - the object that deflected the projectile\n\n#### Explode\n\nLocal Argument\n\n```sqf\n_projectile addEventHandler [\"Explode\", {\n    params [\"_projectile\", \"_position\", \"_velocity\"];\n}];\n```\n\n- projectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D\n\n#### HitExplosion\n\n```sqf\n_projectile addEventHandler [\"HitExplosion\", {\n    params [\"_projectile\", \"_hitEntity\", \"_projectileOwner\", \"_hitSelections\", \"_instigator\"];\n}];\n```\n\n- projectile: Object\n- hitEntity: Object\n- projectileOwner: Object\n- hitSelections: Array of Arrays - same list of FireGeometry components that #HitPart (Entity) gets but only contains:\n  - position: Array format PositionASL - position of impact\n  - vector: Array format Vector3D - vector that is orthogonal (perpendicular) to the surface struck. For example, if a wall was hit, vector would be pointing out of the wall at a 90 degree angle\n  - selection: String - named selection of the object that was hit, in the FireGeometry LOD.\n  - radius: Number - radius (size) of component hit\n  - surface: String - surface type struck\n- Arma 3 v2.18 instigator: Object - shot instigator\n\n#### HitPart (Projectile)\n\nTriggered when the projectile hits any surface.\n\n```sqf\n_projectile addEventHandler [\"HitPart\", {\n    params [\"_projectile\", \"_hitEntity\", \"_projectileOwner\", \"_pos\", \"_velocity\", \"_normal\", \"_components\", \"_radius\" ,\"_surfaceType\", \"_instigator\"];\n}];\n```\n\n- projectile: Object\n- hitEntity: Object\n- projectileOwner: Object\n- pos: Array format PositionASL\n- velocity: Array format Vector3D\n- normal: Array format Vector3D\n- components: Array of Strings - the selections that were hit, in the FireGeometry LOD.\n- radius: Number - radius (size) of the hitPoint\n- surfaceType: String\n- Arma 3 v2.18 instigator: Object - shot instigator\n\n> [!IMPORTANT]\n> This event handler only triggers for direct hits and not splash damage, unlike #HitPart (Entity). For splash damage, use #HitExplosion.\n\n#### Init (Projectile)\n\nTriggered whenever a projectile is created. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n```cpp\ninit = \"params ['_projectile'];\";\n```\n\n```sqf\nparams [\"_projectile\"];\n```\n\n- projectile: Object - object the event handler is assigned to\n\n#### MineActivated (Arma 3 v2.14)\n\nLocal Argument\nLocal Effect\n\n```sqf\n_projectile addEventHandler [\"MineActivated\", {\n    params [\"_projectile\", \"_isActive\"];\n}];\n```\n\n- projectile: Object\n- isActive: Boolean - new active state of the mine\n\n#### Penetrated\n\nThis event fires as many times as the projectile penetrates a surface.\n\n```sqf\n_projectile addEventHandler [\"Penetrated\", {\n    params [\"_projectile\", \"_hitObject\", \"_surfaceType\", \"_entryPoint\", \"_exitPoint\", \"_exitVector\"];\n}];\n```\n\n- projectile: Object\n- hitObject: Object\n- surfaceType: String - see surfaceType\n- entryPoint: Array format PositionASL - the projectile's entry point\n- exitPoint: Array format PositionASL - the projectile's exit point\n- exitVector: Array format Vector3D - speed/angle exit vector (see vectorMagnitude to obtain the speed, in metre per second)\n\n#### SubmunitionCreated\n\nThis event fires as many times as submunitions are created.\n\n```sqf\n_projectile addEventHandler [\"SubmunitionCreated\", {\n    params [\"_projectile\", \"_submunitionProjectile\", \"_position\", \"_velocity\"];\n}];\n```\n\n- projectile: Object\n- subMunitionProjectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D\n\n### Group Event Handlers (Arma 3 v2.10)\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers\n\n#### CombatModeChanged\n\nTriggers when the group's **behaviour** changes (see behaviour, setBehaviour)\n\n```sqf\n_group addEventHandler [\"CombatModeChanged\", {\n    params [\"_group\", \"_newMode\"];\n}];\n```\n\n- group: Group\n- newMode: String - see AI Behaviour (**not** Combat Modes!)\n\n#### CommandChanged\n\n```sqf\n_group addEventHandler [\"CommandChanged\", {\n    params [\"_group\", \"_newCommand\"];\n}];\n```\n\n- group: Group\n- newCommand: String, can be one of:\n\n|  |  |\n|---|---|\n| \"NO CMD\" | NoCommand |\n| \"WAIT\" | Wait |\n| \"ATTACK\" | Attack |\n| \"Suppress\" | Suppress |\n| \"HIDE\" | Hide |\n| \"MOVE\" | Move |\n| \"HOOK CARGO\" | HookCargo |\n| \"UNHOOK CARGO\" | UnhookCargo |\n| \"VIV GETIN\" | ViVGetIn |\n| \"VIV GETOUT\" | ViVGetOut |\n| \"VIV UNLOAD\" | ViVUnload |\n| \"HEAL\" | Heal |\n| \"REPAIR\" | Repair |\n| \"REFUEL\" | Refuel |\n| \"REARM\" | Rearm |\n| \"SUPPORT\" | Support |\n| \"JOIN\" | Join |\n| \"GET IN\" | GetIn |\n| \"FIRE\" | Fire |\n| \"GET OUT\" | GetOut |\n| \"STOP\" | Stop |\n| \"EXPECT\" | Expect |\n| \"ACTION\" | Action |\n| \"SCRIPTED\" | Scripted |\n| \"DISMISS\" | Dismiss |\n| \"HEAL SOLDIER\" | HealSoldier |\n| \"PATCH SOLDIER\" | PatchSoldier |\n| \"FIRST AID\" | FirstAid |\n| \"HEAL SELF\" | HealSoldierSelf |\n| \"ATTACK AND FIRE\" | AttackAndFire |\n| \"CARRY SOLDIER\" | CarrySoldier |\n| \"DROP CARRIED\" | DropCarried |\n| \"TAKE BAG\" | TakeBag |\n| \"ASSEMBLE\" | Assemble |\n| \"DISASSEMBLE\" | DisAssemble |\n| \"DROP BAG\" | DropBag |\n| \"OPEN BAG\" | OpenBag |\n| \"IRLASER ON\" | IRLaserOn |\n| \"IRLASER OFF\" | IRLaserOff |\n| \"GUN LIGHT ON\" | GunLightOn |\n| \"GUN LIGHT OFF\" | GunLightOff |\n| \"FIRE AT POSITION\" | FireAtPosition |\n| \"REPAIR VEHICLE\" | RepairVehicle |\n| \"OPEN PARA\" | OpenParachute |\n| \"KEEP DEPTH LEADER\" | KeepDepthLeader |\n| \"KEEP DEPTH UND SURF\" | KeepDepthUnderSurface |\n| \"KEEP DEPTH ABV SURF\" | KeepDepthAboveSurface |\n| \"KEEP DEPTH BOTTOM\" | KeepDepthBottom |\n| \"PUT IN\" | PutIn |\n| \"UNLOAD FROM\" | UnloadFrom |\n| \"USE CONTAINER MAGAZINE\" | UseContainerMagazine |\n| \"ACTIVATE MINE\" | ActivateMine |\n| \"DISABLE MINE\" | DisableMine |\n\n#### Deleted (Group)\n\n```sqf\n_group addEventHandler [\"Deleted\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group\n\n#### Empty\n\n```sqf\n_group addEventHandler [\"Empty\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group\n\n#### EnableAttackChanged\n\n```sqf\n_group addEventHandler [\"EnableAttackChanged\", {\n    params [\"_group\", \"_attackEnabled\"];\n}];\n```\n\n- group: Group\n- attackEnabled: Boolean\n\n#### EnemyDetected\n\n```sqf\n_group addEventHandler [\"EnemyDetected\", {\n    params [\"_group\", \"_newTarget\"];\n}];\n```\n\n- group: Group\n- newTarget: Object\n\n#### Fleeing\n\n```sqf\n_group addEventHandler [\"Fleeing\", {\n    params [\"_group\", \"_fleeingNow\"];\n}];\n```\n\n- group: Group\n- fleeingNow: Boolean\n\n#### FormationChanged\n\n```sqf\n_group addEventHandler [\"FormationChanged\", {\n    params [\"_group\", \"_newFormation\"];\n}];\n```\n\n- group: Group\n- newFormation: String - see setFormation\n\n#### GroupIdChanged\n\n```sqf\n_group addEventHandler [\"GroupIdChanged\", {\n    params [\"_group\", \"_newGroupId\"];\n}];\n```\n\n- group: Group\n- newGroupId: String\n\n#### KnowsAboutChanged\n\n```sqf\n_group addEventHandler [\"KnowsAboutChanged\", {\n    params [\"_group\", \"_targetUnit\", \"_newKnowsAbout\", \"_oldKnowsAbout\"];\n}];\n```\n\n- group: Group\n- targetUnit: Object\n- newKnowsAbout: Number\n- oldKnowsAbout: Number\n\n#### LeaderChanged\n\n```sqf\n_group addEventHandler [\"LeaderChanged\", {\n    params [\"_group\", \"_newLeader\"];\n}];\n```\n\n- group: Group\n- newLeader: Object\n\n#### Local (Group)\n\n```sqf\n_group addEventHandler [\"Local\", {\n    params [\"_group\", \"_isLocal\"];\n}];\n```\n\n- group: Group\n\n#### SpeedModeChanged\n\n```sqf\n_group addEventHandler [\"SpeedModeChanged\", {\n    params [\"_group\", \"_newSpeedMode\"];\n}];\n```\n\n- group: Group\n- newSpeedMode: String - see setSpeedMode\n\n#### UnitJoined\n\n```sqf\n_group addEventHandler [\"UnitJoined\", {\n    params [\"_group\", \"_newUnit\"];\n}];\n```\n\n- group: Group\n- newUnit: Object\n\n#### UnitKilled (Arma 3 v2.18)\n\nLocal Argument\n\nTriggered when a unit in the group is killed.\n\n```sqf\n_group addEventHandler [\"UnitKilled\", {\n    params [\"_group\", \"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- group: Group - the group the event handler is assigned to\n- unit: Object - the unit that was killed\n- killer: Object - the object that killed the unit. Contains the unit itself in case of collisions.\n- instigator: Object - the person who pulled the trigger\n- useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n\n#### UnitLeft\n\n```sqf\n_group addEventHandler [\"UnitLeft\", {\n    params [\"_group\", \"_oldUnit\"];\n}];\n```\n\n- group: Group\n- oldUnit: Object\n\n#### VehicleAdded\n\n```sqf\n_group addEventHandler [\"VehicleAdded\", {\n    params [\"_group\", \"_newVehicle\"];\n}];\n```\n\n- group: Group\n- newVehicle: Object\n\n#### VehicleRemoved\n\n```sqf\n_group addEventHandler [\"VehicleRemoved\", {\n    params [\"_group\", \"_oldVehicle\"];\n}];\n```\n\n- group: Group\n- oldVehicle: Object\n\n#### WaypointComplete\n\n```sqf\n_group addEventHandler [\"WaypointComplete\", {\n    params [\"_group\", \"_waypointIndex\"];\n}];\n```\n\n- group: Group\n- waypointIndex: Number\n\n### Game UI Event Handlers\n\nIn Game UI Event Handlers trigger when user scrolls or activates in game action menu.\n\nThe following mission EHs are available in Arma 3:\n- PrevAction - action menu scroll up event\n- Action - action menu action event\n- NextAction - action menu scroll down event\n\n> [!IMPORTANT]\n> Only one event of each kind can exist, adding another will overwrite the existing one.\n\nCommands:\n- inGameUISetEventHandler\n\n> [!NOTE]\n> See Arma 3: Event Handlers/inGameUISetEventHandler.\n\n### Control/Display UI Event Handlers\n\nCommands:\n- ctrlAddEventHandler\n- ctrlRemoveEventHandler\n- ctrlRemoveAllEventHandlers\n- displayAddEventHandler\n- displayRemoveEventHandler\n- displayRemoveAllEventHandlers\n\n> [!NOTE]\n> See User Interface Event Handlers.\n\n### Music Event Handlers\n\nMusic event handler, always executed on the computer where it was added.\n\n> [!NOTE]\n> Does not apply to interface-less machines (dedicated server, headless client).\n\nCommands:\n- setMusicEventHandler\n- addMusicEventHandler\n- removeMusicEventHandler\n- removeAllMusicEventHandlers\n\n#### MusicStart (Arma 3 v0.50)\n\nTriggers when CfgMusic sound starts playing, after being executed with playMusic command.\n\n```sqf\naddMusicEventHandler [\"MusicStart\", {\n    params [\"_musicClassname\", \"_eventHandlerID\", \"_currentPosition\", \"_totalLength\"];\n}];\n```\n\n- musicClassName: String - CfgMusic class name of the music that started\n- eventHandlerID: Number - EH id returned by addMusicEventHandler\n- Arma 3 v2.18 currentPosition: Number - current playback position in 0...1 range (see also: getMusicPlayedTime)\n- Arma 3 v2.18 totalLength: Number - track total length in seconds\n\n#### MusicStop (Arma 3 v0.50)\n\nTriggers when CfgMusic sound finished playing, after being executed with playMusic command.\n\nArma 3 v2.14 `playMusic \"\"` triggers this event if a music is currently playing.\n\n```sqf\naddMusicEventHandler [\"MusicStop\", {\n    params [\"_musicClassname\", \"_eventHandlerID\", \"_currentPosition\", \"_totalLength\"];\n}];\n```\n\n- musicClassName: String - CfgMusic class name of the music that stopped\n- eventHandlerID: Number - EH id returned by addMusicEventHandler\n- Arma 3 v2.18 currentPosition: Number - current playback position in 0...1 range (see also: getMusicPlayedTime)\n- Arma 3 v2.18 totalLength: Number - track total length in seconds\n\n### Eden Editor\n\nCommands:\n- add3DENEventHandler\n- remove3DENEventHandler\n- removeAll3DENEventHandlers\n\n> [!NOTE]\n> See also:\n> - Arma 3: Event Handlers: Eden Editor\n> - its sub-category Object Event Handlers\n> - Eden Editor\n\n### Public Variable Broadcast Event\n\nCommands:\n- addPublicVariableEventHandler\n\nTriggers when missionNamespace variable EH is associated with is sent over network via publicVariable, publicVariableServer or publicVariableClient commands.\n\n> [!NOTE]\n> Unlike with other types of EHs, there is no way of removing added public variable event handler\n\n### Weapon Muzzle Config Events\n\nThere are six event handlers that can be set on weapon in config. Their parameters are the same as their entity EH equivalents.\n- \"Fired\" - when muzzle fired - see Fired\n- \"Reload\" - before muzzle is reloaded - see MagazineReloading\n- \"Reloaded\" - after muzzle is reloaded - see Reloaded\n- \"MagazineUnloaded\" - when the magazine is removed - see MagazineUnloaded\n- \"WeaponChanged\" - when the weapon is switched to or from - see WeaponChanged\n- \"SlotItemChanged\" - when one of the weapon's attachments is changed - see SlotItemChanged\n\n```cpp\nclass CfgWeapons\n{\n    class RifleCore;\n    class TAG_Rifle : RifleCore\n    {\n        class EventHandlers\n        {\n            fired        = \"systemChat format ['fired weapon EH output: %1 [time: %2]', _this, time]\";\n            reload        = \"systemChat format ['reload weapon EH output: %1 [time: %2]', _this, time]\";\n            reloaded    = \"systemChat format ['reloaded weapon EH output: %1 [time: %2]', _this, time]\";\n            magazineunloaded    = \"systemChat format ['magazineunloaded weapon EH output: %1 [time: %2]', _this, time]\";\n            slotitemchanged    = \"systemChat format ['slotitemchanged weapon EH output: %1 [time: %2]', _this, time]\";\n            weaponchanged    = \"systemChat format ['weaponchanged weapon EH output: %1 [time: %2]', _this, time]\";\n        };\n    };\n};\n```\n\n### Ammo Config Events\n\nThere are three event handlers that can be set on ammo in config:\n- \"init\" - when the ammo is created, by any mean (fired, created, etc). Params: [shot]\n- \"fired\" - when the ammo is fired (legacy). Params: same as in entity EH \"Fired\".\n- \"ammoHit\" - when the ammo hits anything (can trigger multiple times). Params: [shot, shooter, hitobj, pos, velocity, hitComponents, [hit, indirecthit, indirecthitrange, explosive, name], normal, explode, instigator (since Arma 3 v2.18)]\n\n```cpp\nclass CfgAmmo\n{\n    class BulletCore;\n    class TAG_Bullet : BulletCore\n    {\n        class EventHandlers\n        {\n            init    = \"systemChat format ['init ammo EH output: %1 [time: %2]', _this, time]\";\n            fired    = \"systemChat format ['fired ammo EH output: %1 [time: %2]', _this, time]\";\n            ammoHit    = \"systemChat format ['ammoHit EH output: %1 [time: %2]', _this, time]\";\n        };\n    };\n};\n```\n\n### BI Scripted Events\n\nCommands:\n- BIS_fnc_addScriptedEventHandler\n- BIS_fnc_removeScriptedEventHandler\n- BIS_fnc_removeAllScriptedEventHandlers\n- BIS_fnc_callScriptedEventHandler\n\n> [!NOTE]\n> See also Arma 3: Scripted Event Handlers.\n\nJump to the top of the page","sections":[{"heading":null,"level":1,"markdown":"An Event Handler (abbreviated to EH) allows you to automatically monitor and then execute custom code upon particular events being triggered.\n\nSee also Event Scripts for special event triggered scripts."},{"heading":"Basic Event Handlers","level":3,"markdown":"The object-based Event Handler is always executed on the computer where it was added.\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers"},{"heading":"AmmoExplodedNear (Arma 3 v2.22)","level":4,"markdown":"Triggers when ammo explodes in some damage range of the object. This EH triggers where the ammo is 'real', similar to HitPart.\n\n```sqf\nthis addEventHandler [\"AmmoExplodedNear\", {\n    params [\"_object\", \"_shot\", \"_position\", \"_velocity\", \"_ammo\", \"_explosive\", \"_indirectHit\", \"_invArmor\", \"_damage\"];\n}];\n```\n\n- object: Object - object the event handler is assigned to\n- shot: Object - shot that has exploded\n- position: Array - world position of the shot\n- velocity: Array - world velocity of the shot\n- ammmo: String - config ammo class name\n- explosive: Number - config value for 'explosive'\n- indirectHit: Number - config value for 'indirectHit'\n- invArmor: Number - calculated inverse armor from config value\n- damage: Number - a rough estimate of the potential damage to the center of the object based on config values and the distance"},{"heading":"AnimChanged","level":4,"markdown":"Global Argument\n\nTriggered every time a new animation is started. This EH is only triggered for the 1st animation state in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimChanged\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that is started"},{"heading":"AnimDone","level":4,"markdown":"Global Argument\n\nTriggered every time an animation is finished. Triggered for all animation states in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimDone\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that has been finished"},{"heading":"AnimStateChanged","level":4,"markdown":"Global Argument\n\nTriggered every time an animation state changes. Triggered for all animation states in a sequence.\n\n```sqf\nthis addEventHandler [\"AnimStateChanged\", {\n    params [\"_unit\", \"_anim\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- anim: String - name of the anim that has been started"},{"heading":"Assembled (Arma 3 v2.18)","level":4,"markdown":"Local Argument\n\nTriggers when weapon that is moved out of the world is assembled again. EH should be attached to the entity.\n\n```sqf\nthis addEventHandler [\"Assembled\", {\n    params [\"_entity\", \"_unit\", \"_primaryBag\", \"_secondaryBag\"];\n}];\n```\n\n- entity: Object - weapon this event is assigned to\n- unit: Object - person who assembled the weapon\n- primaryBag: Object - first backpack object which was entity disassembled into (just before it is deleted)\n- secondaryBag: Object - second backpack object which was entity disassembled into (just before it is deleted)"},{"heading":"Attached (Arma 3 v2.18)","level":4,"markdown":"Triggered after an object has been attached to another object (see attachTo).\n\n```sqf\nthis addEventHandler [\"Attached\", {\n    params [\"_attachedObj\", \"_parentObj\", \"_isReattach\", \"_offset\", \"_memoryPointIndex\", \"_followBoneRotation\"];\n}];\n```\n\n- attachedObj: Object\n- parentObj: Object\n- isReattach: Boolean - true if `attachedObj` was already attached to `parentObj`, e.g. if only the offset was changed\n- offset: Array format PositionRelative\n- memoryPointIndex: Number\n- followBoneRotation: Boolean"},{"heading":"CargoLoaded (Arma 3 v2.06)","level":4,"markdown":"Global Argument\n\nTriggered when a vehicle is loaded into another vehicle (ViV).\n\nIt can be added to either the transport vehicle, or the cargo vehicle, and will fire for both cases.\n\n```sqf\nthis addEventHandler [\"CargoLoaded\", {\n    params [\"_parentVehicle\", \"_cargoVehicle\"];\n}];\n```\n\n- parentVehicle: Object - the transport (parent) vehicle\n- cargoVehicle: Object - the cargo (child) vehicle"},{"heading":"CargoUnloaded (Arma 3 v2.06)","level":4,"markdown":"Global Argument\n\nTriggered when a vehicle is unloaded from another vehicle (ViV).\n\nIt can be added to either the transport vehicle, or the cargo vehicle, and will fire for both cases.\n\n```sqf\nthis addEventHandler [\"CargoUnloaded\", {\n    params [\"_parentVehicle\", \"_cargoVehicle\"];\n}];\n```\n\n- parentVehicle: Object - the transport (parent) vehicle\n- cargoVehicle: Object - the cargo (child) vehicle"},{"heading":"ContainerClosed (Arma 3 v1.32)","level":4,"markdown":"Global Argument\n\nTriggers when player finished accessing cargo container.\nThis event handler is similar to InventoryClosed EH, but needs to be assigned to the container rather than the player.\n\n**Note:** will trigger only for the unit opening container.\n\n```sqf\nthis addEventHandler [\"ContainerClosed\", {\n    params [\"_container\", \"_unit\"];\n}];\n```\n\n- container: Object - cargo container.\n- unit: Object - unit who accessed the container"},{"heading":"ContainerOpened (Arma 3 v1.32)","level":4,"markdown":"Global Argument\n\nTriggers when cargo container is accessed by player.\nThis event handler is similar to InventoryOpened EH, but needs to be assigned to the container rather than the player and cannot be overridden.\n\n**Note:** will trigger only for the unit opening container.\n\n```sqf\nthis addEventHandler [\"ContainerOpened\", {\n    params [\"_container\", \"_unit\"];\n}];\n```\n\n- container: Object - cargo container\n- unit: Object - unit who accessed the container"},{"heading":"ControlsShifted (Arma 3 v1.00)","level":4,"markdown":"Global ArgumentLocal Effect\n\nTriggers when control of a vehicle is shifted (pilot->co-pilot, co-pilot->pilot), usually when user performs an action such as TakeVehicleControl, SuspendVehicleControl, UnlockVehicleControl, LockVehicleControl, or when enableCopilot command is used. This event handler will always fire on the PC where action is triggered as well as where the vehicle is local at the time. When control of the vehicle is shifted, the locality of the vehicle changes to the locality of the new controller. For example, if helicopter is local to the server and co-pilot takes controls, the helicopter changes locality to co-pilot PC.\nThis means that if \"ControlsShifted\" EH was added on both server and client, \"Take Controls\" action will trigger EH on both, client and server PC, but subsequent co-pilot \"Release Controls\" action will trigger only on co-pilot's PC, because vehicle will be local to co-pilot at this point. There is also a slightly better mission version of ControlsShifted event handler.\n\n```sqf\nthis addEventHandler [\"ControlsShifted\", {\n    params [\"_vehicle\", \"_activeCoPilot\", \"_oldController\"];\n}];\n```\n\n- vehicle: Object - vehicle which controls were shifted\n- activeCoPilot: Object - co-pilot unit which controls vehicle after this event. objNull if co-pilot is not controlling the vehicle\n- oldController: Object - unit who controlled vehicle before this event"},{"heading":"Dammaged","level":4,"markdown":"Global Argument\n\nTriggered when the unit is damaged. In ArmA works with all vehicles not only men like in OFP.\n\n**Notes:**\n- The typo is \"intentional\": it is Da**mm**aged with two \"m\".\n- If simultaneous damage occured (e.g. via grenade) EH might be triggered several times.\n- The Dammaged EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\n\n```sqf\nthis addEventHandler [\"Dammaged\", {\n    params [\"_unit\", \"_hitSelection\", \"_damage\", \"_hitPartIndex\", \"_hitPoint\", \"_shooter\", \"_projectile\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- hitSelection: String - name of the selection where the unit was damaged\n- damage: Number - resulting level of damage\n- Arma 3 v1.68 hitPartIndex: Number - hit index of the hit selection\n- Arma 3 v1.68 hitPoint: String - hit point Cfg name\n- Arma 3 v1.70 shooter: Object - shooter reference (to get instigator use getShotParents on projectile)\n- Arma 3 v1.70 projectile: Object - the projectile that caused damage"},{"heading":"Deleted (Entity) (Arma 3 v1.68)","level":4,"markdown":"Global Argument\n\nTriggered just before the assigned entity is deleted.\n\n```sqf\nthis addEventHandler [\"Deleted\", {\n    params [\"_entity\"];\n}];\n```\n\n- entity: Object - object the event handler is assigned to"},{"heading":"Detached (Arma 3 v2.18)","level":4,"markdown":"Triggered after an object has been detached from its parent object (see detach). Does not fire if the parent object was deleted.\n\n```sqf\nthis addEventHandler [\"Detached\", {\n    params [\"_attachedObj\", \"_parentObj\"];\n}];\n```\n\n- attachedObj: Object\n- parentObj: Object"},{"heading":"Disassembled (Arma 3 v2.00)","level":4,"markdown":"Local Argument\n\nTriggers when entity such as weapon/backpack gets disassembled. EH should be attached to the entity.\n\n```sqf\nthis addEventHandler [\"Disassembled\", {\n    params [\"_entity\", \"_primaryBag\", \"_secondaryBag\", \"_unit\"];\n}];\n```\n\n- entity: Object - weapon this event is assigned to (just before is is moved out of the world)\n- primaryBag: Object - first backpack object which was entity disassembled into\n- secondaryBag: Object - second backpack object which was entity disassembled into\n- Arma 3 v2.18 unit: Object - person who disassembled the weapon"},{"heading":"Engine","level":4,"markdown":"Global Argument\n\nTriggered when the engine of the unit is turned on/off.\n\n> [!NOTE]\n> Although the event is global, on clients (non-server) and applied to remote vehicles, it will fire only if the vehicle is closer than about 6 km from the camera.\n> Should the vehicle be far away, it will fire as soon as the camera and vehicle are close enough together, alongside the isEngineOn flag change.\n\n```sqf\nthis addEventHandler [\"Engine\", {\n    params [\"_vehicle\", \"_engineState\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- engineState: Boolean - true when the engine is turned on, false when turned off"},{"heading":"EpeContact (Arma 3 v1.00)","level":4,"markdown":"Global Argument\n\nTriggered when object collision (PhysX) is in progress.\n\n```sqf\nthis addEventHandler [\"EpeContact\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\", \"_reactVect\", \"_worldPos\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- selection1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- selection2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision\n- Arma 3 v2.12 reactVect: Array - impact reaction force vector\n- Arma 3 v2.12 worldPos: PositionWorld - point of impact in world coordinates"},{"heading":"EpeContactEnd (Arma 3 v1.00)","level":4,"markdown":"Global Argument\n\nTriggered when object collision (PhysX) ends.\n\n```sqf\nthis addEventHandler [\"EpeContactEnd\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- selection1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- selection2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision"},{"heading":"EpeContactStart (Arma 3 v1.00)","level":4,"markdown":"Global Argument\n\nTriggered when object collision (PhysX) starts.\n\n```sqf\nthis addEventHandler [\"EpeContactStart\", {\n    params [\"_object1\", \"_object2\", \"_selection1\", \"_selection2\", \"_force\", \"_reactForce\", \"_worldPos\"];\n}];\n```\n\n- object1: Object - object with attached handler\n- object2: Object - object which is colliding with object1\n- select1: String - selection of object1 which is colliding - not in use at this moment, empty string is always returned\n- select2: String - selection of object2 which is colliding - not in use at this moment, empty string is always returned\n- force: Number - force of collision\n- Arma 3 v2.12 reactForce: Array - impact reaction force vector\n- Arma 3 v2.12 worldPos: PositionWorld - point of impact in world coordinates"},{"heading":"Explosion (Arma 3 v0.76)","level":4,"markdown":"Global Argument\n\nTriggered when a vehicle or unit is damaged by a nearby explosion.\nIt can be assigned to a remote unit or vehicle but will only fire on the PC where EH is added and explosion is local, i.e. it really needs to be added on every PC and JIP and will fire only where the explosion is originated.\n\n```sqf\nthis addEventHandler [\"Explosion\", {\n    params [\"_vehicle\", \"_damage\", \"_explosionSource\"];\n}];\n```\n\n- vehicle: Object - object the event handler is assigned to\n- damage: Number - damage inflicted to the object\n- Arma 3 v2.10 explosionSource: Object - the exploding object (NOT the shooter) - may be objNull in some cases\n\n> [!NOTE]\n> This event will fire even for tiniest of explosion damage (which appears as 0 damage argument), while #HitPart (Entity) could ignore such damage and not fire.\n> Example of such event would be a tank firing AP round and hitting ground a meter away from the vehicle, it does not produce an explosion yet its indirectHit could still cause tiny amount of damage to weak hit points (car wheels, headlights, etc.).\n> In such case you might not get any #HitPart (Entity) event fires, get some #HandleDamage events if target is local, and get this Explosion event."},{"heading":"Fired","level":4,"markdown":"Global Argument\n\nTriggered when the unit fires a weapon.\n\nThis EH will not trigger if a unit fires out of a vehicle. For those cases an EH has to be attached to that particular vehicle.\nWhen \"Manual Fire\" is used, the *gunner* is objNull if gunner is not present or the *gunner* is not the one who fires.\nTo check if \"Manual Fire\" is on, use isManualFire. The actual shot instigator could be retrieved with getShotParents command.\n\n> [!WARNING]\n> **Special multiplayer behaviour:** When added to a remote unit or vehicle, this EH will only fire if said entity is within range of the camera.\n> That range is determined by the fired ammo's highest visibleFire and audibleFire config value.\n> In case of units, muzzle attachment coefficients are applied too.\n\n```sqf\nthis addEventHandler [\"Fired\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_magazine\", \"_projectile\", \"_gunner\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- magazine: String - magazine name which was used\n- projectile: Object - object of the projectile that was shot out\n- Arma 3 v1.66 gunner: Object - gunner whose weapons are firing."},{"heading":"FiredMan (Arma 3 v1.66)","level":4,"markdown":"Global Argument\n\nTriggered when the unit fires a weapon. This EH must be attached to a soldier and unlike with \"Fired\" EH, it will fire regardless of whether the soldier is on foot or firing vehicle weapon.\nFor remoteControled unit use \"Fired\" EH instead.\n\n> [!WARNING]\n> **Special multiplayer behaviour:** When added to a remote unit or vehicle, this EH will only fire if said entity is within range of the camera.\n> That range is determined by the fired ammo's highest visibleFire and audibleFire config value.\n> In case of units, muzzle attachment coefficients are applied too.\n\n```sqf\nthis addEventHandler [\"FiredMan\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_magazine\", \"_projectile\", \"_vehicle\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to (the instigator)\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- magazine: String - magazine name which was used\n- projectile: Object - object of the projectile that was shot out\n- vehicle: Object - vehicle, if weapon is vehicle weapon, otherwise objNull"},{"heading":"FiredNear","level":4,"markdown":"Global Argument\n\nTriggered when a weapon is fired somewhere *near* the unit or vehicle. It is also triggered if the unit itself is firing.\n\nWhen \"Manual Fire\" is used, the *gunner* is objNull if gunner is not present or the *gunner* is not the one who fires.\nTo check if \"Manual Fire\" is on, use isManualFire. The actual shot instigator can be retrieved with getShotParents command.\n\nArma 3 v1.30 Works with thrown weapons (using the \"Throw\" weapon) like grenades.\n\n```sqf\nthis addEventHandler [\"FiredNear\", {\n    params [\"_unit\", \"_firer\", \"_distance\", \"_weapon\", \"_muzzle\", \"_mode\", \"_ammo\", \"_gunner\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- firer: Object - object which fires a weapon near the unit\n- distance: Number - distance in meters between the *unit* and *firer* (max. distance ~69m)\n- weapon: String - fired weapon\n- muzzle: String - muzzle that was used\n- mode: String - current mode of the fired weapon\n- ammo: String - ammo used\n- Arma 3 v1.66 gunner: Object - gunner, whose weapons are fired"},{"heading":"Fuel","level":4,"markdown":"Global Argument\n\nTriggered when the vehicle's fuel status changes between non-empty and empty or between empty and non-empty.\n\n```sqf\nthis addEventHandler [\"Fuel\", {\n    params [\"_vehicle\", \"_hasFuel\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- hasFuel: Boolean - false when has no fuel, true when has some fuel"},{"heading":"Gear","level":4,"markdown":"Global Argument\n\nTriggered when the unit lowers/retracts the landing gear, whether it is a helicopter or a plane.\nAlso triggered for helicopters in landing mode, regardless if they have retractable gear or not.\n\n> [!NOTE]\n> Not to be confused with *InventoryOpened* and *InventoryClosed* events, *Gear* fires when the landing gear state on an aircraft has changed.\n\n```sqf\nthis addEventHandler [\"Gear\", {\n    params [\"_vehicle\", \"_gearState\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- gearState: Boolean - true when the gear is lowered, false when retracted"},{"heading":"GestureChanged (Arma 3 v2.06)","level":4,"markdown":"Global Argument\n\nTriggered every time a new gesture is played.\n\n```sqf\nthis addEventHandler [\"GestureChanged\", {\n    params [\"_unit\", \"_gesture\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- gesture: String - name of the gesture that has started playing"},{"heading":"GestureDone (Arma 3 v2.06)","level":4,"markdown":"Global Argument\n\nTriggered every time a gesture is finished.\n\n```sqf\nthis addEventHandler [\"GestureDone\", {\n    params [\"_unit\", \"_gesture\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- gesture: String - name of the gesture that has been finished"},{"heading":"GetIn","level":4,"markdown":"Global Argument\n\nTriggers when a unit enters the vehicle to which this EH has been added. This EH is triggered by moveInXXXX commands and \"GetInXXXX\" actions, but not upon a seat change within the same vehicle.\n\nIn vehicles with multi-turret setup, entering any turret will show \"gunner\" for position.\n\n```sqf\nthis addEventHandler [\"GetIn\", {\n    params [\"_vehicle\", \"_role\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- unit: Object - unit that entered the vehicle\n- Arma 3 v1.36 turret: Array - turret path"},{"heading":"GetInMan (Arma 3 v1.58)","level":4,"markdown":"Global Argument\n\nTriggers when a unit enters a vehicle. Similar to \"GetIn\" but must be assigned to a unit and not vehicle.\nPersistent on respawn if assigned where unit was local. This EH is triggered by moveInXXXX commands and \"GetInXXXX\" actions.\n\n```sqf\nthis addEventHandler [\"GetInMan\", {\n    params [\"_unit\", \"_role\", \"_vehicle\", \"_turret\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- vehicle: Object - vehicle the unit entered\n- turret: Array - turret path"},{"heading":"GetOut","level":4,"markdown":"Global Argument\n\nTriggers when a unit gets out from the vehicle to which this EH has been added.\nThis EH is triggered by moveOut, \"GetOut\" & \"Eject\" actions, if an alive crew member disconnects or is deleted, but not upon a seat change within the same vehicle.\n\n```sqf\nthis addEventHandler [\"GetOut\", {\n    params [\"_vehicle\", \"_role\", \"_unit\", \"_turret\", \"_isEject\"];\n}];\n```\n\n- vehicle: Object - vehicle the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- unit: Object - unit that left the vehicle\n- Arma 3 v1.36 turret: Array - turret path\n- Arma 3 v2.14 isEject: Boolean - true if unit used 'Eject' action"},{"heading":"GetOutMan (Arma 3 v1.58)","level":4,"markdown":"Global Argument\n\nTriggers when a unit exits a vehicle. Similar to \"GetOut\" but must be assigned to a unit and not vehicle.\nPersistent on respawn if assigned where unit was local. This EH is triggered by moveOut and \"GetOut\" & \"Eject\" actions.\n\n```sqf\nthis addEventHandler [\"GetOutMan\", {\n    params [\"_unit\", \"_role\", \"_vehicle\", \"_turret\", \"_isEject\"];\n}];\n```\n\n- unit: Object - unit the event handler is assigned to\n- role: String - can be either \"driver\", \"gunner\", \"commander\" or \"cargo\"\n- vehicle: Object - vehicle that the unit left\n- turret: Array - turret path\n- Arma 3 v2.14 isEject: Boolean - true if unit used 'Eject' action"},{"heading":"HandleDamage","level":4,"markdown":"Global Argument\n\nTriggers when the unit is damaged and fires for each damaged selection separately\nWorks with all vehicles.\nThis EH can accept a remote unit as argument however it will only fire when the unit is local to the PC this event handler was added on.\nFor example, you can add this event handler to one particular vehicle on every PC.\nWhen this vehicle gets hit, only EH on PC where the vehicle is currently local will fire.\n\nIf the provided code returns a numeric value, this value will overwrite the default damage of given selection after processing.\nIf no value is returned, the default damage processing will be done - this allows for safe stacking of this event handler.\nOnly the return value of the last added \"HandleDamage\" EH is considered.\n\n> [!IMPORTANT]\n> A return value of 0 will make the unit **invulnerable** if damage is not scripted in other ways (i.e using setDamage and/or setHit for additional damage handling).\n> The return value is the hit zone's **absolute damage value**, **not** the damage to be *added* to it.\n\n**Notes:**\n- Multiple \"HandleDamage\" EHs can be added to the same unit. If multiple EHs return damage value for custom damage handling, only last returned value will be considered by the engine.\nEHs that do not return value can be safely added after EHs that do return value.\n- You can save the last event as timestamp (diag_tickTime) onto the unit, as well as the current health of the unit/its selections, with setVariable and query it on each \"HandleDamage\" event with getVariable to define a system how to handle the \"HandleDamage\" event.\n- \"HandleDamage\" will continue to trigger even if the unit is already dead.\n- \"HandleDamage\" is persistent. If you add it to the player object, it will continue to exist after player respawned.\n- \"HandleDamage\" can trigger \"twice\" per damage event. Once for direct damage, once for indirect damage (explosive damage). This can happen even in the same frame, but is unlikely.\n- Use setMissionOptions to filter out no damage calls or fake head hit.\n\nAdditional [Celery's explanation (Updated by ShadowRanger for Arma 3)](https://forums.bistudio.com/forums/topic/205515-handledamage-event-handler-explained/).\n\n```sqf\nthis addEventHandler [\"HandleDamage\", {\n    params [\"_unit\", \"_selection\", \"_damage\", \"_source\", \"_projectile\", \"_hitPartIndex\", \"_instigator\", \"_hitPoint\", \"_directHit\", \"_context\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- selection: String - name of the selection where the unit was damaged.\n  - \"\" for overall structural damage\n  - \"?\" for unknown selections\n- damage: Number - resulting level of damage for the selection\n- source: Object - the source unit that caused the damage\n- projectile: String - classname of the projectile that caused inflicted the damage. (\"\" for unknown, such as fall damage)\n- Arma 3 v1.50 hitPartIndex: Number - hit part index of the hit point, -1 otherwise\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 hitPoint: String - hit point Cfg name\n- Arma 3 v2.12 directHit: Boolean - true for direct projectile damage, false for explosion splash damage and all other kinds of damage like fall damage, fire damage, collision damage, etc.\n- Arma 3 v2.16 context: Number - some additional context for the event:\n\n0 : TotalDamage - total damage adjusted before iteration through hitpoints\n\n1 : HitPoint - some hit point processed during iteration\n\n2 : LastHitPoint - the last hitpoint from iteration is processed\n\n3 : FakeHeadHit - head hit that is added/adjusted\n\n4 : TotalDamageBeforeBleeding - total damage is adjusted before calculating bleeding\n\n> [!NOTE]\n> Between an unknown version (confirmed in Arma 3 v1.70) until v1.78 HandleDamage event triggered for every selection of a vehicle, no matter if the section was damaged or not."},{"heading":"HandleHeal","level":4,"markdown":"Global Argument\n\nTriggered when unit starts healing process (player using heal action on self or other unit, scripted action or AI heals after being ordered or on its own).\nThis event handler must be added to the 'injured' (could be added to Init field in editor) and in multiplayer will trigger only on PC where 'healer' is local. If code returns anything but true, engine side healing follows, otherwise healing is aborted.\n\n> [!IMPORTANT]\n> When AI unit is ordered (or acts at own accord) to heal at a medical vehicle and the event handler returns true, the healing is canceled but AI will try again and again and again. The event handler in this case will fire every second until AI unit is healed by other means.\n\n**NOTE**: This Event Handler was broken before Arma 3 v2.18.\n\n```sqf\nthis addEventHandler [\"HandleHeal\", {\n    _this spawn {\n        params [\"_injured\", \"_healer\", \"_isMedic\", \"_atVehicle\", \"_action\"];\n        private _damage = damage _injured;\n        if (_injured == _healer) then\n        {\n            waitUntil { damage _injured != _damage };\n            if (damage _injured < _damage) then\n            {\n                _injured setDamage 0;\n            };\n        };\n    };\n}];\n```\n\n```sqf\nthis addEventHandler [\"HandleHeal\", {\n    params [\"_injured\", \"_healer\", \"_isMedic\", \"_atVehicle\", \"_action\"];\n}];\n```\n\n- injured: Object - unit EH is attached to\n- healer: Object - unit that does the healing (could be the same unit as 'injured')\n- isMedic: Boolean - true when healer is 'Medic'\n- Arma 3 v2.18 atVehicle: Object - when healing at medical vehicle, this is the vehicle\n- Arma 3 v2.18 action: String - the action that triggered the event handler, for example \"SoldierHealSelf\""},{"heading":"HandleIdentity","level":4,"markdown":"Global Argument\n\nTriggered whenever an entity is created. Can be used in scripts if EH is added immediately after unit is created in unscheduled environment.\nDoesn't trigger for editor placed units. Does not work in Multiplayer. If EH scope returns true, the default engine identity application is overridden.\n\n```sqf\nbob = group player createUnit [typeOf player, position player, [], 0, \"NONE\"];\nbob addEventHandler [\"HandleIdentity\", {\n    params [\"_unit\"];\n    hint str _unit;\n}];\n```\n\n- unit: Object - object the event handler is assigned to"},{"heading":"HandleRating (Arma 3 v1.32)","level":4,"markdown":"Local Argument\n\nTriggered when engine adds rating to overall rating of the unit, usually after a kill or a friendly kill.\nIf EH code returns Number, this will override default engine behaviour and the resulting value added will be the one returned by EH code.\n\n```sqf\nthis addEventHandler [\"HandleRating\", {\n    params [\"_unit\", \"_rating\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- rating: Number - rating to be added"},{"heading":"HandleScore (Arma 3 v1.32)","level":4,"markdown":"Global ArgumentServer Execution\n\nTriggered when engine adds score to overall score of the unit, usually after a kill.\nIf the EH code returns Nothing or true, the default engine scoreboard update (score, vehicle kills, infantry kills, etc) is applied, if it returns false, the engine update is cancelled. To add or modify score, use addScore and addScoreSide commands.\nFor remote units like players, the event does not persist after respawn, and must be re-added to the new unit.\n\n**Note:** MP only.\n\n```sqf\nthis addEventHandler [\"HandleScore\", {\n    params [\"_unit\", \"_object\", \"_score\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- object: Object - object for which score was awarded\n- score: Number - score to be added"},{"heading":"Hit","level":4,"markdown":"Local Argument\n\nTriggered when the unit is hit/damaged.\n\nIs *not* always triggered when unit is killed by a hit.\n\nMost of the time only the killed event handler is triggered when a unit dies from a hit.\n\nThe hit EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\n\nDoes not fire when a unit is set to allowDamage false.\n\n```sqf\nthis addEventHandler [\"Hit\", {\n    params [\"_unit\", \"_source\", \"_damage\", \"_instigator\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- source: Object - object that caused the damage – contains *unit* in case of collisions\n- damage: Number - level of damage caused by the hit\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger"},{"heading":"HitPart (Entity)","level":4,"markdown":"Global Argument\n\nTriggered when the object it was added to gets damaged.\nIt returns the position and component that was hit on the object within a nested array, this is because the model may have more than one selection name for the hit component (i.e. a single piece of geometry can be simultaneously part of multiple, overlapping named selections).\n\nWhile you can add \"HitPart\" handler to a remote unit, the respective addEventHandler command must be executed on the shooter's PC and will only fire on shooter's PC as well.\nThe event will not fire if the shooter is not local, even if the target itself is local.\nAdditionally, if the unit gets damaged by any means other than ammunition or explosions, such as fall damage and burning, \"HitPart\" will not fire.\nBecause of this, this event handler is most suitable for when the shooter needs feedback on his shooting, such as target practicing or hitmarker creation.\n\nThis EH returns an array of arrays. Each sub-array contains data for the part that was hit as usually multiple parts are hit at the same time (see HitPart Sample). The structure of the sub-arrays is listed below.\n\n```sqf\nthis addEventHandler [\"HitPart\", {\n    {\n        _x params [\n            \"_target\", \"_shooter\", \"_projectile\", \"_position\", \"_velocity\",\n            \"_selection\", \"_ammo\", \"_vector\", \"_radius\", \"_surfaceType\",\n            \"_isDirect\", \"_instigator\"\n        ];\n    } forEach _this;\n}];\n```\n\n- target: Object - object that was damaged\n- shooter: Object - Unit or vehicle that inflicted the damage. If injured by a vehicle collision, the target itself is returned, or objNull in case of explosions. In case of explosives that were planted by someone (e.g. satchel charges), that unit is returned.\n- projectile: Object - object that was fired\n- position: Array format PositionASL - position the bullet impacted\n- velocity: Vector3D - 3D speed at which the bullet impacted\n- selection: Array - array of Strings with named selection of the object that were hit, in the FireGeometry LOD\n- ammo:\n  - Array in format [hitValue, indirectHitValue, indirectHitRange, explosiveDamage, ammoClassName] - If the damage was directly or indirectly inflicted by a projectile. Hit and damage values are derived from the projectile's CfgAmmo class, and do not match the actual damage inflicted, which is usually lower due to armor and other factors.\n  - Array in format [impulseValue, 0, 0, 0] - if the damage was inflicted by a vehicle collision\n- vector: Vector3D - Vector that is orthogonal (perpendicular) to the surface struck. For example, if a wall was hit, the vector would be pointing out of the wall at a 90 degree angle.\n- radius: Number - radius (size) of component hit\n- surfaceType: String - surface type struck\n- isDirect: Boolean - true if object was directly hit, false if it was hit by indirect / splash damage\n- Arma 3 v2.18 instigator: Object - shot instigator\n\n> [!NOTE]\n> See #HitPart (Projectile) for a similar event handler that is attached to the projectile instead of the entity.\n\n> [!NOTE]\n> This event does not fire when miniscule explosive damage is dealt to the target entity, but the Explosion event will still fire."},{"heading":"IncomingMissile","level":4,"markdown":"Global Argument\n\nTriggered when a unit fires a missile or rocket at the target. For projectiles fired by players this EH only triggers for guided missiles that have locked onto the target.\n\n```sqf\nthis addEventHandler [\"IncomingMissile\", {\n    params [\"_target\", \"_ammo\", \"_vehicle\", \"_instigator\", \"_missile\"];\n}];\n```\n\n- target: Object - object the event handler is assigned to\n- ammo: String - ammo type that was fired on the target\n- Arma 3 v1.42 vehicle: Object - vehicle that fired the weapon. In case of soldier, unit is returned\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v2.10 missile: Object - the incoming missile"},{"heading":"Init (Entity)","level":4,"markdown":"Global Argument\n\nTriggered whenever an entity is created. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n> [!IMPORTANT]\n> It is recommended to use the #PostInit event handler instead of this one when setting entity textures (setObjectTexture, BIS_fnc_initVehicle etc) to avoid networking issues.\n\ne.g:\n\n```cpp\ninit = \"params ['_entity'];\";\n```\n\n```sqf\nparams [\"_entity\"];\n```\n\n- entity: Object - object the event handler is assigned to"},{"heading":"InventoryClosed (Arma 3 v1.22)","level":4,"markdown":"Global Argument\n\nTriggered when the unit closes inventory. Said unit can be non-local when adding the EH, but **must** be local for the EH to trigger.\n\n```sqf\nthis addEventHandler [\"InventoryClosed\", {\n    params [\"_unit\", \"_container\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- container: Object - connected container or weaponholder\n\n```sqf\n// Delete dropped items when inventory closed\nplayer addEventHandler [\"InventoryClosed\", {\n    params [\"_unit\", \"_container\"];\n    if (_container isKindOf \"WeaponHolder\") then\n    {\n        deleteVehicle _container;\n    };\n}];\n```"},{"heading":"InventoryOpened (Arma 3 v1.22)","level":4,"markdown":"Global Argument\n\nTriggered when unit opens inventory. Said unit can be non-local when adding the EH, but **must** be local for the EH to trigger. End EH main scope with true to override the opening of the inventory in case you wish to handle it yourself:\n\n```sqf\n// Create and open an ammo box when \"Inventory\" button is pressed\nplayer addEventHandler [\"InventoryOpened\", {\n    player removeAllEventHandlers \"InventoryOpened\";\n    _box = \"Box_NATO_Ammo_F\" createVehicle [0,0,0];\n    _box setPosASL (player modelToWorldVisualWorld [0,1.5,0.5]);\n    player action [\"Gear\", _box];\n    true; // <-- inventory override\n}];\n```\n\nTo return all nearby containers use nearSupplies command.\n\n```sqf\nthis addEventHandler [\"InventoryOpened\", {\n    params [\"_unit\", \"_primaryContainer\", \"_secondaryContainer\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- primaryContainer: Object - connected container or weaponholder\n- Arma 3 v1.66 secondaryContainer: Object - second connected container or weaponholder or objNull"},{"heading":"Killed","level":4,"markdown":"Local Argument\n\nTriggered when the unit is killed.\n\n```sqf\nthis addEventHandler [\"Killed\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\", \"_shot\", \"_real\"];\n}];\n```\n\n- unit: Object - the object the event handler is assigned to\n- killer: Object - the object that killed the unit. Contains the unit itself in case of collisions.\n- Arma 3 v1.66 instigator: Object - the person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n- Arma 3 v2.22 shot: Object - shot that caused damage\n- Arma 3 v2.22 real: Boolean - true when the shot was 'real' where the event handler triggered"},{"heading":"LandedStopped","level":4,"markdown":"Global Argument\n\nTriggered when an AI pilot would get out usually. Not executed for player.\n\n```sqf\nthis addEventHandler [\"LandedStopped\", {\n    params [\"_plane\", \"_airportID\", \"_airportObject\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number - ID of the airport (-1 for anything else)\n- Arma 3 v2.12 airportObject: Object - airport object in the event of a Dynamic Airport, otherwise objNull"},{"heading":"LandedTouchDown","level":4,"markdown":"Global Argument\n\nTriggered when a plane (AI or player) touches the ground.\n\n```sqf\nthis addEventHandler [\"LandedTouchDown\", {\n    params [\"_plane\", \"_airportID\", \"_airportObject\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number - ID of the airport (-1 for anything else)\n- Arma 3 v2.12 airportObject: Object - airport object in the event of a Dynamic Airport, otherwise objNull"},{"heading":"Landing (Arma 3 v1.70)","level":4,"markdown":"Global Argument\n\nTriggered when an AI pilot (or auto-pilot) is preparing for landing. The exact moment of triggering coincides with lowering of the gear (\"Gear\" EH)\n\n```sqf\nthis addEventHandler [\"Landing\", {\n    params [\"_plane\", \"_airportID\", \"_isCarrier\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number or Object - ID of the airport or aircraft carrier object\n- isCarrier: Boolean - true if landing on aircraft carrier"},{"heading":"LandingCanceled (Arma 3 v1.70)","level":4,"markdown":"Global Argument\n\nTriggered when AI pilot landing is cancelled (for example new order received to land elsewhere).\nThe exact moment of triggering coincides with retracting of the gear (\"Gear\" EH).\n\n**Note**: Does not trigger if player switches off auto-pilot. Canceled is spelled with one `L`\n\n```sqf\nthis addEventHandler [\"LandingCanceled\", {\n    params [\"_plane\", \"_airportID\", \"_isCarrier\"];\n}];\n```\n\n- plane: Object - object the event handler is assigned to\n- airportID: Number or Object - ID of the airport or aircraft carrier object (-1 no airport)\n- isCarrier: Boolean - true if landing on aircraft carrier"},{"heading":"LaserTargetChanged (Arma 3 v2.22)","level":4,"markdown":"Triggered when the laser target changes.\n\n```sqf\nthis addEventHandler [\"LaserTargetChanged\", {\n    params [\"_unit\", \"_laserTarget\", \"_designatedTarget\", \"_turretPath\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- laserTarget: Object - the laser target entity that got created at impact point\n- designatedTarget: Object - the object that is targeted by the laser\n- turretPath: Turret Path - the path to the turret that activated the laser. It is empty when the event is triggered by a unit"},{"heading":"LeaningChanged (Arma 3 v2.18)","level":4,"markdown":"Global Argument\n\nTriggered when a soldier leaning factor is changed between -1 (extreme left), 0 (not leaning) and 1 (extreme right)\n\n```sqf\nthis addEventHandler [\"LeaningChanged\", {\n    params [\"_unit\", \"_newLeaning\", \"_oldLeaning\"];\n}];\n```\n\n- unit: Object - soldier\n- newLeaning: Number from -1 to 1\n- oldLeaning: Number from -1 to 1"},{"heading":"Local (Entity)","level":4,"markdown":"Global Argument\n\nTriggers when locality of object in MP is changed. The event handler only triggers on the computers that are directly involved in change of locality.\nSo if EH is added to every computer on network, it will only trigger on 2 computers, on the computer that receives ownership of the object (new owner), in which case _this select 1 will be true,\nand on the computer from which ownership is transferred (old owner), in which case _this select 1 will be false.\n\n```sqf\nthis addEventHandler [\"Local\", {\n    params [\"_entity\", \"_isLocal\"];\n}];\n```\n\n- entity: Object - the object that changed locality\n- isLocal: Boolean - if the object is local on given computer"},{"heading":"MagazineReloading (Arma 3 v2.18)","level":4,"markdown":"Local Argument\n\nTriggers when reloading starts.\n\n```sqf\nthis addEventHandler [\"MagazineReloading\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_magazine\", \"_magazineClass\", \"_ammoCount\", \"_magazineID\", \"_magazineCreator\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got unloaded\n- muzzle: String - weapon's muzzle that got unloaded\n- magazine: Array - magazine info in format [magazineClass, ammoCount, magazineID, magazineCreator], where:\n  - magazineClass: String - class name of the magazine\n  - ammoCount: Number - amount of ammo in magazine\n  - magazineID: Number - global magazine id\n  - magazineCreator: Number - owner of the magazine creator"},{"heading":"MagazineUnloaded (Arma 3 v2.18)","level":4,"markdown":"Local Argument\n\nTriggers when a magazine is removed from a weapon manually or via script.\n\n```sqf\nthis addEventHandler [\"MagazineUnloaded\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_magazine\", \"_magazineClass\", \"_ammoCount\", \"_magazineID\", \"_magazineCreator\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got unloaded\n- muzzle: String - weapon's muzzle that got unloaded\n- magazine: Array - magazine info in format [magazineClass, ammoCount, magazineID, magazineCreator], where:\n  - magazineClass: String - class name of the magazine\n  - ammoCount: Number - amount of ammo in magazine\n  - magazineID: Number - global magazine id\n  - magazineCreator: Number - owner of the magazine creator"},{"heading":"OpticsModeChanged (Arma 3 v2.10)","level":4,"markdown":"Local Argument\n\nTriggers everytime a local unit changes optic mode. This could be either through the setOpticsMode command or by the player switching to the next optic mode using e.g <kbd>NUM /</kbd> or <kbd>Ctrl</kbd>+<kbd>RMB</kbd>.\n\n```sqf\nthis addEventHandler [\"OpticsModeChanged\", {\n    params [\"_unit\", \"_opticsClass\", \"_newMode\", \"_oldMode\", \"_isADS\"];\n}];\n```\n\n- unit: Object - the unit\n- opticsClass: String\n- newMode: String\n- oldMode: String\n- isADS: Boolean - if the new view is GUNNER"},{"heading":"OpticsSwitch (Arma 3 v2.10)","level":4,"markdown":"Local Argument\n\nTriggers at the start of the camera transition from GUNNER to INTERNAL/EXTERNAL and vice-versa.\nSo anytime the right mouse button is pressed and there is a GUNNER view available or are currently in it, this triggers.\nWorks in vehicles and FFV as well. See also cameraView.\n\n```sqf\nthis addEventHandler [\"OpticsSwitch\", {\n    params [\"_unit\", \"_isADS\"];\n}];\n```\n\n- unit: Object - the unit\n- isADS: Boolean - if the new view is GUNNER"},{"heading":"PathCalculated (Arma 3 v1.94)","level":4,"markdown":"Local Argument\n\nTriggers when a path has been calculated for the unit. Works for both agents and normal AI units.\n\nNote that paths to far destinations are typically calculated in segments.\nWhen the unit completes a segment, a new path is calculated and this is continued until the unit reaches its destination.\n\n```sqf\nthis addEventHandler [\"PathCalculated\", {\n    params [\"_unit\", \"_path\"];\n}];\n```\n\n- unit: Object - the unit/agent for which the path was calculated\n- path: Array - the array of positions representing the path (PositionASL)"},{"heading":"PeriscopeElevationChanged (Arma 3 v2.00)","level":4,"markdown":"Fires every frame during periscope elevation animation.\n\n```sqf\nthis addEventHandler [\"PeriscopeElevationChanged\", {\n    params [\"_vehicle\", \"_turret\", \"_elevation\", \"_direction\", \"_userIsBlocked\"];\n}];\n```\n\n- vehicle: Object - the vehicle this EH is assigned to\n- turret: Array - the turret which periscope is changing elevation\n- elevation: Number - current periscope elevation (changes with each simulation). See also periscopeElevation, elevatePeriscope\n- direction: Number - 1: moves up, 0: stopped, -1: moves down; when `direction` returns 0, this also means the event handler fired for the last time for this elevation.\n- userIsBlocked: Boolean - whether or not the user ability to override is blocked. See also periscopeElevation, elevatePeriscope"},{"heading":"PostInit (Arma 3 v2.06)","level":4,"markdown":"Global Argument\n\nTriggered whenever an entity is created and initialized. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n> [!IMPORTANT]\n> It is recommended to use this event handler instead of the #Init one when setting entity textures (setObjectTexture, BIS_fnc_initVehicle etc) to avoid networking issues.\n\ne.g:\n\n```cpp\npostInit = \"params ['_entity'];\";\n```\n\n```cpp\npostinit = \"params ['_entity']; if (local _entity) then { [_entity, '', [], false] call BIS_fnc_initVehicle };\";\n```\n\n```sqf\nparams [\"_entity\"];\n```\n\n- entity: Object - object the event handler is assigned to"},{"heading":"PostReset","level":4,"markdown":"**Obsolete** - triggers after PP effects have been reset by the engine."},{"heading":"Put (Arma 3 v0.56)","level":4,"markdown":"Global Argument\n\nTriggers when a unit puts an item in a container.\n\nArma 3 v2.14 This event handler can be added to a container.\n\n```sqf\nthis addEventHandler [\"Put\", {\n    params [\"_unit\", \"_container\", \"_item\"];\n}];\n```\n\n- unit: Object - unit who put the item in the container\n- container: Object - the container into which the item was placed (vehicle, box, etc.)\n- item: String - the class name of the moved item\n\n> [!NOTE]\n> This EH could also trigger when unit replaces magazine in weapon with another magazine from unit containers (uniform, vest, backpack) during reload."},{"heading":"PylonChanged (Arma 3 v2.20)","level":4,"markdown":"Local Argument\n\nTriggers when an aircraft's pylon changes magazine type:\n\n```sqf\nvehicle player addEventHandler [\"PylonChanged\", {\n    params [\"_vehicle\", \"_pylonIndex\", \"_oldMagazine\", \"_newMagazine\"];\n}];\n```\n\n- vehicle: Object\n- pylonIndex: Number\n- oldMagazine: String\n- newMagazine: String\n\n> [!IMPORTANT]\n> This event generally triggers **twice** for a swap, first unload then load, e.g:\n>\n> ```sqf\n> // [myVehicle, 1, \"oldMagClass\", \"\"]\n> // [myVehicle, 1, \"\", \"newMagClass\"]\n> ```"},{"heading":"Reloaded (Arma 3 v1.58)","level":4,"markdown":"Local Argument\n\nTriggers once a weapon is reloaded with a new magazine. For more information, see Reloaded.\n\n```sqf\nthis addEventHandler [\"Reloaded\", {\n    params [\"_unit\", \"_weapon\", \"_muzzle\", \"_newMagazine\", \"_oldMagazine\"];\n}];\n```\n\n- unit: Object - unit or vehicle to which EH is assigned\n- weapon: String - weapon that got reloaded\n- muzzle: String - weapon's muzzle that got reloaded\n- newMagazine: Array - new magazine info\n- oldMagazine: Array or Nothing - old magazine info"},{"heading":"Respawn","level":4,"markdown":"Local Argument\n\nTriggered when a unit respawns.\n\n```sqf\nthis addEventHandler [\"Respawn\", {\n    params [\"_unit\", \"_corpse\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- corpse: Object - object the event handler was assigned to, aka the corpse/unit player was previously controlling"},{"heading":"RopeAttach (Arma 3 v1.34)","level":4,"markdown":"Triggered when a rope is attached to an object.\n\nIn the case of sling loading, this event handler must be assigned to the helicopter and will trigger for each attached rope.\n\n```sqf\nthis addEventHandler [\"RopeAttach\", {\n    params [\"_object1\", \"_rope\", \"_object2\"];\n}];\n```\n\n- object1: Object - object to which the event handler is assigned.\n- rope: Object - the rope being attached between object 1 and object 2.\n- object2: Object - the object that is being attached to object 1 via rope."},{"heading":"RopeBreak (Arma 3 v1.34)","level":4,"markdown":"Triggered when a rope is detached from an object.\n\nIn the case of sling loading, this event handler must be assigned to the helicopter and will trigger for each detached rope.\n\n```sqf\nthis addEventHandler [\"RopeBreak\", {\n    params [\"_object1\", \"_rope\", \"_object2\"];\n}];\n```\n\n- object1: Object - object to which the event handler is assigned.\n- rope: Object - the rope that connected object 1 and object 2.\n- object2: Object - the object that was connected to object 1 with a rope."},{"heading":"SeatSwitched (Arma 3 v1.50)","level":4,"markdown":"Global Argument\n\nTriggered when unit changes seat within vehicle. EH returns both units switching seats.\nIf switching seats with an empty seat, one of the returned units will be objNull.\nThe new position can be obtained with assignedVehicleRole.\nThis EH must be assigned to a vehicle.\n\n```sqf\nthis addEventHandler [\"SeatSwitched\", {\n    params [\"_vehicle\", \"_unit1\", \"_unit2\"];\n}];\n```\n\n- vehicle: Object - vehicle to which the event handler is assigned.\n- unit1: Object - unit switching seat.\n- unit2: Object - unit switching seat."},{"heading":"SeatSwitchedMan (Arma 3 v1.58)","level":4,"markdown":"Global Argument\n\nTriggered when unit changes seat within vehicle. EH returns both units switching seats.\nIf switching seats with an empty seat, one of the returned units will be objNull.\nThe new position can be obtained with assignedVehicleRole <unit>. This EH must be assigned to a unit and not a vehicle.\nThis EH is persistent and will be transferred to the new unit after respawn, but only if it was assigned where unit was local.\n\n```sqf\nthis addEventHandler [\"SeatSwitchedMan\", {\n    params [\"_unit1\", \"_unit2\", \"_vehicle\"];\n}];\n```\n\n- unit1: Object - unit switching seat.\n- unit2: Object - unit with which unit1 is switching seat.\n- vehicle: Object - vehicle where switching seats is taking place."},{"heading":"SelectedActionChanged","level":4,"markdown":"RTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality."},{"heading":"SelectedActionPerformed","level":4,"markdown":"RTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality."},{"heading":"SelectedRotorLibActionChanged","level":4,"markdown":"RTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedRotorLibActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality."},{"heading":"SelectedRotorLibActionPerformed","level":4,"markdown":"RTM helicopter user action event\n\n```sqf\nthis addEventHandler [\"SelectedRotorLibActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Works only for key press combination <kbd>RCtrl</kbd>+<kbd>W</kbd>, which is the binding for helicopter wheels brakes.\n> It fires with or without Advanced Flight Model enabled. The enum number returned is 4 and 5, probably because the enum is structured like this:\n> - 0: HelicopterAutoTrimOn\n> - 1: HelicopterAutoTrimOff\n> - 2: HelicopterTrimOn\n> - 3: HelicopterTrimOff\n> - 4: WheelsBrakeOn\n> - 5: WheelsBrakeOff"},{"heading":"SlotItemChanged (Arma 3 v2.14)","level":4,"markdown":"Global Argument\n\nTriggered when any of the following slots get assigned or unassigned: *Items* - Map, GPS, Radio, Watch, Compass, Helmet, Goggles, NVG; *Weapon* - Binoculars; *Containers* - Uniform, Vest, Backpack.\n\n```sqf\nthis addEventHandler [\"SlotItemChanged\", {\n    params [\"_unit\", \"_name\", \"_slot\", \"_assigned\", \"_weapon\"];\n}];\n```\n\n- unit: Object - unit EH assigned to.\n- name: String - name of the item/weapon/container (see getSlotItemName).\n- slot: Number - slot id (see getSlotItemName).\n- assigned: Boolean - true assign action, false unassign action.\n- Arma 3 v2.18 weapon: String - name of weapon in event that slot changed is a weapon attachment slot"},{"heading":"SoundPlayed (Arma 3 v0.56)","level":4,"markdown":"Local Argument\n\nTriggered when player is making noises when injured or fatigued for example. The number param passed to the EH code points to the sound origin:\n1. Breath\n1. Breath Injured\n1. Breath Scuba\n1. Injured\n1. Pulsation\n1. Hit Scream\n1. Burning\n1. Drowning\n1. Drown\n1. Gasping\n1. Stabilizing\n1. Healing\n1. Healing With Medikit\n1. Recovered\n1. Breath Held\n\n```sqf\nthis addEventHandler [\"SoundPlayed\", {\n    params [\"_unit\", \"_soundID\"];\n}];\n```\n\n- unit: Object - unit to which the event handler is assigned\n- soundID: Number - sound origin\n\n> [!NOTE]\n> Since Arma 3 v2.12 returning a Number from last added EH in range from 0 to 5 will alter the volume of played sound from mute to max volume."},{"heading":"Suppressed (Arma 3 v2.02)","level":4,"markdown":"Local Argument\n\nTriggers when enemy projectile is passing by closer than defined suppression radius ammo value in config.\nCan be made to trigger for the same side if the side is set as enemy to itself (with setFriend). For more information see Arma 3: Suppression.\n\n```sqf\nthis addEventHandler [\"Suppressed\", {\n    params [\"_unit\", \"_distance\", \"_shooter\", \"_instigator\", \"_ammoObject\", \"_ammoClassName\", \"_ammoConfig\"];\n}];\n```\n\n- unit: Object - unit to which the event is assigned\n- distance: Number - distance of the projectile pass-by\n- shooter: Object - who (or what) fired - vehicle or drone\n- instigator: Object - who pressed the trigger. Instigator is different from the shooter when player is operator of UAV for example\n- ammoObject: Object - the ammunition itself\n- ammoClassName: String - the ammunition's classname\n- ammoConfig: Config - the ammunition's CfgAmmo config path"},{"heading":"Take (Arma 3 v0.56)","level":4,"markdown":"Global Argument\n\nTriggers when a unit takes an item from a container.\n\nArma 3 v2.14 This event handler can be added to a container.\n\n```sqf\nthis addEventHandler [\"Take\", {\n    params [\"_unit\", \"_container\", \"_item\"];\n}];\n```\n\n- unit: Object - unit who took the item from the container\n- container: Object - the container from which the item was taken (vehicle, box, etc.)\n- item: String - the class name of the taken item\n\n> [!NOTE]\n> This EH could also trigger when unit replaces magazine in weapon with another magazine from unit containers (uniform, vest, backpack) during reload."},{"heading":"TaskSetAsCurrent (Arma 3 v1.32)","level":4,"markdown":"Triggers when player's current task changes\n\n```sqf\nthis addEventHandler [\"TaskSetAsCurrent\", {\n    params [\"_unit\", \"_task\"];\n}];\n```\n\n- unit: Object - the player to whom the event handler is assigned\n- task: Task - the new current task"},{"heading":"TurnIn (Arma 3 v1.66)","level":4,"markdown":"Triggers when member of crew in a vehicle uses Turn In action\n\n```sqf\nthis addEventHandler [\"TurnIn\", {\n    params [\"_vehicle\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - the vehicle the event handler is assigned to\n- unit: Object - the unit performing the Turn In action\n- turret: Array - turret path"},{"heading":"TurnOut (Arma 3 v1.66)","level":4,"markdown":"Triggers when member of crew in a vehicle uses Turn Out action\n\n```sqf\nthis addEventHandler [\"TurnOut\", {\n    params [\"_vehicle\", \"_unit\", \"_turret\"];\n}];\n```\n\n- vehicle: Object - the vehicle the event handler is assigned to\n- unit: Object - the unit performing the Turn Out action\n- turret: Array - turret path"},{"heading":"VisionModeChanged (Arma 3 v2.08)","level":4,"markdown":"Triggers when the assigned vehicle/unit's vision mode has changed.\n\n```sqf\nplayer addEventHandler [\"VisionModeChanged\", {\n    params [\"_person\", \"_visionMode\", \"_TIindex\", \"_visionModePrev\", \"_TIindexPrev\", \"_vehicle\", \"_turret\"];\n}];\n```\n\n- person: Object - unit for whom the vision mode changes\n- visionMode: Number - vision mode index\n- TIindex: Number - thermal vision mode index; will return -1 when *visionMode* is not 2\n- visionModePrev: Number - last vision mode\n- TIindexPrev: Number - last TI mode; will return -1 when *visionModePrev* is not 2\n- vehicle: Object - if unit is in a vehicle or controlling a UAV, this will be the vehicle\n- turret: Array - turret path to the turret occupied by the unit, or [] if not on turret"},{"heading":"WeaponAssembled","level":4,"markdown":"Global Argument\n\nTriggers when a weapon gets assembled. EH must be attached to the unit and not the weapon.\n\n```sqf\nthis addEventHandler [\"WeaponAssembled\", {\n    params [\"_unit\", \"_weapon\", \"_primaryBag\", \"_secondaryBag\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- weapon: Object - object of the assembled weapon\n- Arma 3 v2.18 primaryBag: Object - primary bag (just before it is deleted)\n- Arma 3 v2.18 secondaryBag: Object - secondary bag (just before it is deleted)"},{"heading":"WeaponChanged (Arma 3 v2.18)","level":4,"markdown":"Fires on weapon switch and firemode switch. Does not fire for player units inside vehicles (but does fire for vehicles with players in them).\n\nThe locality is unknown, but it is known that this EH behaves like currentWeapon, currentWeaponMode and currentMuzzle in terms of locality.\n\nArma 3 v2.22 Fires for \"Throw\" muzzle changes too.\n\n```sqf\nthis addEventHandler [\"WeaponChanged\", {\n    params [\"_object\", \"_oldWeapon\", \"_newWeapon\", \"_oldMode\", \"_newMode\", \"_oldMuzzle\", \"_newMuzzle\", \"_turretIndex\"];\n}];\n```\n\n- object: Object - the unit or vehicle the event handler is assigned to\n- oldWeapon: String - the class name of the previous weapon\n- newWeapon: String - the class name of the new weapon (same as currentWeapon)\n- oldMode: String - the previous weapon mode\n- newMode: String - the new weapon mode (same as currentWeaponMode)\n- oldMuzzle: String - the previous weapon muzzle\n- newMuzzle: String - the new weapon muzzle (same as currentMuzzle)\n- turretIndex: Array format Turret Path - the turret path, or empty array if `object` is not a transport vehicle"},{"heading":"WeaponDeployed (Arma 3 v1.44)","level":4,"markdown":"Global Argument\n\nTriggers when the deployed state of a weapon or bipod changes.\n\n**Note:** A weapon cannot be rested and deployed at the same time.\n\n```sqf\nthis addEventHandler [\"WeaponDeployed\", {\n    params [\"_unit\", \"_isDeployed\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- isDeployed: Boolean - true if deployed"},{"heading":"WeaponDisassembled","level":4,"markdown":"Global Argument\n\nTriggers when a weapon gets disassembled. EH must be attached to the unit and not the weapon.\n\n**Note:** As of Arma 3 v1.32, this event does not fire if the weapon is not local.\n\n```sqf\nthis addEventHandler [\"WeaponDisassembled\", {\n    params [\"_unit\", \"_primaryBag\", \"_secondaryBag\", \"_weapon\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- primaryBag: Object - first backpack object which was weapon disassembled into\n- secondaryBag: Object - second backpack object which was weapon disassembled into\n- Arma 3 v2.18 weapon: Object - disassembled weapon (just before it is moved out of the world)"},{"heading":"WeaponRested (Arma 3 v1.44)","level":4,"markdown":"Local Argument\n\nTriggers when weapon rested state changes (weapon near a surface that can provide weapon support).\n\n**Note:** A weapon cannot be rested and deployed at the same time.\n\n```sqf\nthis addEventHandler [\"WeaponRested\", {\n    params [\"_unit\", \"_isRested\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- isRested: Boolean - true if rested"},{"heading":"Multiplayer Event Handlers","level":3,"markdown":"Global object event handler, executed on every connected machine.\n\nCommands:\n- addMPEventHandler\n- removeMPEventHandler\n- removeAllMPEventHandlers\n\n> [!IMPORTANT]\n> A Multiplayer Event Handler is **not** saved in a save file and therefore will not be restored on load - use it accordingly."},{"heading":"MPHit","level":4,"markdown":"Global ArgumentGlobal Effect\n\nTriggered when the unit is hit/damaged. EH can be added on any machine and EH code will trigger globally on every connected client and server.\nThis EH is clever enough to be triggered globally only once even if added on all clients or a single client that is then disconnected, EH will still trigger globally only once.\n\nIs *not* always triggered when unit is killed by a hit.\nMost of the time only the killed event handler is triggered when a unit dies from a hit.\nThe hit EH will not necessarily fire if only minor damage occurred (e.g. firing a bullet at a tank), even though the damage increased.\nCan also trigger several times for an explosion (direct and indirect damage). Does not fire when a unit is set to allowDamage false.\nHowever it will fire with \"HandleDamage\" EH added alongside stopping unit from taking damage (`unit addEventHandler [\"HandleDamage\", { 0 }];`.\nWill not trigger once the unit is dead.\n\n**Note:** call a function from the MPHit EH code space rather than defining the full code in there directly.\nThe reason is the code space will be transferred over network on each event activation - so keep the data as small as possible!\n\n```sqf\nthis addMPEventHandler [\"MPHit\", {\n    params [\"_unit\", \"_causedBy\", \"_damage\", \"_instigator\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n\n- causedBy: Object - object that caused the damage. Contains the unit itself in case of collisions.\n\n- damage: Number - level of damage caused by the hit\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger"},{"heading":"MPKilled","level":4,"markdown":"Global ArgumentGlobal Effect\n\nTriggered when the unit is killed. EH can be added on any machine and EH code will trigger globally **on every connected client and server**.\nThis EH has a safeguard measure so that even if it's added on all clients or a single client that is then disconnected, EH will still trigger globally only once per client.\n\n```sqf\nthis addMPEventHandler [\"MPKilled\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- killer: Object - object that killed the unit. Contains the unit itself in case of collisions\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax"},{"heading":"MPRespawn","level":4,"markdown":"Global ArgumentLocal Effect\n\nTriggered when a unit, it is assigned to, respawns. This EH does not work as one would expect MP EH should work like.\nIt is only triggered on one machine where the unit it was assigned to is local.\nThe only difference between **Respawn** and **MPRespawn** is that **MPRespawn** can be assigned from anywhere while **Respawn** requires the unit to be local.\n\nMPRespawn EH expects the EH code to return an array in Position format which will be used to place the respawned unit at the desired coordinates.\n\nFor example: `player addMPEventHandler [\"MPRespawn\", { [1234, 1234, 0] }];` will place player at [1234,1234,0] immediately on respawn.\n\n```sqf\nthis addMPEventHandler [\"MPRespawn\", {\n    params [\"_unit\", \"_corpse\"];\n}];\n```\n\n- unit: Object - object the event handler is assigned to\n- corpse: Object - object the event handler was assigned to, aka the corpse/unit player was previously controlling."},{"heading":"Mission Event Handlers","level":3,"markdown":"Mission Event Handlers are specific EHs that are anchored to the running mission and automatically removed when mission is over.\n\nCommands:\n- addMissionEventHandler\n- removeMissionEventHandler\n\n> [!NOTE]\n> See Arma 3: Mission Event Handlers."},{"heading":"Curator Event Handlers (Arma 3 v1.16)","level":3,"markdown":"Local ArgumentLocal Effect\n\nArma 3: Curator Event Handlers are also added with the addEventHandler command. They are executed only where the curator is local - on the machine that is in control of it.\n\n> [!IMPORTANT]\n> These Event Handlers must be added to the curator object/module, **not** the player!\n\nCommands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers"},{"heading":"CuratorFeedbackMessage","level":4,"markdown":"Local Argument\n\nTriggered when curator attempts invalid action in curator interface.\n\nEach error has its own unique ID, recognized values are:\n\n- 003 - when trying to teleport camera outside of curatorCameraArea\n- 101 - trying to place an object when placing is disabled using setCuratorCoef \"place\"\n- 102 - trying to place an object which is too expensive (cost set in *curatorObjectRegistered* multiplied by setCuratorCoef \"place\" is larger than curatorPoints)\n- 103 - trying to place an object outside of curatorEditingArea\n- 104 - items of a placed composition were skipped / could not be placed (since Arma 3 v2.06)\n- 201 - trying to place a waypoint when waypoint placing is disabled\n- 202 - trying to place a waypoint which is too expensive (cost set by setCuratorWaypointCost multiplied by setCuratorCoef \"place\" is larger than curatorPoints)\n- 206 - trying to place a waypoint when no AI unit is selected\n- 301 - trying to move or rotate an entity when editing is disabled using setCuratorCoef \"edit\"\n- 302 - trying to move or rotate an entity when it is too expensive (entity cost multiplied by setCuratorCoef \"edit\" is larger than curatorPoints)\n- 303 - trying to move an entity outside of curatorEditingArea\n- 304 - trying to move or rotate an entity which is outside of curatorEditingArea\n- 307 - trying to move or rotate a player (players cannot be manipulated with)\n- 401 - trying to delete an entity when deleting is disabled using setCuratorCoef \"delete\"\n- 402 - trying to delete an entity which is too expensive (cost multiplied by setCuratorCoef \"delete\" is larger than curatorPoints)\n- 404 - trying to delete an entity which is outside of curatorEditingArea\n- 405 - trying to delete an entity which has non-editable crew in it\n- 407 - trying to delete a player (players cannot be manipulated with)\n- 501 - trying to destroy an object when destroying is disabled using setCuratorCoef \"destroy\"\n- 502 - trying to destroy an object which is too expensive (cost multiplied by setCuratorCoef \"destroy\" is larger than curatorPoints)\n- 504 - trying to destroy an object which is outside of curatorEditingArea\n- 505 - trying to destroy an object which has non-editable crew in it\n- 506 - trying to destroy an object when no object is selected\n- 507 - trying to destroy a player (players cannot be manipulated with)\n\n```sqf\nthis addEventHandler [\"CuratorFeedbackMessage\", {\n    params [\"_curator\", \"_errorID\"];\n}];\n```\n\n- curator: Object\n- errorID: Number"},{"heading":"CuratorGroupDoubleClicked","level":4,"markdown":"Local Argument\n\nTriggered when a group is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupDoubleClicked\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group"},{"heading":"CuratorGroupPlaced","level":4,"markdown":"Local Argument\n\nTriggered when new group is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupPlaced\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group"},{"heading":"CuratorGroupSelectionChanged","level":4,"markdown":"Local Argument\n\nTriggered when a group is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorGroupSelectionChanged\", {\n    params [\"_curator\", \"_group\"];\n}];\n```\n\n- curator: Object\n- group: Group"},{"heading":"CuratorMarkerDeleted","level":4,"markdown":"Local Argument\n\nTriggered when a marker is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerDeleted\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String"},{"heading":"CuratorMarkerDoubleClicked","level":4,"markdown":"Local Argument\n\nTriggered when a marker is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerDoubleClicked\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String"},{"heading":"CuratorMarkerEdited","level":4,"markdown":"Local Argument\n\nTriggered when a marker is moved in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerEdited\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String"},{"heading":"CuratorMarkerPlaced","level":4,"markdown":"Local Argument\n\nTriggered when new marker is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerPlaced\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String"},{"heading":"CuratorMarkerSelectionChanged","level":4,"markdown":"Local Argument\n\nTriggered when a marker is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorMarkerSelectionChanged\", {\n    params [\"_curator\", \"_marker\"];\n}];\n```\n\n- curator: Object\n- marker: String"},{"heading":"CuratorObjectDeleted","level":4,"markdown":"Local Argument\n\nTriggered when an object is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectDeleted\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object"},{"heading":"CuratorObjectDoubleClicked","level":4,"markdown":"Local Argument\n\nTriggered when an object is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectDoubleClicked\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object"},{"heading":"CuratorObjectEdited","level":4,"markdown":"Local Argument\n\nTriggered when an object is moved or rotated in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectEdited\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object"},{"heading":"CuratorObjectPlaced","level":4,"markdown":"Local Argument\n\nTriggered when new object is placed in curator interface.\nThis event handler will trigger individually for each unit in a placed group - excluding the crew in vehicles.\n\n```sqf\nthis addEventHandler [\"CuratorObjectPlaced\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object"},{"heading":"CuratorObjectRegistered","level":4,"markdown":"Local Argument\n\nTriggered when player enters curator interface. Assign curator cost to every object in the game.\nThis is the primary method that a mission designer can use to limit the objects a curator can place.\n\n> [!NOTE]\n> See Curator#Manual Assigning.\n\n```sqf\nthis addEventHandler [\"CuratorObjectRegistered\", {\n    params [\"_curator\", \"_input\"];\n}];\n```\n\n- curator: Object\n- input: Array of Strings - all CfgVehicles classes"},{"heading":"CuratorObjectSelectionChanged","level":4,"markdown":"Local Argument\n\nTriggered when an object is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorObjectSelectionChanged\", {\n    params [\"_curator\", \"_entity\"];\n}];\n```\n\n- curator: Object\n- entity: Object"},{"heading":"CuratorPinged","level":4,"markdown":"Local Argument\n\nTriggered when a player pings his curator(s) by pressing the *Zeus* key.\n\n```sqf\nthis addEventHandler [\"CuratorPinged\", {\n    params [\"_curator\", \"_player\"];\n}];\n```\n\n- curator: Object\n- player: Object"},{"heading":"CuratorSelectionPresetLoaded (Arma 3 v2.14)","level":4,"markdown":"Local Argument\n\nTriggered when a selection preset is loaded using the respective number key or through script.\n\n```sqf\nthis addEventHandler [\"CuratorSelectionPresetLoaded\", {\n    params [\"_curator\", \"_numkey\"];\n}];\n```\n\n- curator: Object\n- numkey: Number"},{"heading":"CuratorSelectionPresetSaved (Arma 3 v2.14)","level":4,"markdown":"Local Argument\n\nTriggered when a selection preset is saved using the respective CTRL + number key or set through script.\n\n```sqf\nthis addEventHandler [\"CuratorSelectionPresetSaved\", {\n    params [\"_curator\", \"_numkey\"];\n}];\n```\n\n- curator: Object\n- numkey: Number"},{"heading":"CuratorWaypointDeleted","level":4,"markdown":"Local Argument\n\nTriggered when a waypoint is deleted in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointDeleted\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array"},{"heading":"CuratorWaypointDoubleClicked","level":4,"markdown":"Local Argument\n\nTriggered when a waypoint is double-clicked on in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointDoubleClicked\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array"},{"heading":"CuratorWaypointEdited","level":4,"markdown":"Local Argument\n\nTriggered when a waypoint is moved in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointEdited\", {\n    params [\"_curator\", \"_group\", \"_waypointID\"];\n}];\n```\n\n- curator: Object\n- group: Group\n- waypointID: Number"},{"heading":"CuratorWaypointPlaced","level":4,"markdown":"Local Argument\n\nTriggered when new waypoint is placed in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointPlaced\", {\n    params [\"_curator\", \"_group\", \"_waypointID\"];\n}];\n```\n\n- curator: Object\n- group: Group\n- waypointID: Number"},{"heading":"CuratorWaypointSelectionChanged","level":4,"markdown":"Local Argument\n\nTriggered when a waypoint is selected in curator interface.\n\n```sqf\nthis addEventHandler [\"CuratorWaypointSelectionChanged\", {\n    params [\"_curator\", \"_waypoint\"];\n}];\n```\n\n- curator: Object\n- waypoint: Array"},{"heading":"UserAction Event Handlers (Arma 3 v2.06)","level":3,"markdown":"UserAction Event Handlers are events that trigger on user action.\n\nCommands:\n- addUserActionEventHandler\n- removeUserActionEventHandler\n\n> [!NOTE]\n> See Arma 3: Modded Keybinding."},{"heading":"Activate","level":4,"markdown":"```sqf\naddUserActionEventHandler [\"KeyName\", \"Activate\", {\n    params [\"_activated\"];\n}];\n```\n\n- activated: Boolean - always returns true"},{"heading":"Deactivate","level":4,"markdown":"```sqf\naddUserActionEventHandler [\"KeyName\", \"Deactivate\", {\n    params [\"_activated\"];\n}];\n```\n\n- activated: Boolean - always returns false"},{"heading":"Analog","level":4,"markdown":"```sqf\naddUserActionEventHandler [\"KeyName\", \"Analog\", {\n    params [\"_value\"];\n}];\n```\n\n- value: Number - input device's analog value"},{"heading":"Projectile Event Handlers (Arma 3 v2.10)","level":3,"markdown":"Commands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers"},{"heading":"Deleted (Projectile)","level":4,"markdown":"```sqf\n_projectile addEventHandler [\"Deleted\", {\n    params [\"_projectile\"];\n}];\n```\n\n- projectile: Object"},{"heading":"Deflected","level":4,"markdown":"```sqf\n_projectile addEventHandler [\"Deflected\", {\n    params [\"_projectile\", \"_position\", \"_velocity\", \"_hitObject\"];\n}];\n```\n\n- projectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D\n- hitObject: Object - the object that deflected the projectile"},{"heading":"Explode","level":4,"markdown":"Local Argument\n\n```sqf\n_projectile addEventHandler [\"Explode\", {\n    params [\"_projectile\", \"_position\", \"_velocity\"];\n}];\n```\n\n- projectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D"},{"heading":"HitExplosion","level":4,"markdown":"```sqf\n_projectile addEventHandler [\"HitExplosion\", {\n    params [\"_projectile\", \"_hitEntity\", \"_projectileOwner\", \"_hitSelections\", \"_instigator\"];\n}];\n```\n\n- projectile: Object\n- hitEntity: Object\n- projectileOwner: Object\n- hitSelections: Array of Arrays - same list of FireGeometry components that #HitPart (Entity) gets but only contains:\n  - position: Array format PositionASL - position of impact\n  - vector: Array format Vector3D - vector that is orthogonal (perpendicular) to the surface struck. For example, if a wall was hit, vector would be pointing out of the wall at a 90 degree angle\n  - selection: String - named selection of the object that was hit, in the FireGeometry LOD.\n  - radius: Number - radius (size) of component hit\n  - surface: String - surface type struck\n- Arma 3 v2.18 instigator: Object - shot instigator"},{"heading":"HitPart (Projectile)","level":4,"markdown":"Triggered when the projectile hits any surface.\n\n```sqf\n_projectile addEventHandler [\"HitPart\", {\n    params [\"_projectile\", \"_hitEntity\", \"_projectileOwner\", \"_pos\", \"_velocity\", \"_normal\", \"_components\", \"_radius\" ,\"_surfaceType\", \"_instigator\"];\n}];\n```\n\n- projectile: Object\n- hitEntity: Object\n- projectileOwner: Object\n- pos: Array format PositionASL\n- velocity: Array format Vector3D\n- normal: Array format Vector3D\n- components: Array of Strings - the selections that were hit, in the FireGeometry LOD.\n- radius: Number - radius (size) of the hitPoint\n- surfaceType: String\n- Arma 3 v2.18 instigator: Object - shot instigator\n\n> [!IMPORTANT]\n> This event handler only triggers for direct hits and not splash damage, unlike #HitPart (Entity). For splash damage, use #HitExplosion."},{"heading":"Init (Projectile)","level":4,"markdown":"Triggered whenever a projectile is created. Cannot be used in scripts, only inside class Eventhandlers in config.\n\n```cpp\ninit = \"params ['_projectile'];\";\n```\n\n```sqf\nparams [\"_projectile\"];\n```\n\n- projectile: Object - object the event handler is assigned to"},{"heading":"MineActivated (Arma 3 v2.14)","level":4,"markdown":"Local Argument\nLocal Effect\n\n```sqf\n_projectile addEventHandler [\"MineActivated\", {\n    params [\"_projectile\", \"_isActive\"];\n}];\n```\n\n- projectile: Object\n- isActive: Boolean - new active state of the mine"},{"heading":"Penetrated","level":4,"markdown":"This event fires as many times as the projectile penetrates a surface.\n\n```sqf\n_projectile addEventHandler [\"Penetrated\", {\n    params [\"_projectile\", \"_hitObject\", \"_surfaceType\", \"_entryPoint\", \"_exitPoint\", \"_exitVector\"];\n}];\n```\n\n- projectile: Object\n- hitObject: Object\n- surfaceType: String - see surfaceType\n- entryPoint: Array format PositionASL - the projectile's entry point\n- exitPoint: Array format PositionASL - the projectile's exit point\n- exitVector: Array format Vector3D - speed/angle exit vector (see vectorMagnitude to obtain the speed, in metre per second)"},{"heading":"SubmunitionCreated","level":4,"markdown":"This event fires as many times as submunitions are created.\n\n```sqf\n_projectile addEventHandler [\"SubmunitionCreated\", {\n    params [\"_projectile\", \"_submunitionProjectile\", \"_position\", \"_velocity\"];\n}];\n```\n\n- projectile: Object\n- subMunitionProjectile: Object\n- position: Array format PositionASL\n- velocity: Array format Vector3D"},{"heading":"Group Event Handlers (Arma 3 v2.10)","level":3,"markdown":"Commands:\n- addEventHandler\n- removeEventHandler\n- removeAllEventHandlers"},{"heading":"CombatModeChanged","level":4,"markdown":"Triggers when the group's **behaviour** changes (see behaviour, setBehaviour)\n\n```sqf\n_group addEventHandler [\"CombatModeChanged\", {\n    params [\"_group\", \"_newMode\"];\n}];\n```\n\n- group: Group\n- newMode: String - see AI Behaviour (**not** Combat Modes!)"},{"heading":"CommandChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"CommandChanged\", {\n    params [\"_group\", \"_newCommand\"];\n}];\n```\n\n- group: Group\n- newCommand: String, can be one of:\n\n|  |  |\n|---|---|\n| \"NO CMD\" | NoCommand |\n| \"WAIT\" | Wait |\n| \"ATTACK\" | Attack |\n| \"Suppress\" | Suppress |\n| \"HIDE\" | Hide |\n| \"MOVE\" | Move |\n| \"HOOK CARGO\" | HookCargo |\n| \"UNHOOK CARGO\" | UnhookCargo |\n| \"VIV GETIN\" | ViVGetIn |\n| \"VIV GETOUT\" | ViVGetOut |\n| \"VIV UNLOAD\" | ViVUnload |\n| \"HEAL\" | Heal |\n| \"REPAIR\" | Repair |\n| \"REFUEL\" | Refuel |\n| \"REARM\" | Rearm |\n| \"SUPPORT\" | Support |\n| \"JOIN\" | Join |\n| \"GET IN\" | GetIn |\n| \"FIRE\" | Fire |\n| \"GET OUT\" | GetOut |\n| \"STOP\" | Stop |\n| \"EXPECT\" | Expect |\n| \"ACTION\" | Action |\n| \"SCRIPTED\" | Scripted |\n| \"DISMISS\" | Dismiss |\n| \"HEAL SOLDIER\" | HealSoldier |\n| \"PATCH SOLDIER\" | PatchSoldier |\n| \"FIRST AID\" | FirstAid |\n| \"HEAL SELF\" | HealSoldierSelf |\n| \"ATTACK AND FIRE\" | AttackAndFire |\n| \"CARRY SOLDIER\" | CarrySoldier |\n| \"DROP CARRIED\" | DropCarried |\n| \"TAKE BAG\" | TakeBag |\n| \"ASSEMBLE\" | Assemble |\n| \"DISASSEMBLE\" | DisAssemble |\n| \"DROP BAG\" | DropBag |\n| \"OPEN BAG\" | OpenBag |\n| \"IRLASER ON\" | IRLaserOn |\n| \"IRLASER OFF\" | IRLaserOff |\n| \"GUN LIGHT ON\" | GunLightOn |\n| \"GUN LIGHT OFF\" | GunLightOff |\n| \"FIRE AT POSITION\" | FireAtPosition |\n| \"REPAIR VEHICLE\" | RepairVehicle |\n| \"OPEN PARA\" | OpenParachute |\n| \"KEEP DEPTH LEADER\" | KeepDepthLeader |\n| \"KEEP DEPTH UND SURF\" | KeepDepthUnderSurface |\n| \"KEEP DEPTH ABV SURF\" | KeepDepthAboveSurface |\n| \"KEEP DEPTH BOTTOM\" | KeepDepthBottom |\n| \"PUT IN\" | PutIn |\n| \"UNLOAD FROM\" | UnloadFrom |\n| \"USE CONTAINER MAGAZINE\" | UseContainerMagazine |\n| \"ACTIVATE MINE\" | ActivateMine |\n| \"DISABLE MINE\" | DisableMine |"},{"heading":"Deleted (Group)","level":4,"markdown":"```sqf\n_group addEventHandler [\"Deleted\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group"},{"heading":"Empty","level":4,"markdown":"```sqf\n_group addEventHandler [\"Empty\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group"},{"heading":"EnableAttackChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"EnableAttackChanged\", {\n    params [\"_group\", \"_attackEnabled\"];\n}];\n```\n\n- group: Group\n- attackEnabled: Boolean"},{"heading":"EnemyDetected","level":4,"markdown":"```sqf\n_group addEventHandler [\"EnemyDetected\", {\n    params [\"_group\", \"_newTarget\"];\n}];\n```\n\n- group: Group\n- newTarget: Object"},{"heading":"Fleeing","level":4,"markdown":"```sqf\n_group addEventHandler [\"Fleeing\", {\n    params [\"_group\", \"_fleeingNow\"];\n}];\n```\n\n- group: Group\n- fleeingNow: Boolean"},{"heading":"FormationChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"FormationChanged\", {\n    params [\"_group\", \"_newFormation\"];\n}];\n```\n\n- group: Group\n- newFormation: String - see setFormation"},{"heading":"GroupIdChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"GroupIdChanged\", {\n    params [\"_group\", \"_newGroupId\"];\n}];\n```\n\n- group: Group\n- newGroupId: String"},{"heading":"KnowsAboutChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"KnowsAboutChanged\", {\n    params [\"_group\", \"_targetUnit\", \"_newKnowsAbout\", \"_oldKnowsAbout\"];\n}];\n```\n\n- group: Group\n- targetUnit: Object\n- newKnowsAbout: Number\n- oldKnowsAbout: Number"},{"heading":"LeaderChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"LeaderChanged\", {\n    params [\"_group\", \"_newLeader\"];\n}];\n```\n\n- group: Group\n- newLeader: Object"},{"heading":"Local (Group)","level":4,"markdown":"```sqf\n_group addEventHandler [\"Local\", {\n    params [\"_group\", \"_isLocal\"];\n}];\n```\n\n- group: Group"},{"heading":"SpeedModeChanged","level":4,"markdown":"```sqf\n_group addEventHandler [\"SpeedModeChanged\", {\n    params [\"_group\", \"_newSpeedMode\"];\n}];\n```\n\n- group: Group\n- newSpeedMode: String - see setSpeedMode"},{"heading":"UnitJoined","level":4,"markdown":"```sqf\n_group addEventHandler [\"UnitJoined\", {\n    params [\"_group\", \"_newUnit\"];\n}];\n```\n\n- group: Group\n- newUnit: Object"},{"heading":"UnitKilled (Arma 3 v2.18)","level":4,"markdown":"Local Argument\n\nTriggered when a unit in the group is killed.\n\n```sqf\n_group addEventHandler [\"UnitKilled\", {\n    params [\"_group\", \"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- group: Group - the group the event handler is assigned to\n- unit: Object - the unit that was killed\n- killer: Object - the object that killed the unit. Contains the unit itself in case of collisions.\n- instigator: Object - the person who pulled the trigger\n- useEffects: Boolean - same as *useEffects* in setDamage alt syntax"},{"heading":"UnitLeft","level":4,"markdown":"```sqf\n_group addEventHandler [\"UnitLeft\", {\n    params [\"_group\", \"_oldUnit\"];\n}];\n```\n\n- group: Group\n- oldUnit: Object"},{"heading":"VehicleAdded","level":4,"markdown":"```sqf\n_group addEventHandler [\"VehicleAdded\", {\n    params [\"_group\", \"_newVehicle\"];\n}];\n```\n\n- group: Group\n- newVehicle: Object"},{"heading":"VehicleRemoved","level":4,"markdown":"```sqf\n_group addEventHandler [\"VehicleRemoved\", {\n    params [\"_group\", \"_oldVehicle\"];\n}];\n```\n\n- group: Group\n- oldVehicle: Object"},{"heading":"WaypointComplete","level":4,"markdown":"```sqf\n_group addEventHandler [\"WaypointComplete\", {\n    params [\"_group\", \"_waypointIndex\"];\n}];\n```\n\n- group: Group\n- waypointIndex: Number"},{"heading":"Game UI Event Handlers","level":3,"markdown":"In Game UI Event Handlers trigger when user scrolls or activates in game action menu.\n\nThe following mission EHs are available in Arma 3:\n- PrevAction - action menu scroll up event\n- Action - action menu action event\n- NextAction - action menu scroll down event\n\n> [!IMPORTANT]\n> Only one event of each kind can exist, adding another will overwrite the existing one.\n\nCommands:\n- inGameUISetEventHandler\n\n> [!NOTE]\n> See Arma 3: Event Handlers/inGameUISetEventHandler."},{"heading":"Control/Display UI Event Handlers","level":3,"markdown":"Commands:\n- ctrlAddEventHandler\n- ctrlRemoveEventHandler\n- ctrlRemoveAllEventHandlers\n- displayAddEventHandler\n- displayRemoveEventHandler\n- displayRemoveAllEventHandlers\n\n> [!NOTE]\n> See User Interface Event Handlers."},{"heading":"Music Event Handlers","level":3,"markdown":"Music event handler, always executed on the computer where it was added.\n\n> [!NOTE]\n> Does not apply to interface-less machines (dedicated server, headless client).\n\nCommands:\n- setMusicEventHandler\n- addMusicEventHandler\n- removeMusicEventHandler\n- removeAllMusicEventHandlers"},{"heading":"MusicStart (Arma 3 v0.50)","level":4,"markdown":"Triggers when CfgMusic sound starts playing, after being executed with playMusic command.\n\n```sqf\naddMusicEventHandler [\"MusicStart\", {\n    params [\"_musicClassname\", \"_eventHandlerID\", \"_currentPosition\", \"_totalLength\"];\n}];\n```\n\n- musicClassName: String - CfgMusic class name of the music that started\n- eventHandlerID: Number - EH id returned by addMusicEventHandler\n- Arma 3 v2.18 currentPosition: Number - current playback position in 0...1 range (see also: getMusicPlayedTime)\n- Arma 3 v2.18 totalLength: Number - track total length in seconds"},{"heading":"MusicStop (Arma 3 v0.50)","level":4,"markdown":"Triggers when CfgMusic sound finished playing, after being executed with playMusic command.\n\nArma 3 v2.14 `playMusic \"\"` triggers this event if a music is currently playing.\n\n```sqf\naddMusicEventHandler [\"MusicStop\", {\n    params [\"_musicClassname\", \"_eventHandlerID\", \"_currentPosition\", \"_totalLength\"];\n}];\n```\n\n- musicClassName: String - CfgMusic class name of the music that stopped\n- eventHandlerID: Number - EH id returned by addMusicEventHandler\n- Arma 3 v2.18 currentPosition: Number - current playback position in 0...1 range (see also: getMusicPlayedTime)\n- Arma 3 v2.18 totalLength: Number - track total length in seconds"},{"heading":"Eden Editor","level":3,"markdown":"Commands:\n- add3DENEventHandler\n- remove3DENEventHandler\n- removeAll3DENEventHandlers\n\n> [!NOTE]\n> See also:\n> - Arma 3: Event Handlers: Eden Editor\n> - its sub-category Object Event Handlers\n> - Eden Editor"},{"heading":"Public Variable Broadcast Event","level":3,"markdown":"Commands:\n- addPublicVariableEventHandler\n\nTriggers when missionNamespace variable EH is associated with is sent over network via publicVariable, publicVariableServer or publicVariableClient commands.\n\n> [!NOTE]\n> Unlike with other types of EHs, there is no way of removing added public variable event handler"},{"heading":"Weapon Muzzle Config Events","level":3,"markdown":"There are six event handlers that can be set on weapon in config. Their parameters are the same as their entity EH equivalents.\n- \"Fired\" - when muzzle fired - see Fired\n- \"Reload\" - before muzzle is reloaded - see MagazineReloading\n- \"Reloaded\" - after muzzle is reloaded - see Reloaded\n- \"MagazineUnloaded\" - when the magazine is removed - see MagazineUnloaded\n- \"WeaponChanged\" - when the weapon is switched to or from - see WeaponChanged\n- \"SlotItemChanged\" - when one of the weapon's attachments is changed - see SlotItemChanged\n\n```cpp\nclass CfgWeapons\n{\n    class RifleCore;\n    class TAG_Rifle : RifleCore\n    {\n        class EventHandlers\n        {\n            fired        = \"systemChat format ['fired weapon EH output: %1 [time: %2]', _this, time]\";\n            reload        = \"systemChat format ['reload weapon EH output: %1 [time: %2]', _this, time]\";\n            reloaded    = \"systemChat format ['reloaded weapon EH output: %1 [time: %2]', _this, time]\";\n            magazineunloaded    = \"systemChat format ['magazineunloaded weapon EH output: %1 [time: %2]', _this, time]\";\n            slotitemchanged    = \"systemChat format ['slotitemchanged weapon EH output: %1 [time: %2]', _this, time]\";\n            weaponchanged    = \"systemChat format ['weaponchanged weapon EH output: %1 [time: %2]', _this, time]\";\n        };\n    };\n};\n```"},{"heading":"Ammo Config Events","level":3,"markdown":"There are three event handlers that can be set on ammo in config:\n- \"init\" - when the ammo is created, by any mean (fired, created, etc). Params: [shot]\n- \"fired\" - when the ammo is fired (legacy). Params: same as in entity EH \"Fired\".\n- \"ammoHit\" - when the ammo hits anything (can trigger multiple times). Params: [shot, shooter, hitobj, pos, velocity, hitComponents, [hit, indirecthit, indirecthitrange, explosive, name], normal, explode, instigator (since Arma 3 v2.18)]\n\n```cpp\nclass CfgAmmo\n{\n    class BulletCore;\n    class TAG_Bullet : BulletCore\n    {\n        class EventHandlers\n        {\n            init    = \"systemChat format ['init ammo EH output: %1 [time: %2]', _this, time]\";\n            fired    = \"systemChat format ['fired ammo EH output: %1 [time: %2]', _this, time]\";\n            ammoHit    = \"systemChat format ['ammoHit EH output: %1 [time: %2]', _this, time]\";\n        };\n    };\n};\n```"},{"heading":"BI Scripted Events","level":3,"markdown":"Commands:\n- BIS_fnc_addScriptedEventHandler\n- BIS_fnc_removeScriptedEventHandler\n- BIS_fnc_removeAllScriptedEventHandlers\n- BIS_fnc_callScriptedEventHandler\n\n> [!NOTE]\n> See also Arma 3: Scripted Event Handlers.\n\nJump to the top of the page"}],"categories":["Event Handlers"],"groups":["Event Handlers"]},{"name":"Arma 3: Functions Library","title":"Arma 3: Functions Library","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Functions_Library","revid":379070,"updated":"2026-09-25T10:49:19Z","aliases":["Arma 3 Functions Library","CfgFunctions","Functions Library (Arma 3)"],"markdown":"Arma 3's **Functions Library** is the way to declare mission, campaign or addon's Functions. The main difference from older Function Libraries is that it runs automatically and does not require a Functions module.\n\nThe advantages of using the Functions Library over e.g execVM an SQF file are as follow:\n1. **Automatic compilation upon mission start** into a global variable - no need to remember direct paths to files.\n1. **Anti-hack protection** using compileFinal (see Arma 3: Writing a Function#Recompiling and BIS_fnc_recompile)\n1. **Listing in the Functions Viewer**\n1. **Advanced debugging options**\n1. **Optional immediate execution upon mission start**, without need for manual call\n1. **Potential performance improvements**\n\n> [!IMPORTANT]\n> This page is about Arma 3 Functions Library.\n> - For Arma 2/Arma 2:OA, see Arma 2: Functions Library.\n> - For Take On Helicopters, see Take On Helicopters: Functions Library.\n\n### Function Declaration\n\nFunctions are configured within the `CfgFunctions` class.\n\nMission and campaign specific functions can be configured in Description.ext/Campaign Description.ext, while addon functions are defined in Config.cpp.\nConfiguration structure is the same in both cases.\n\n> [!NOTE]\n> The root directory (noted as **<ROOT>** on this page) is the origin from which the game will try to load function files. It depends on `CfgFunctions`' location:\n> - if Description.ext, **<ROOT>** means the mission's root directory\n> - if Campaign Description.ext, **<ROOT>** means the campaign's root directory\n> - if in config, **<ROOT>** means the **game**'s root directory. The addon path needs to be set manually.\n\nSee a basic example config:\n class **CfgFunctions**\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass functionName {};\n \t\t};\n \t};\n };\n- The function's name will be **TAG**_fnc_**functionName**\n- The function will be loaded:\n  - from config: `**<ROOT>**\\Category\\**fn_**functionName**.sqf**`\n  - from description.ext: `**<ROOT>**\\**functions**\\Category\\**fn_**functionName**.sqf**`\n\n> [!IMPORTANT]\n> **config.cpp only**:\n> - `<ROOT>` in mods is defined by the `file` mandatory attribute - see the #file section below.\n> - Anywhere outside of running mission, refer to the functions stored in uiNamespace. e.g: \n>\n> ```sqf\n> arguments call (uiNamespace getVariable \"TAG_fnc_functionName\");\n> ```\n\n#### Config Levels\n\nA **CfgFunctions** config is made of three levels: Tag, Category, and Function.\n\n##### Tag\n\nTo prevent duplicates, every author must create a subclass with a unique tag and create functions under it.\nThe tag name will be used when composing a function name (e.g **BIS**_fnc_spawnGroup).\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n \t};\n\n \tclass TAG_WeaponManagement\n \t{\n \t\t**tag** = \"TAG\"; `// the function will be named **TAG_fnc_myOtherFunction**`\n \t\tclass Category\n \t\t{\n \t\t\tclass myOtherFunction {};\n \t\t};\n \t};\n };\n\n###### Attributes\n\n###### tag\n\nThe `tag` attribute can override the config tag set differently.\n\n##### Category\n\nThe category name changes the function's category in the Functions Viewer. It does not change the function's name, only the loading path.\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n\n \t\tclass OtherCategory\n \t\t{\n \t\t\t**file** = \"My\\Category\\Path\";\n \t\t\tclass myFunction {}; `// file path will be **<ROOT>**\\My\\Category\\Path\\fn_myFunction.sqf\";`\n \t\t};\n\n \t\tclass DataCategory\n \t\t{\n \t\t\t**requiredAddons[]** = { \"A3_Data_F\" }; `// Optional requirements of CfgPatches classes. If some addons are missing, category functions will not be compiled.`\n \t\t\tclass myDataFunction {};\n \t\t};\n \t};\n };\n\n###### Attributes\n\n###### file\n\nThe `file` attribute can override the category's loading path segment - it is required for mods.\n\n###### requiredAddons\n\nThe category can skip loading if a required addon is missing by setting its dependency with the `requiredAddons` attribute.\n\n##### Function\n\n> [!NOTE]\n> By convention, the function class should be named in **camelCase** and not have its first letter capitalised (e.g PascalCase):\n> - ✓ TAG_fnc_myFunction\n> - ✗ TAG_fnc_MyFunction\n> - ✓ TAG_fnc_POWRescue\n\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category1\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n\n \t\tclass Category2\n \t\t{\n \t\t\tfile = \"Path\\To\\Category\";\n \t\t\tclass myFunction\n \t\t\t{\n \t\t\t\t**file** = \"My\\Function\\Filepath.sqf\"; `// file path will be **<ROOT>**\\My\\Function\\Filepath.sqf\", ignoring \"Path\\To\\Category\"`\n \t\t\t};\n\n \t\t\tclass myFSMFunction\n \t\t\t{\n \t\t\t\t**preInit**\t\t= 1;\n \t\t\t\t**postInit**\t= 1;\n \t\t\t\t**ext**\t\t\t= \".fsm\";\n \t\t\t\t**preStart**\t= 1;\n \t\t\t\t**recompile**\t= 1;\n \t\t\t};\n \t\t};\n \t};\n };\n\n###### Attributes\n\n| Attribute | Description | Available in |  |\n|---|---|---|---|\n| Description.ext | config.cpp |  |  |\n| file | the `file` attribute can be used to manually set the file path.<br>> [!IMPORTANT]<br>> The **file** entry **overrides** Category's set path and ignores it entirely (they are not merged). | ✓ | ✓ |\n| preInit | the `preInit` attribute (formerly known as \"forced\") can be set to 1 to call the function upon mission start, before objects are initialized.<br>Passed arguments are `[\"preInit\"]`.<br>The function is run in an **unscheduled environment**. | ✓ | ✓ |\n| postInit | the `postInit` attribute can be set to 1 to call the function upon mission start, after objects are initialized.<br>Passed arguments are `[\"postInit\", didJIP]`.<br>The function is run in a **scheduled environment** so suspension is allowed, but **any long term suspension will halt the mission loading until suspension is done**. | ✓ | ✓ |\n| ext | the `ext` attribute can be used to set function file's type; it can be one of:<br>- \".sqf\" (default)<br>- \".fsm\" (see FSM) | ✓ | ✓ |\n| preStart | the `preStart` attribute can be set to 1 to call the function upon game start, before title screen, but after all addons are loaded. | ✗ | ✓ |\n| recompile | the `recompile` attribute can be set to 1 to recompile the function upon mission start (functions in Description.ext are always compiled upon mission (re)start) | ✗ | ✓ |\n| headerType | the `headerType` adds code to the beginning of functions that can:<br>- Set up the Meta Variables _fnc_scriptParent and _fnc_scriptName<br>- Name the current scope via the command scriptName<br>- Adds debug information by saving the current execution order in the Array _fnc_scriptMap.<br>Possible values are:<br>- -1: No header - Adds nothing, literally adds a blank String to the beginning of functions. The functions will have no debug or #Meta Variables assigned for it and the scope will not be named. Useful to reduce the performance overhead or if custom debug system is used.<br>- 0: Default header - The default header changes based on the current Debug Mode<br>- 1: System header - Incorporates the Meta Variables _fnc_scriptParent. Also names the current scope.<br>```sqf<br>private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then { '%1' } else { _fnc_scriptName };<br>scriptName '%1';<br>```<br>See the following section for more information. | ✓ | ✓ |\n\n> [!IMPORTANT]\n> Notes about `preInit` and `postInit` defined in **config.cpp**:\n> - these attributes will make the function run **on each, every and any mission start**\n> - Any scripting error will prevent the mission from being loaded correctly\n> - Server admins might blacklist the whole addon if they find out the function is used for hacking\n\n### Advanced Knowledge\n\n#### Meta Variables\n\n- **_fnc_scriptName**: String - Name of the script\n- **_fnc_scriptNameParent**: String - Name of the parent script\n- **_fnc_scriptMap**: Array - List of all parent scripts\n\n#### Debug Modes\n\nDevelopers can access several debug modes using *BIS_fnc_functionsDebug* function. **For this to work function recompiling has to be allowed!**\n\n##### Debug Mode 0\n\ndefault - incorporates the Meta Variables _fnc_scriptParent and _fnc_scriptName and names the current scope.\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\n```\n\n##### Debug Mode 1\n\nAs per *Debug Mode 0* and also saves the current execution order in the Array _fnc_scriptMap.\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\nprivate _fnc_scriptMap = if (isNil \"_fnc_scriptMap\") then { [_fnc_scriptName] } else { _fnc_scriptMap + [_fnc_scriptName] };\n```\n\n##### Debug Mode 2\n\nAs per *Debug Mode 1* and also outputs execution order using textLogFormat ( textLogFormat is not available in the retail version of Arma3 ) is it available in Diagnostics exe?\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\nprivate _fnc_scriptMap = if (isNil \"_fnc_scriptMap\") then { [_fnc_scriptName] } else { _fnc_scriptMap + [_fnc_scriptName] };\ntextLogFormat [\"%1 : %2\", _fnc_scriptMap joinString \" >> \", _this];\n```\n\n### See Also\n\n- Initialisation Order\n- Arma 3: Functions Viewer\n- Arma 3 Functions\n- Writing a Function Tutorial\n\nArma 3 Editing","sections":[{"heading":null,"level":1,"markdown":"Arma 3's **Functions Library** is the way to declare mission, campaign or addon's Functions. The main difference from older Function Libraries is that it runs automatically and does not require a Functions module.\n\nThe advantages of using the Functions Library over e.g execVM an SQF file are as follow:\n1. **Automatic compilation upon mission start** into a global variable - no need to remember direct paths to files.\n1. **Anti-hack protection** using compileFinal (see Arma 3: Writing a Function#Recompiling and BIS_fnc_recompile)\n1. **Listing in the Functions Viewer**\n1. **Advanced debugging options**\n1. **Optional immediate execution upon mission start**, without need for manual call\n1. **Potential performance improvements**\n\n> [!IMPORTANT]\n> This page is about Arma 3 Functions Library.\n> - For Arma 2/Arma 2:OA, see Arma 2: Functions Library.\n> - For Take On Helicopters, see Take On Helicopters: Functions Library."},{"heading":"Function Declaration","level":3,"markdown":"Functions are configured within the `CfgFunctions` class.\n\nMission and campaign specific functions can be configured in Description.ext/Campaign Description.ext, while addon functions are defined in Config.cpp.\nConfiguration structure is the same in both cases.\n\n> [!NOTE]\n> The root directory (noted as **<ROOT>** on this page) is the origin from which the game will try to load function files. It depends on `CfgFunctions`' location:\n> - if Description.ext, **<ROOT>** means the mission's root directory\n> - if Campaign Description.ext, **<ROOT>** means the campaign's root directory\n> - if in config, **<ROOT>** means the **game**'s root directory. The addon path needs to be set manually.\n\nSee a basic example config:\n class **CfgFunctions**\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass functionName {};\n \t\t};\n \t};\n };\n- The function's name will be **TAG**_fnc_**functionName**\n- The function will be loaded:\n  - from config: `**<ROOT>**\\Category\\**fn_**functionName**.sqf**`\n  - from description.ext: `**<ROOT>**\\**functions**\\Category\\**fn_**functionName**.sqf**`\n\n> [!IMPORTANT]\n> **config.cpp only**:\n> - `<ROOT>` in mods is defined by the `file` mandatory attribute - see the #file section below.\n> - Anywhere outside of running mission, refer to the functions stored in uiNamespace. e.g: \n>\n> ```sqf\n> arguments call (uiNamespace getVariable \"TAG_fnc_functionName\");\n> ```"},{"heading":"Config Levels","level":4,"markdown":"A **CfgFunctions** config is made of three levels: Tag, Category, and Function."},{"heading":"Tag","level":5,"markdown":"To prevent duplicates, every author must create a subclass with a unique tag and create functions under it.\nThe tag name will be used when composing a function name (e.g **BIS**_fnc_spawnGroup).\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n \t};\n\n \tclass TAG_WeaponManagement\n \t{\n \t\t**tag** = \"TAG\"; `// the function will be named **TAG_fnc_myOtherFunction**`\n \t\tclass Category\n \t\t{\n \t\t\tclass myOtherFunction {};\n \t\t};\n \t};\n };"},{"heading":"Attributes","level":6,"markdown":""},{"heading":"tag","level":6,"markdown":"The `tag` attribute can override the config tag set differently."},{"heading":"Category","level":5,"markdown":"The category name changes the function's category in the Functions Viewer. It does not change the function's name, only the loading path.\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n\n \t\tclass OtherCategory\n \t\t{\n \t\t\t**file** = \"My\\Category\\Path\";\n \t\t\tclass myFunction {}; `// file path will be **<ROOT>**\\My\\Category\\Path\\fn_myFunction.sqf\";`\n \t\t};\n\n \t\tclass DataCategory\n \t\t{\n \t\t\t**requiredAddons[]** = { \"A3_Data_F\" }; `// Optional requirements of CfgPatches classes. If some addons are missing, category functions will not be compiled.`\n \t\t\tclass myDataFunction {};\n \t\t};\n \t};\n };"},{"heading":"Attributes","level":6,"markdown":""},{"heading":"file","level":6,"markdown":"The `file` attribute can override the category's loading path segment - it is required for mods."},{"heading":"requiredAddons","level":6,"markdown":"The category can skip loading if a required addon is missing by setting its dependency with the `requiredAddons` attribute."},{"heading":"Function","level":5,"markdown":"> [!NOTE]\n> By convention, the function class should be named in **camelCase** and not have its first letter capitalised (e.g PascalCase):\n> - ✓ TAG_fnc_myFunction\n> - ✗ TAG_fnc_MyFunction\n> - ✓ TAG_fnc_POWRescue\n\n class CfgFunctions\n {\n \tclass TAG\n \t{\n \t\tclass Category1\n \t\t{\n \t\t\tclass myFunction {};\n \t\t};\n\n \t\tclass Category2\n \t\t{\n \t\t\tfile = \"Path\\To\\Category\";\n \t\t\tclass myFunction\n \t\t\t{\n \t\t\t\t**file** = \"My\\Function\\Filepath.sqf\"; `// file path will be **<ROOT>**\\My\\Function\\Filepath.sqf\", ignoring \"Path\\To\\Category\"`\n \t\t\t};\n\n \t\t\tclass myFSMFunction\n \t\t\t{\n \t\t\t\t**preInit**\t\t= 1;\n \t\t\t\t**postInit**\t= 1;\n \t\t\t\t**ext**\t\t\t= \".fsm\";\n \t\t\t\t**preStart**\t= 1;\n \t\t\t\t**recompile**\t= 1;\n \t\t\t};\n \t\t};\n \t};\n };"},{"heading":"Attributes","level":6,"markdown":"| Attribute | Description | Available in |  |\n|---|---|---|---|\n| Description.ext | config.cpp |  |  |\n| file | the `file` attribute can be used to manually set the file path.<br>> [!IMPORTANT]<br>> The **file** entry **overrides** Category's set path and ignores it entirely (they are not merged). | ✓ | ✓ |\n| preInit | the `preInit` attribute (formerly known as \"forced\") can be set to 1 to call the function upon mission start, before objects are initialized.<br>Passed arguments are `[\"preInit\"]`.<br>The function is run in an **unscheduled environment**. | ✓ | ✓ |\n| postInit | the `postInit` attribute can be set to 1 to call the function upon mission start, after objects are initialized.<br>Passed arguments are `[\"postInit\", didJIP]`.<br>The function is run in a **scheduled environment** so suspension is allowed, but **any long term suspension will halt the mission loading until suspension is done**. | ✓ | ✓ |\n| ext | the `ext` attribute can be used to set function file's type; it can be one of:<br>- \".sqf\" (default)<br>- \".fsm\" (see FSM) | ✓ | ✓ |\n| preStart | the `preStart` attribute can be set to 1 to call the function upon game start, before title screen, but after all addons are loaded. | ✗ | ✓ |\n| recompile | the `recompile` attribute can be set to 1 to recompile the function upon mission start (functions in Description.ext are always compiled upon mission (re)start) | ✗ | ✓ |\n| headerType | the `headerType` adds code to the beginning of functions that can:<br>- Set up the Meta Variables _fnc_scriptParent and _fnc_scriptName<br>- Name the current scope via the command scriptName<br>- Adds debug information by saving the current execution order in the Array _fnc_scriptMap.<br>Possible values are:<br>- -1: No header - Adds nothing, literally adds a blank String to the beginning of functions. The functions will have no debug or #Meta Variables assigned for it and the scope will not be named. Useful to reduce the performance overhead or if custom debug system is used.<br>- 0: Default header - The default header changes based on the current Debug Mode<br>- 1: System header - Incorporates the Meta Variables _fnc_scriptParent. Also names the current scope.<br>```sqf<br>private _fnc_scriptNameParent = if (isNil '_fnc_scriptName') then { '%1' } else { _fnc_scriptName };<br>scriptName '%1';<br>```<br>See the following section for more information. | ✓ | ✓ |\n\n> [!IMPORTANT]\n> Notes about `preInit` and `postInit` defined in **config.cpp**:\n> - these attributes will make the function run **on each, every and any mission start**\n> - Any scripting error will prevent the mission from being loaded correctly\n> - Server admins might blacklist the whole addon if they find out the function is used for hacking"},{"heading":"Advanced Knowledge","level":3,"markdown":""},{"heading":"Meta Variables","level":4,"markdown":"- **_fnc_scriptName**: String - Name of the script\n- **_fnc_scriptNameParent**: String - Name of the parent script\n- **_fnc_scriptMap**: Array - List of all parent scripts"},{"heading":"Debug Modes","level":4,"markdown":"Developers can access several debug modes using *BIS_fnc_functionsDebug* function. **For this to work function recompiling has to be allowed!**"},{"heading":"Debug Mode 0","level":5,"markdown":"default - incorporates the Meta Variables _fnc_scriptParent and _fnc_scriptName and names the current scope.\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\n```"},{"heading":"Debug Mode 1","level":5,"markdown":"As per *Debug Mode 0* and also saves the current execution order in the Array _fnc_scriptMap.\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\nprivate _fnc_scriptMap = if (isNil \"_fnc_scriptMap\") then { [_fnc_scriptName] } else { _fnc_scriptMap + [_fnc_scriptName] };\n```"},{"heading":"Debug Mode 2","level":5,"markdown":"As per *Debug Mode 1* and also outputs execution order using textLogFormat ( textLogFormat is not available in the retail version of Arma3 ) is it available in Diagnostics exe?\n\n```sqf\nprivate _fnc_scriptNameParent = if (isNil \"_fnc_scriptName\") then { \"%1\" } else { _fnc_scriptName };\nprivate _fnc_scriptName = \"%1\";\nscriptName _fnc_scriptName;\nprivate _fnc_scriptMap = if (isNil \"_fnc_scriptMap\") then { [_fnc_scriptName] } else { _fnc_scriptMap + [_fnc_scriptName] };\ntextLogFormat [\"%1 : %2\", _fnc_scriptMap joinString \" >> \", _this];\n```"},{"heading":"See Also","level":3,"markdown":"- Initialisation Order\n- Arma 3: Functions Viewer\n- Arma 3 Functions\n- Writing a Function Tutorial\n\nArma 3 Editing"}],"categories":["Arma 3: Editing","Functions Library"],"groups":["Scripting"]},{"name":"Arma 3: Mission Event Handlers","title":"Arma 3: Mission Event Handlers","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Mission_Event_Handlers","revid":378631,"updated":"2026-05-15T11:20:24Z","aliases":["Arma 3: Event Handlers/addMissionEventHandler"],"markdown":"Arma 3 v0.50 Local Effect\n\nMission event handlers are specific EHs that are anchored to the running mission and automatically removed when mission is over.\nThese events fire only on the machine where they have been added.\n\nFor all other available EHs see the Event Handlers main page.\n\n> [!NOTE]\n> **OnUser...** mission event handlers used in combination with getUserInfo provide a way to track server users from the very early stage of joining a server to the very last stage of leaving the server. All these event handlers are designed to be used server side and return unique user network id in String format as the first param. These ids could also be obtained via getPlayerID and allUsers script commands. There may be other params specific to each event. See:\n>\n> - #OnUserConnected\n> - #OnUserDisconnected\n> - #OnUserClientStateChanged\n> - #OnUserAdminStateChanged\n> - #OnUserSelectedPlayer\n> - #OnUserKicked\n\n### Related Commands\n\n- addMissionEventHandler\n- removeMissionEventHandler\n- removeAllMissionEventHandlers\n\n### Events\n\n##### ActionTargetChanged (Arma 3 v2.22)\n\nExecutes when action target object changes under cursor. This event handler fires before user actions are processed and added to the player.\n\n```sqf\naddMissionEventHandler [\"ActionTargetChanged\", {\n    params [\"_newActionTarget\", \"_oldActionTarget\"];\n}];\n```\n\n- newActionTarget: Object\n- oldActionTarget: Object\n\n##### ArtilleryShellFired (Arma 3 v2.18)\n\nGlobal Mission Event Handler. Executes each time a vehicle classified as artillery (has an artillery computer) fires a shell.\n\n```sqf\naddMissionEventHandler [\"ArtilleryShellFired\", {\n    params [\"_vehicle\", \"_weapon\", \"_ammo\", \"_gunner\", \"_instigator\", \"_artilleryTarget\", \"_targetPosition\", \"_shell\"];\n}];\n```\n\n- vehicle: Object - artillery vehicle firing the shell\n- weapon: String - weapon name\n- ammo: String - ammo name\n- gunner: Object - gunner\n- instigator: Object - instigator\n- artilleryTarget: Object - artillery target object\n- targetPosition: Position - ground position the shell is aimed at\n- shell: Object - the projectile\n\n##### BuildingChanged (Arma 3 v1.68)\n\nFired each time a building model changes, for example due to stages of destruction.\n\n```sqf\naddMissionEventHandler [\"BuildingChanged\", {\n    params [\"_from\", \"_to\", \"_isRuin\"];\n}];\n```\n\n- from: Object - building it changes from\n- to: Object - building it changes to\n- isRuin: Boolean - true if changes to ruins\n\n##### CommandModeChanged (Arma 3 v1.58)\n\nExecutes assigned code when user switches to/from High Command mode (<kbd>LShift</kbd>+<kbd>Space</kbd>). Stackable version of onCommandModeChanged.\n\n```sqf\naddMissionEventHandler [\"CommandModeChanged\", {\n    params [\"_isHighCommand\", \"_isForced\"];\n}];\n```\n\n- isHighCommand: Boolean - same as `_isHighCommand` param\n- isForced: Boolean - true if command mode was forced\n\n##### ControlsShifted (Arma 3 v1.00)\n\nTriggers when control of a vehicle is shifted (pilot->co-pilot, co-pilot->pilot), usually when user performs an action such as TakeVehicleControl, SuspendVehicleControl, UnlockVehicleControl, LockVehicleControl, or when enableCopilot command is used. This event handler will always fire on the PC where action is triggered as well as where the vehicle is local at the time. When control of the vehicle is shifted, the locality of the vehicle changes to the locality of the new controller. Since Arma 3 v1.96 this EH is extended with additional params.\n\n```sqf\naddMissionEventHandler [\"ControlsShifted\", {\n    params [\"_newController\", \"_oldController\", \"_vehicle\", \"_copilotEnabled\", \"_controlsUnlocked\"];\n}];\n```\n\n- newController: Object - unit currently controlling the vehicle\n- oldController: Object - unit previously controlling the vehicle\n- vehicle: Object - the vehicle for which controls shifted\n- copilotEnabled: Boolean - true if copilot is enabled\n- controlsUnlocked: Boolean - true if controls are unlocked\n\n##### DisplayOpened (Arma 3 v2.22)\n\nExecutes when any display is opened.\n\n```sqf\naddMissionEventHandler [\"DisplayOpened\", {\n    params [\"_display\", \"_configClass\"];\n}];\n```\n\n- display: Display\n- configClass: Config\n\n##### Draw2D (Arma 3 v2.18)\n\nRuns after all UI has been drawn. Runs the EH code each frame in unscheduled environment. Client side EH only (presence of UI).\nWill stop executing when UI loses focus (<kbd>Alt</kbd>+<kbd>Tab</kbd> for example). Usually used with drawIcon.\n\n```sqf\naddMissionEventHandler [\"Draw2D\", {\n    // no params\n}];\n```\n\n##### Draw3D (Arma 3 v0.50)\n\nRuns the EH code each frame in unscheduled environment. Client side EH only (presence of UI).\nWill stop executing when UI loses focus (<kbd>Alt</kbd>+<kbd>Tab</kbd> for example). Usually used with drawIcon3D, drawLine3D.\n\n```sqf\naddMissionEventHandler [\"Draw3D\", {\n    // no params\n}];\n```\n\n##### Drowned (Arma 3 v2.14)\n\nRuns when a vehicle gets drowned (the vehicle is submerged below 'maxFord' for longer than 'waterResistance'). This will cause engine damage and for some vehicles that will render engine unusable until the vehicle/engine is fully repared. Some vehicles can drown but would still be recoverable as they wouldn't be destroyed. The event handler will also fire when vehicle is removed from water, in which case 'drowned' param will change to false. To check if the engine was damaged by water use waterDamaged command.\n\n```sqf\naddMissionEventHandler [\"Drowned\", {\n    params [\"_vehicle\", \"_drowned\"];\n}];\n```\n\n##### EachFrame (Arma 3 v1.58)\n\nExecutes assigned code each frame. Stackable version of onEachFrame.\n\n```sqf\naddMissionEventHandler [\"EachFrame\", {\n    // no params\n}];\n```\n\n##### Ended (Arma 3 v0.50)\n\nTriggered when mission ends, either using trigger of type \"End\", endMission command, BIS_fnc_endMission function or ENDMISSION cheat.\n\n```sqf\naddMissionEventHandler [\"Ended\", {\n    params [\"_endType\"];\n}];\n```\n\n- endType: String - mission end type. Used in Debriefing among other things\n\n##### MPEnded (Arma 3 v1.60)\n\nTriggered when the server switches off from \"playing\" state (mission ends, server closes, etc.) It's only for MP games, it is called on server and also on clients. It is not called on clients when client disconnects from server (and mission continues). This EH has no arguments passed to the code.\n\n```sqf\naddMissionEventHandler [\"MPEnded\", {\n    // no params\n}];\n```\n\nIf client code must be executed on disconnect, this code can be used instead:\n\n```sqf\n0 spawn\n{\n    waitUntil { !isNull findDisplay 46 };\n    findDisplay 46 displayAddEventHandler [\"Unload\",\n    {\n        // code here gets executed on the client at end of mission, whether due to player abort, loss of connection, or mission ended by server\n        // might not work on headless clients\n    }];\n};\n```\n\n##### EntityCreated (Arma 3 v2.10)\n\nTriggered when an entity is created.\n\n> [!NOTE]\n> Unlike most event handlers, the argument is entity Object and not an array containing the entity. However, it is recommended to use params to make sure the code remains compatible in case the event arguments are expanded in the future.\n\n> [!IMPORTANT]\n> This event is called before variable namespace is copied to **remote** respawning entity, keep this in mind so your setVariables are not overwritten in the next frame. EntityRespawned always fires after variable namespace is copied to new entity regardless of locality.\n\n```sqf\naddMissionEventHandler [\"EntityCreated\", {\n    params [\"_entity\"];\n}];\n```\n\n##### EntityDeleted (Arma 3 v2.18)\n\nTriggered when an entity is deleted. It only triggers for objects that support the \"Deleted\" event handler, such as vehicles, soldiers, animals, and houses. Simple objects for example are not supported.\n\n> [!NOTE]\n> Unlike most event handlers, the argument is entity Object and not an array containing the entity. However, it is recommended to use params to make sure the code remains compatible in case the event arguments are expanded in the future.\n\n```sqf\naddMissionEventHandler [\"EntityDeleted\", {\n    params [\"_entity\"];\n}];\n```\n\n##### EntityKilled (Arma 3 v1.56)\n\nTriggered when an entity is killed.\n\n```sqf\naddMissionEventHandler [\"EntityKilled\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- unit: Object - entity that was killed\n- killer: Object - the killer (vehicle or person)\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n\n---\n\nIt's worth noting that *instigator* param is objNull during road kill. To work around this issue try:\n\n```sqf\naddMissionEventHandler [\"EntityKilled\", {\n    params [\"_killed\", \"_killer\", \"_instigator\"];\n    if (isNull _instigator) then { _instigator = UAVControl vehicle _killer select 0 }; // UAV/UGV player operated road kill\n    if (isNull _instigator) then { _instigator = _killer }; // player driven vehicle road kill\n    hint format [\"Killed By %1\", name _instigator];\n}];\n```\n\n##### EntityRespawned (Arma 3 v1.56)\n\nTriggered when an entity is respawned.\n\n```sqf\naddMissionEventHandler [\"EntityRespawned\", {\n    params [\"_newEntity\", \"_oldEntity\"];\n}];\n```\n\n- newEntity: Object - respawned entity\n- oldEntity: Object - corpse/wreck\n\n##### ExtensionCallback (Arma 3 v1.96)\n\nTriggered when an extension calls provided function pointer with 3 params.\n\n```sqf\naddMissionEventHandler [\"ExtensionCallback\", {\n    params [\"_name\", \"_function\", \"_data\"];\n}];\n```\n\n- name: String - user provided param\n- function: String - user provided param\n- data: String - user provided param\n\n##### GroupCreated (Arma 3 v2.04)\n\nTriggered when a Group is created. Note that the group contains **no** units at that point!\n\n```sqf\naddMissionEventHandler [\"GroupCreated\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group - the created group\n\n##### GroupDeleted (Arma 3 v2.04)\n\nTriggered when a Group is manually or automatically deleted.\n\n```sqf\naddMissionEventHandler [\"GroupDeleted\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group - the deleted group\n\n##### GroupIconClick (Arma 3 v1.58)\n\nExecutes assigned code when user clicks on the HC group icon on the map. If groupIconSelectable is true, LMB clicking (firing) at the HC group icon on the HUD will also trigger the event. To set group icon selectable use setGroupIconsSelectable. Stackable version of onGroupIconClick.\n\n```sqf\naddMissionEventHandler [\"GroupIconClick\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_mouseButton\", \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- mouseButton: Number - mouse button: 0 - <kbd>LMB</kbd>, 1 - <kbd>RMB</kbd> (only applicable to IconClick)\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed\n\n##### GroupIconOverEnter (Arma 3 v1.58)\n\n**Continuously** executes assigned code when user hovers with pointer over the HC group icon, either on the HUD or the main map. groupIconSelectable must be set to true for this EH to work at all. To set group icon selectable use setGroupIconsSelectable. When EH fires over the HUD icon, X and Y coordinates will change depending on the position of the pointer in relation to the icon area. When over main map, the X and Y do not change and indicate icon center. Stackable version of onGroupIconOverEnter.\n\n```sqf\naddMissionEventHandler [\"GroupIconOverEnter\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed\n\n##### GroupIconOverLeave (Arma 3 v1.58)\n\nExecutes assigned code when user moves the pointer away from HC group icon it was over. Fires either for on the HUD icons or the main map HC icons. groupIconSelectable must be set to true for this EH to work at all. To set group icon selectable use setGroupIconsSelectable. Stackable version of onGroupIconOverLeave.\n\n```sqf\naddMissionEventHandler [\"GroupIconOverLeave\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse (Y is always 0 when leaving HUD icon for some reason)\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed\n\n##### HandleAccTime (Arma 3 v1.90)\n\nFires when user changes time acceleration with +/- keys in SP or setAccTime command. If the code returns true the on-screen message confirming the change is not displayed. Doesn't fire if desired value is already set.\n\n```sqf\naddMissionEventHandler [\"HandleAccTime\", {\n    params [\"_currentTimeAcc\", \"_prevTimeAcc\", \"_messageSuppressed\"];\n}];\n```\n\n- currentTimeAcc: Number - current value\n- prevTimeAcc: Number - previous value\n- messageSuppressed: Boolean - true if on-screen message was suppressed\n\n##### HandleChatMessage (Arma 3 v2.00)\n\nFires when a message is received, before adding it to the chat feed. Fires clientside.\n\n> [!NOTE]\n> - On a dedicated server and headless client it fires only for global (channel 0) and system messages (channel 16).\n> - The HandleChatMessage EH can be used to disable/modify system messages like \"Player NAME connecting/is losing connection\".\n\n> [!IMPORTANT]\n> Does not trigger for any of the chat related script command such as systemChat, sideChat, or other chat commands.\n\nThe output message could be overridden:\n- Return true to block incoming chat message from being added to the chat feed.\n- Return String to replace the chat message content but not the sender name.\n- Return Array [from, text] to replace both the chat message content and the the sender's name.\n\n> [!IMPORTANT]\n> Only the last added HandleChatMessage EH with override will be used to override the message.\n\n> [!WARNING]\n> Do not put any of the chat related script command such as systemChat, sideChat, etc in this EH code as it would naturally cause recursion and the game will freeze.\n\n```sqf\naddMissionEventHandler [\"HandleChatMessage\", {\n    params [\"_channel\", \"_owner\", \"_from\", \"_text\", \"_person\", \"_name\", \"_strID\", \"_forcedDisplay\", \"_isPlayerMessage\", \"_sentenceType\", \"_chatMessageType\", \"_params\"];\n}];\n```\n\n- channel: Number - see radio channel indices (16 for system chat message for example)\n- owner: Number - owner id of the sender:\n  - in SP: 0\n  - in MP with no sender: clientOwner\n  - in MP with sender: sender's clientOwner, or if AI - creator id part of netId of the AI\n- from: String - sender's formatted name as appeared on the chat\n- text: String - the chat message\n- person: Object - sender's object\n- name: String - sender's name, could be different from `from`\n- strID: String - sender's network player ID (marker id):\n  - \"-1\": means not available\n  - \"0\": means isPlayer in SP\n  - \"1\": means AI in SP or MP\n  - >1: getPlayerID in MP\n- forcedDisplay: Boolean - if the message should be displayed when the chat list is disabled (when enableRadio is set to false radio protocol messages won't display)\n- isPlayerMessage: Boolean - if the message is addressed to player\n- sentenceType: Number - 0: Normal type, 1: Protocol type\n- chatMessageType: Number - 0: Generic type, 1: SimpleMove type, 2: KillConfirmation type\n- params: Array of Strings - sentence parameters, if any\n\n##### HandleDisconnect (Arma 3 v1.32 Server Execution)\n\nTriggered right after a player disconnects from the game, more accurately when a player-controlled unit changes ownership due to the owning player being disconnected (disconnected player information is no available through e.g getUserInfo anymore).\nSimilar to the #PlayerDisconnected event but contains the unit occupied by the player before their disconnection.\nMust be added on the server and triggers only on the server.\n\n> [!IMPORTANT]\n> A player disconnecting while not controlling a unit (not spawned, deleted unit, etc) does **not** trigger this event.\n\n```sqf\naddMissionEventHandler [\"HandleDisconnect\", {\n    params [\"_unit\", \"_id\", \"_uid\", \"_name\"];\n    true;\n}];\n```\n\n- unit: Object - unit formerly occupied by player\n- id: Number - same as _id in onPlayerDisconnected\n- uid: String - same as _uid in onPlayerDisconnected\n- name: String - same as _name in onPlayerDisconnected\n**Override**: if this EH code returns true, the unit, previously occupied by player, gets transferred to the server, becomes AI and continues to live, even with description.ext param `disabledAI = 1;`.\n\n##### HCGroupSelectionChanged (Arma 3 v1.58)\n\nExecutes assigned code when user selects available HC group (`F1, F2…`). Stackable version of onHCGroupSelectionChanged.\n\n```sqf\naddMissionEventHandler [\"HCGroupSelectionChanged\", {\n    params [\"_group\", \"_isSelected\"];\n}];\n```\n\n- group: Group - group selected (same as `_group` param)\n- isSelected: Boolean - true if selected (same as `_isSelected` param)\n\n##### Loaded (Arma 3 v0.50)\n\nTriggered when mission is loaded from save.\n\n> [!WARNING]\n> \"Loaded\" event handler should be added BEFORE the mission is loaded from save. Placing it in a function with preInit = 1; usually does the trick.\n\n```sqf\naddMissionEventHandler [\"Loaded\", {\n    params [\"_saveType\"];\n}];\n```\n\n- savingType: String - one of \"autosaveold\", \"autosave\", \"save\", \"save2\", \"save3\", \"save4\", \"save5\", \"save6\", \"continue\" or \"\".\n  - \"save\" - custom save, achieved by pressing SAVE button in the pause menu\n  - \"autosave\" - automatic checkpoint, saved using saveGame command\n  - \"continue\" - saved when leaving a mission to the main menu\n\n##### Map (Arma 3 v1.62)\n\nTriggered when map is opened or closed either by user action or script command openMap.\n\n```sqf\naddMissionEventHandler [\"Map\", {\n    params [\"_mapIsOpened\", \"_mapIsForced\"];\n}];\n```\n\n- mapIsOpened: Boolean - true if map is opened\n- mapIsForced: Boolean - true if map is forced\n\n##### MapSingleClick (Arma 3 v1.58)\n\nExecutes when the player clicks anywhere on the main map. Stackable version of onMapSingleClick with the limitation that it does not have the ability to override the click (e.g. to prevent the player from placing the custom waypoint with <kbd>LShift</kbd>+<kbd>LMB</kbd>). Since the introduction of `_thisArgs` for addMissionEventHandler in Arma 3 v2.04, this EH also supports custom arguments (just like onMapSingleClick).\n\n```sqf\naddMissionEventHandler [\"MapSingleClick\", {\n    params [\"_units\", \"_pos\", \"_alt\", \"_shift\"];\n}];\n```\n\n- units: Array - leader selected units, same as groupSelectedUnits (same as onMapSingleClick's `_units` variable)\n- pos: Array - world Position3D of the click in format `[x, y, 0]` (same as onMapSingleClick's `_pos` variable)\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed (same as onMapSingleClick's `_alt` variable)\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed (same as onMapSingleClick's `_shift` variable)\n\n##### MarkerCreated (Arma 3 v2.02)\n\nExecutes when a marker is created either by a user or via script command.\n\n```sqf\naddMissionEventHandler [\"MarkerCreated\", {\n    params [\"_marker\", \"_channelNumber\", \"_owner\", \"_local\"];\n}];\n```\n\n- marker: String - the name of the created marker, can be used with the marker commands\n- channelNumber: Number - channel in which the marker was created\n- owner: Object - player that created the marker or objNull\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network\n\n##### MarkerDeleted (Arma 3 v2.02)\n\nExecutes immediately before a marker is deleted either by a user or via script command.\n\n```sqf\naddMissionEventHandler [\"MarkerDeleted\", {\n    params [\"_marker\", \"_local\", \"_deleter\"];\n}];\n```\n\n- marker: String - the name of the deleted marker\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network\n- Arma 3 v2.20 deleter: Object - the player/curator unit that deleted the marker\n\n##### MarkerUpdated (Arma 3 v2.02)\n\nExecutes when a marker is changed.\n\n> [!WARNING]\n> Changing the marker in the EH code will lead to an infinite loop and the game will crash!\n\n```sqf\naddMissionEventHandler [\"MarkerUpdated\", {\n    params [\"_marker\", \"_local\"];\n}];\n```\n\n- marker: String - the name of the marker\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network\n\n##### OnUserConnected (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code on user joining server.\n\n```sqf\naddMissionEventHandler [\"OnUserConnected\", {\n    params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber) - always 1\n- clientState: String - client state (see getClientState) - always \"CREATED\"\n\n##### OnUserDisconnected (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code on user leaving server.\n\n```sqf\naddMissionEventHandler [\"OnUserDisconnected\", {\n        params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber) - always 0\n- clientState: String - client state (see getClientState) - always \"NONE\"\n\n##### OnUserClientStateChanged (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code for every stage of user client state change.\n\n```sqf\naddMissionEventHandler [\"OnUserClientStateChanged\", {\n    params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber)\n- clientState: String - client state (see getClientState)\n\n##### OnUserAdminStateChanged (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code after user logs in, gets voted in or logs out as admin.\n\n```sqf\naddMissionEventHandler [\"OnUserAdminStateChanged\", {\n    params [\"_networkId\", \"_loggedIn\", \"_votedIn\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- loggedIn: Boolean - true if user logged in or got voted in as admin, false if logged out (see admin)\n- votedIn: Boolean - true if user got voted in as admin, false otherwise (see admin)\n\n##### OnUserSelectedPlayer (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code after player object is selected for user to take over control, the ownership information is broadcast and request to sync is made but the object is still owned by previous owner for a short time.\n\n```sqf\naddMissionEventHandler [\"OnUserSelectedPlayer\", {\n        params [\"_networkId\", \"_playerObject\", \"_attempts\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- playerObject: Object - player object to be controlled by the user (see player, selectPlayer)\n- Arma 3 v2.18 attempts: Number - how many times server was trying to obtain non-null playerObject. Current threshold after which the event will fire anyway is 50.\n\n> [!IMPORTANT]\n> This is the earliest the player object is known when player joins the server, but it is not local to the user yet, so there is a wait time depending on network connection. When player respawns, the unit created on the client and so it might take a while before server has valid player object. From Arma 3 v2.18 the server will pospone this event until the object is not null, or until it tried 50 times, whichever is earlier. The best approach to handle this matter and get notified about completion of the transfer of the ownership is to use \"Local\" entity event handler, like so:\n>\n> ```sqf\n> addMissionEventHandler [\"OnUserSelectedPlayer\", {\n>     params [\"_networkId\", \"_playerObject\", \"_attempts\"];\n>     _playerObject addEventHandler [\"Local\",\n>     {\n>         params [\"_player\"];\n>         _player removeEventHandler [\"Local\", _thisEventHandler];\n>         // code to handle _player\n>     }];\n> }];\n> ```\n>\n> Note that the player object would change locality again if the user goes to lobby.\n\n##### OnUserKicked (Arma 3 v2.06 Server Execution)\n\nExecutes assigned code after after a user has been kicked from the server providing kick reason. The possible values for 'kickTypeNumber' and 'kickType' are:\n0 : `\"TIMEOUT\"`, 1 : `\"DISCONNECTED\"`, 2 : `\"KICKED\"`, 3 : `\"BANNED\"`, 4 : `\"MISSING ADDON\"`, 5 : `\"BAD CD KEY\"`, 6 : `\"CD KEY IN USE\"`, 7 : `\"SESSION LOCKED\"`, 8 : `\"BATTLEYE\"`, 9 : `\"STEAM CHECK\"`, 10 : `\"DLC CONTENT\"`, 11 : `\"GS TIMEOUT\"`, 12 : `\"SCRIPT\"`, 13 : `\"OTHER\"`\n\n```sqf\naddMissionEventHandler [\"OnUserKicked\", {\n    params [\"_networkId\", \"_kickTypeNumber\", \"_kickType\", \"_kickReason\", \"_kickMessageIncReason\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- kickTypeNumber: Number - kick type number (see above)\n- kickType: String - kick type (see above)\n- kickReason: String - reason given for the kick by the admin or by other means\n- kickMessageIncReason: String - formatted engine message including the given reason\n\n##### PlayerConnected (Arma 3 v1.58 Server Execution)\n\nExecutes assigned code when client joins the mission in MP. Stackable version of onPlayerConnected.\n\n```sqf\naddMissionEventHandler [\"PlayerConnected\", {\n    params [\"_id\", \"_uid\", \"_name\", \"_jip\", \"_owner\", \"_idStr\"];\n}];\n```\n\n- id: Number - unique DirectPlay ID (very large number). It is also the same id used for user placed markers\n- uid: String - getPlayerUID of the joining client. The same as Steam ID\n- name: String - profileName of the joining client\n- jip: Boolean - didJIP of the joining client\n- owner: Number - owner id of the joining client\n- idStr: String - same as `_id` but in string format, so it can be exactly compared to user marker ids\n\n> [!NOTE]\n> **0** and **1** are special values:\n> - **0** means **everyone** (including the server)\n> - **1** means **current machine** but **is not implemented** and should **not** be used.\n\nIf a dedicated server was started without '-autoInit' option and this EH was created on server, on first GUI client this EH also fires against server, but after first client.\nIn mission's `initServer.sqf`:\n\n```sqf\naddMissionEventHandler [\"PlayerConnected\", {\n    diag_log \"Client connected\";\n    diag_log _this;\n}];\n```\n\nIn RPT:\n 2016/12/16, 15:39:09 \"Client connected\"\n 2016/12/16, 15:39:09 [1.51343e+009,\"7xxxxxxxxxxxxxxx1\",\"longbow\",false,3,\"1513430065\"]\n 2016/12/16, 15:39:34  Mission id: 5071d20b183e9580d0ee4f95f413ca18681d6165\n 2016/12/16, 15:39:34 \"Client connected\"\n 2016/12/16, 15:39:34 [2,\"\",\"__SERVER__\",false,2,\"2\"]\n\nThat happens only for GUI clients, if HC client connects first, EH does not fire for server.\n\nIf dedicated server was started with -autoInit option, this EH does not fire against server, only for future clients, and all further clients appear to be JIP'ed.\n\nInteresting moment for headless clients, for headless clients instead of getPlayerUID, handler gets string like \"HC12160\", where '12160' is headless client process ID (matches HC's PID observed in windows task manager)\n\n##### PlayerDisconnected (Arma 3 v1.58 Server Execution)\n\nExecutes assigned code when client leaves the mission in MP. Stackable version of onPlayerDisconnected.\n\n```sqf\naddMissionEventHandler [\"PlayerDisconnected\", {\n    params [\"_id\", \"_uid\", \"_name\", \"_jip\", \"_owner\", \"_idstr\"];\n}];\n```\n\n- id: Number - unique DirectPlay ID (very large number). It is also the same id used for user placed markers (same as `_id` param)\n- uid: String - getPlayerUID of the leaving client. The same as Steam ID (same as `_uid` param)\n- name: String - profileName of the leaving client (same as `_name` param)\n- jip: Boolean - didJIP of the leaving client (same as `_jip` param)\n- owner: Number - owner id of the leaving client (same as `_owner` param)\n- idstr: String - same as id but in string format, so could be exactly compared to user marker ids\n\n##### PlayerViewChanged (Arma 3 v1.66)\n\nFired on player view change. Player view changes when player is changing body due to teamSwitch, gets in out of a vehicle or operates UAV for example.\n\n```sqf\naddMissionEventHandler [\"PlayerViewChanged\", {\n    params [\n        \"_oldUnit\", \"_newUnit\", \"_vehicleIn\",\n        \"_oldCameraOn\", \"_newCameraOn\", \"_uav\"\n    ];\n}];\n```\n\n- oldUnit: Object - player body before EH fired\n- newUnit: Object - player body after EH fired\n- vehicleIn: Object - vehicle player is in (objNull if not in vehicle)\n- oldCameraOn: Object - cameraOn before EH fired\n- newCameraOn: Object - cameraOn after EH fired\n- uav: Object - UAV reference if player is operating one (objNull if not operating UAV)\n\n##### PreloadStarted (Arma 3 v1.58)\n\nExecutes assigned code before the mission preload screen. Stackable version of onPreloadStarted.\n\n> [!IMPORTANT]\n> This event handler also fires on client after user closes the main map.\n\n```sqf\naddMissionEventHandler [\"PreloadStarted\", {\n    // no params\n}];\n```\n\n##### PreloadFinished (Arma 3 v1.58)\n\nExecutes assigned code after the mission preload screen. Stackable version of onPreloadFinished.\n\n> [!IMPORTANT]\n> This event handler also fires on client after user closes the main map.\n\n```sqf\naddMissionEventHandler [\"PreloadFinished\", {\n    // no params\n}];\n```\n\n##### ProjectileCreated (Arma 3 v2.10)\n\nTriggered when a projectile is created.\n\n```sqf\naddMissionEventHandler [\"ProjectileCreated\", {\n    params [\"_projectile\"];\n}];\n```\n\n##### SaveGame (Arma 3 v2.18)\n\nTriggered just BEFORE the game saving process started but isSaving is already set to true. To know when the saving is finished check when isSaving returns false.\n\n```sqf\naddMissionEventHandler [\"SaveGame\", {\n    params [\"_saveType\"];\n}];\n```\n\n- saveType: String - one of \"autosaveold\", \"autosave\", \"save\", \"save2\", \"save3\", \"save4\", \"save5\", \"save6\", \"continue\" or \"\".\n\n##### ScriptError (Arma 3 v2.14)\n\nTriggered when a script error occurs. See also the `-showScriptErrors` startup parameter.\n\n> [!NOTE]\n> Event Handlers have a recursion check. Most of them have a level limit set to **1**;\n> **ScriptError** has it set to **2** - meaning that an error occuring inside the Event Handler will trigger once more the EH, but no more than two times total.\n\n```sqf\naddMissionEventHandler [\"ScriptError\", {\n    params [\"_errorText\", \"_sourceFile\", \"_lineNumber\", \"_errorPos\", \"_content\", \"_stackTraceOutput\"];\n}];\n```\n\n- errorText: String - e.g. \"Zero Divisor\"\n- sourceFile: String - empty string if spawned Code\n- lineNumber: Number - script's line number\n- errorPos: Number - script's error byte position in the script *content*\n- content: String - the whole script's Code as String\n- stackTraceOutput: Array - see diag_stacktrace output\n\n##### ScriptSpawned (Arma 3 v2.22)\n\nExecutes when any script is spawned.\n\n```sqf\naddMissionEventHandler [\"ScriptSpawned\", {\n    params [\"_data\"];\n}];\n```\n\n- _data: Array with [fileName, content, hash, parentFileName, parentLine, parentScript]\n  - fileName: String - file name of the spawned script, empty when not available\n  - content: String - content of the spawned script\n  - hash: String - hash value of the Script Handle\n  - parentFileName String - file name of the parent script, empty when not available\n  - parentLine: Number - line number of the parent script\n  - parentScript: String - content of the parent script\n\n##### SelectedActionPerformed\n\nRTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality\n\n##### SelectedActionChanged\n\nRTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality\n\n##### SelectedRotorLibActionPerformed\n\nRTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedRotorLibActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Works only for key press combination `RightCtrl` + `W`, which is the binding for helicopter wheels brakes. It fires with or without Advanced Flight Model enabled. The enum number returned is 4 and 5, probably because the enum is structured like this:\n>\n> 0: HelicopterAutoTrimOn\n>\n> 1: HelicopterAutoTrimOff\n>\n> 2: HelicopterTrimOn\n>\n> 3: HelicopterTrimOff\n>\n> 4: WheelsBrakeOn\n>\n> 5: WheelsBrakeOff\n\n##### SelectedRotorLibActionChanged\n\nRTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedRotorLibActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality\n\n##### Service (Arma 3 v2.12)\n\nExecutes assigned code when a serviced vehicle gets rearmed, repaired or refueled. The code executes with interval while the serviced vehicle receives service. If the code returns true the default on-screen service message is not shown.\n\n```sqf\naddMissionEventHandler [\"Service\", {\n    params [\"_serviceVehicle\", \"_servicedVehicle\", \"_serviceType\", \"_needsService\", \"_autoSupply\"];\n}];\n```\n\n- serviceVehicle: Object - service vehicle\n- servicedVehicle: Object - vehicle receiving service\n- serviceType: Number - 0 - MINOR REPAIR, 1 - REPAIR, 2 - REFUEL, 3 - REARM\n- needsService: Number - how much serviced vehicle needsSevice, 0..1 where 0 - no need, 1 - need a lot\n- autoSupply: Boolean - true if supply started by proximity, false if supply started due to user action\n\n##### TeamSwitch (Arma 3 v1.58)\n\nExecutes assigned code when player teamswitches. Stackable version of onTeamSwitch.\n\n```sqf\naddMissionEventHandler [\"TeamSwitch\", {\n    params [\"_previousUnit\", \"_newUnit\"];\n}];\n```\n\n- previousUnit: Object - switching from unit (same as `_from` param)\n- newUnit: Object - switching to unit (same as `_to` param)\n\n##### UAVCrewCreated (Arma 3 v2.14)\n\nFires when UAV or UGV is assembled from Backpack after the AI crew is created\n\n```sqf\naddMissionEventHandler [\"UAVCrewCreated\", {\n    params [\"_uav\", \"_driver\", \"_gunner\"];\n}];\n```\n\n- uav: Object - the assembled weapon\n- driver: Object - AI driver\n- gunner: Object - AI gunner","sections":[{"heading":null,"level":1,"markdown":"Arma 3 v0.50 Local Effect\n\nMission event handlers are specific EHs that are anchored to the running mission and automatically removed when mission is over.\nThese events fire only on the machine where they have been added.\n\nFor all other available EHs see the Event Handlers main page.\n\n> [!NOTE]\n> **OnUser...** mission event handlers used in combination with getUserInfo provide a way to track server users from the very early stage of joining a server to the very last stage of leaving the server. All these event handlers are designed to be used server side and return unique user network id in String format as the first param. These ids could also be obtained via getPlayerID and allUsers script commands. There may be other params specific to each event. See:\n>\n> - #OnUserConnected\n> - #OnUserDisconnected\n> - #OnUserClientStateChanged\n> - #OnUserAdminStateChanged\n> - #OnUserSelectedPlayer\n> - #OnUserKicked"},{"heading":"Related Commands","level":3,"markdown":"- addMissionEventHandler\n- removeMissionEventHandler\n- removeAllMissionEventHandlers"},{"heading":"Events","level":3,"markdown":""},{"heading":"ActionTargetChanged (Arma 3 v2.22)","level":5,"markdown":"Executes when action target object changes under cursor. This event handler fires before user actions are processed and added to the player.\n\n```sqf\naddMissionEventHandler [\"ActionTargetChanged\", {\n    params [\"_newActionTarget\", \"_oldActionTarget\"];\n}];\n```\n\n- newActionTarget: Object\n- oldActionTarget: Object"},{"heading":"ArtilleryShellFired (Arma 3 v2.18)","level":5,"markdown":"Global Mission Event Handler. Executes each time a vehicle classified as artillery (has an artillery computer) fires a shell.\n\n```sqf\naddMissionEventHandler [\"ArtilleryShellFired\", {\n    params [\"_vehicle\", \"_weapon\", \"_ammo\", \"_gunner\", \"_instigator\", \"_artilleryTarget\", \"_targetPosition\", \"_shell\"];\n}];\n```\n\n- vehicle: Object - artillery vehicle firing the shell\n- weapon: String - weapon name\n- ammo: String - ammo name\n- gunner: Object - gunner\n- instigator: Object - instigator\n- artilleryTarget: Object - artillery target object\n- targetPosition: Position - ground position the shell is aimed at\n- shell: Object - the projectile"},{"heading":"BuildingChanged (Arma 3 v1.68)","level":5,"markdown":"Fired each time a building model changes, for example due to stages of destruction.\n\n```sqf\naddMissionEventHandler [\"BuildingChanged\", {\n    params [\"_from\", \"_to\", \"_isRuin\"];\n}];\n```\n\n- from: Object - building it changes from\n- to: Object - building it changes to\n- isRuin: Boolean - true if changes to ruins"},{"heading":"CommandModeChanged (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code when user switches to/from High Command mode (<kbd>LShift</kbd>+<kbd>Space</kbd>). Stackable version of onCommandModeChanged.\n\n```sqf\naddMissionEventHandler [\"CommandModeChanged\", {\n    params [\"_isHighCommand\", \"_isForced\"];\n}];\n```\n\n- isHighCommand: Boolean - same as `_isHighCommand` param\n- isForced: Boolean - true if command mode was forced"},{"heading":"ControlsShifted (Arma 3 v1.00)","level":5,"markdown":"Triggers when control of a vehicle is shifted (pilot->co-pilot, co-pilot->pilot), usually when user performs an action such as TakeVehicleControl, SuspendVehicleControl, UnlockVehicleControl, LockVehicleControl, or when enableCopilot command is used. This event handler will always fire on the PC where action is triggered as well as where the vehicle is local at the time. When control of the vehicle is shifted, the locality of the vehicle changes to the locality of the new controller. Since Arma 3 v1.96 this EH is extended with additional params.\n\n```sqf\naddMissionEventHandler [\"ControlsShifted\", {\n    params [\"_newController\", \"_oldController\", \"_vehicle\", \"_copilotEnabled\", \"_controlsUnlocked\"];\n}];\n```\n\n- newController: Object - unit currently controlling the vehicle\n- oldController: Object - unit previously controlling the vehicle\n- vehicle: Object - the vehicle for which controls shifted\n- copilotEnabled: Boolean - true if copilot is enabled\n- controlsUnlocked: Boolean - true if controls are unlocked"},{"heading":"DisplayOpened (Arma 3 v2.22)","level":5,"markdown":"Executes when any display is opened.\n\n```sqf\naddMissionEventHandler [\"DisplayOpened\", {\n    params [\"_display\", \"_configClass\"];\n}];\n```\n\n- display: Display\n- configClass: Config"},{"heading":"Draw2D (Arma 3 v2.18)","level":5,"markdown":"Runs after all UI has been drawn. Runs the EH code each frame in unscheduled environment. Client side EH only (presence of UI).\nWill stop executing when UI loses focus (<kbd>Alt</kbd>+<kbd>Tab</kbd> for example). Usually used with drawIcon.\n\n```sqf\naddMissionEventHandler [\"Draw2D\", {\n    // no params\n}];\n```"},{"heading":"Draw3D (Arma 3 v0.50)","level":5,"markdown":"Runs the EH code each frame in unscheduled environment. Client side EH only (presence of UI).\nWill stop executing when UI loses focus (<kbd>Alt</kbd>+<kbd>Tab</kbd> for example). Usually used with drawIcon3D, drawLine3D.\n\n```sqf\naddMissionEventHandler [\"Draw3D\", {\n    // no params\n}];\n```"},{"heading":"Drowned (Arma 3 v2.14)","level":5,"markdown":"Runs when a vehicle gets drowned (the vehicle is submerged below 'maxFord' for longer than 'waterResistance'). This will cause engine damage and for some vehicles that will render engine unusable until the vehicle/engine is fully repared. Some vehicles can drown but would still be recoverable as they wouldn't be destroyed. The event handler will also fire when vehicle is removed from water, in which case 'drowned' param will change to false. To check if the engine was damaged by water use waterDamaged command.\n\n```sqf\naddMissionEventHandler [\"Drowned\", {\n    params [\"_vehicle\", \"_drowned\"];\n}];\n```"},{"heading":"EachFrame (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code each frame. Stackable version of onEachFrame.\n\n```sqf\naddMissionEventHandler [\"EachFrame\", {\n    // no params\n}];\n```"},{"heading":"Ended (Arma 3 v0.50)","level":5,"markdown":"Triggered when mission ends, either using trigger of type \"End\", endMission command, BIS_fnc_endMission function or ENDMISSION cheat.\n\n```sqf\naddMissionEventHandler [\"Ended\", {\n    params [\"_endType\"];\n}];\n```\n\n- endType: String - mission end type. Used in Debriefing among other things"},{"heading":"MPEnded (Arma 3 v1.60)","level":5,"markdown":"Triggered when the server switches off from \"playing\" state (mission ends, server closes, etc.) It's only for MP games, it is called on server and also on clients. It is not called on clients when client disconnects from server (and mission continues). This EH has no arguments passed to the code.\n\n```sqf\naddMissionEventHandler [\"MPEnded\", {\n    // no params\n}];\n```\n\nIf client code must be executed on disconnect, this code can be used instead:\n\n```sqf\n0 spawn\n{\n    waitUntil { !isNull findDisplay 46 };\n    findDisplay 46 displayAddEventHandler [\"Unload\",\n    {\n        // code here gets executed on the client at end of mission, whether due to player abort, loss of connection, or mission ended by server\n        // might not work on headless clients\n    }];\n};\n```"},{"heading":"EntityCreated (Arma 3 v2.10)","level":5,"markdown":"Triggered when an entity is created.\n\n> [!NOTE]\n> Unlike most event handlers, the argument is entity Object and not an array containing the entity. However, it is recommended to use params to make sure the code remains compatible in case the event arguments are expanded in the future.\n\n> [!IMPORTANT]\n> This event is called before variable namespace is copied to **remote** respawning entity, keep this in mind so your setVariables are not overwritten in the next frame. EntityRespawned always fires after variable namespace is copied to new entity regardless of locality.\n\n```sqf\naddMissionEventHandler [\"EntityCreated\", {\n    params [\"_entity\"];\n}];\n```"},{"heading":"EntityDeleted (Arma 3 v2.18)","level":5,"markdown":"Triggered when an entity is deleted. It only triggers for objects that support the \"Deleted\" event handler, such as vehicles, soldiers, animals, and houses. Simple objects for example are not supported.\n\n> [!NOTE]\n> Unlike most event handlers, the argument is entity Object and not an array containing the entity. However, it is recommended to use params to make sure the code remains compatible in case the event arguments are expanded in the future.\n\n```sqf\naddMissionEventHandler [\"EntityDeleted\", {\n    params [\"_entity\"];\n}];\n```"},{"heading":"EntityKilled (Arma 3 v1.56)","level":5,"markdown":"Triggered when an entity is killed.\n\n```sqf\naddMissionEventHandler [\"EntityKilled\", {\n    params [\"_unit\", \"_killer\", \"_instigator\", \"_useEffects\"];\n}];\n```\n\n- unit: Object - entity that was killed\n- killer: Object - the killer (vehicle or person)\n- Arma 3 v1.66 instigator: Object - person who pulled the trigger\n- Arma 3 v1.68 useEffects: Boolean - same as *useEffects* in setDamage alt syntax\n\n---\n\nIt's worth noting that *instigator* param is objNull during road kill. To work around this issue try:\n\n```sqf\naddMissionEventHandler [\"EntityKilled\", {\n    params [\"_killed\", \"_killer\", \"_instigator\"];\n    if (isNull _instigator) then { _instigator = UAVControl vehicle _killer select 0 }; // UAV/UGV player operated road kill\n    if (isNull _instigator) then { _instigator = _killer }; // player driven vehicle road kill\n    hint format [\"Killed By %1\", name _instigator];\n}];\n```"},{"heading":"EntityRespawned (Arma 3 v1.56)","level":5,"markdown":"Triggered when an entity is respawned.\n\n```sqf\naddMissionEventHandler [\"EntityRespawned\", {\n    params [\"_newEntity\", \"_oldEntity\"];\n}];\n```\n\n- newEntity: Object - respawned entity\n- oldEntity: Object - corpse/wreck"},{"heading":"ExtensionCallback (Arma 3 v1.96)","level":5,"markdown":"Triggered when an extension calls provided function pointer with 3 params.\n\n```sqf\naddMissionEventHandler [\"ExtensionCallback\", {\n    params [\"_name\", \"_function\", \"_data\"];\n}];\n```\n\n- name: String - user provided param\n- function: String - user provided param\n- data: String - user provided param"},{"heading":"GroupCreated (Arma 3 v2.04)","level":5,"markdown":"Triggered when a Group is created. Note that the group contains **no** units at that point!\n\n```sqf\naddMissionEventHandler [\"GroupCreated\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group - the created group"},{"heading":"GroupDeleted (Arma 3 v2.04)","level":5,"markdown":"Triggered when a Group is manually or automatically deleted.\n\n```sqf\naddMissionEventHandler [\"GroupDeleted\", {\n    params [\"_group\"];\n}];\n```\n\n- group: Group - the deleted group"},{"heading":"GroupIconClick (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code when user clicks on the HC group icon on the map. If groupIconSelectable is true, LMB clicking (firing) at the HC group icon on the HUD will also trigger the event. To set group icon selectable use setGroupIconsSelectable. Stackable version of onGroupIconClick.\n\n```sqf\naddMissionEventHandler [\"GroupIconClick\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_mouseButton\", \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- mouseButton: Number - mouse button: 0 - <kbd>LMB</kbd>, 1 - <kbd>RMB</kbd> (only applicable to IconClick)\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed"},{"heading":"GroupIconOverEnter (Arma 3 v1.58)","level":5,"markdown":"**Continuously** executes assigned code when user hovers with pointer over the HC group icon, either on the HUD or the main map. groupIconSelectable must be set to true for this EH to work at all. To set group icon selectable use setGroupIconsSelectable. When EH fires over the HUD icon, X and Y coordinates will change depending on the position of the pointer in relation to the icon area. When over main map, the X and Y do not change and indicate icon center. Stackable version of onGroupIconOverEnter.\n\n```sqf\naddMissionEventHandler [\"GroupIconOverEnter\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed"},{"heading":"GroupIconOverLeave (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code when user moves the pointer away from HC group icon it was over. Fires either for on the HUD icons or the main map HC icons. groupIconSelectable must be set to true for this EH to work at all. To set group icon selectable use setGroupIconsSelectable. Stackable version of onGroupIconOverLeave.\n\n```sqf\naddMissionEventHandler [\"GroupIconOverLeave\", {\n    params [\n        \"_is3D\", \"_group\", \"_waypointId\",\n        \"_posX\", \"_posY\",\n        \"_shift\", \"_control\", \"_alt\"\n    ];\n}];\n```\n\n- is3D: Boolean - true if HUD icon, false if main map icon\n- group: Group - group the icon belonds to\n- waypointId: Number - waypoint ID\n- posX: Number - screen X of the mouse\n- posY: Number - screen Y of the mouse (Y is always 0 when leaving HUD icon for some reason)\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed\n- ctrl: Boolean - true if <kbd>Ctrl</kbd> key was pressed\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed"},{"heading":"HandleAccTime (Arma 3 v1.90)","level":5,"markdown":"Fires when user changes time acceleration with +/- keys in SP or setAccTime command. If the code returns true the on-screen message confirming the change is not displayed. Doesn't fire if desired value is already set.\n\n```sqf\naddMissionEventHandler [\"HandleAccTime\", {\n    params [\"_currentTimeAcc\", \"_prevTimeAcc\", \"_messageSuppressed\"];\n}];\n```\n\n- currentTimeAcc: Number - current value\n- prevTimeAcc: Number - previous value\n- messageSuppressed: Boolean - true if on-screen message was suppressed"},{"heading":"HandleChatMessage (Arma 3 v2.00)","level":5,"markdown":"Fires when a message is received, before adding it to the chat feed. Fires clientside.\n\n> [!NOTE]\n> - On a dedicated server and headless client it fires only for global (channel 0) and system messages (channel 16).\n> - The HandleChatMessage EH can be used to disable/modify system messages like \"Player NAME connecting/is losing connection\".\n\n> [!IMPORTANT]\n> Does not trigger for any of the chat related script command such as systemChat, sideChat, or other chat commands.\n\nThe output message could be overridden:\n- Return true to block incoming chat message from being added to the chat feed.\n- Return String to replace the chat message content but not the sender name.\n- Return Array [from, text] to replace both the chat message content and the the sender's name.\n\n> [!IMPORTANT]\n> Only the last added HandleChatMessage EH with override will be used to override the message.\n\n> [!WARNING]\n> Do not put any of the chat related script command such as systemChat, sideChat, etc in this EH code as it would naturally cause recursion and the game will freeze.\n\n```sqf\naddMissionEventHandler [\"HandleChatMessage\", {\n    params [\"_channel\", \"_owner\", \"_from\", \"_text\", \"_person\", \"_name\", \"_strID\", \"_forcedDisplay\", \"_isPlayerMessage\", \"_sentenceType\", \"_chatMessageType\", \"_params\"];\n}];\n```\n\n- channel: Number - see radio channel indices (16 for system chat message for example)\n- owner: Number - owner id of the sender:\n  - in SP: 0\n  - in MP with no sender: clientOwner\n  - in MP with sender: sender's clientOwner, or if AI - creator id part of netId of the AI\n- from: String - sender's formatted name as appeared on the chat\n- text: String - the chat message\n- person: Object - sender's object\n- name: String - sender's name, could be different from `from`\n- strID: String - sender's network player ID (marker id):\n  - \"-1\": means not available\n  - \"0\": means isPlayer in SP\n  - \"1\": means AI in SP or MP\n  - >1: getPlayerID in MP\n- forcedDisplay: Boolean - if the message should be displayed when the chat list is disabled (when enableRadio is set to false radio protocol messages won't display)\n- isPlayerMessage: Boolean - if the message is addressed to player\n- sentenceType: Number - 0: Normal type, 1: Protocol type\n- chatMessageType: Number - 0: Generic type, 1: SimpleMove type, 2: KillConfirmation type\n- params: Array of Strings - sentence parameters, if any"},{"heading":"HandleDisconnect (Arma 3 v1.32 Server Execution)","level":5,"markdown":"Triggered right after a player disconnects from the game, more accurately when a player-controlled unit changes ownership due to the owning player being disconnected (disconnected player information is no available through e.g getUserInfo anymore).\nSimilar to the #PlayerDisconnected event but contains the unit occupied by the player before their disconnection.\nMust be added on the server and triggers only on the server.\n\n> [!IMPORTANT]\n> A player disconnecting while not controlling a unit (not spawned, deleted unit, etc) does **not** trigger this event.\n\n```sqf\naddMissionEventHandler [\"HandleDisconnect\", {\n    params [\"_unit\", \"_id\", \"_uid\", \"_name\"];\n    true;\n}];\n```\n\n- unit: Object - unit formerly occupied by player\n- id: Number - same as _id in onPlayerDisconnected\n- uid: String - same as _uid in onPlayerDisconnected\n- name: String - same as _name in onPlayerDisconnected\n**Override**: if this EH code returns true, the unit, previously occupied by player, gets transferred to the server, becomes AI and continues to live, even with description.ext param `disabledAI = 1;`."},{"heading":"HCGroupSelectionChanged (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code when user selects available HC group (`F1, F2…`). Stackable version of onHCGroupSelectionChanged.\n\n```sqf\naddMissionEventHandler [\"HCGroupSelectionChanged\", {\n    params [\"_group\", \"_isSelected\"];\n}];\n```\n\n- group: Group - group selected (same as `_group` param)\n- isSelected: Boolean - true if selected (same as `_isSelected` param)"},{"heading":"Loaded (Arma 3 v0.50)","level":5,"markdown":"Triggered when mission is loaded from save.\n\n> [!WARNING]\n> \"Loaded\" event handler should be added BEFORE the mission is loaded from save. Placing it in a function with preInit = 1; usually does the trick.\n\n```sqf\naddMissionEventHandler [\"Loaded\", {\n    params [\"_saveType\"];\n}];\n```\n\n- savingType: String - one of \"autosaveold\", \"autosave\", \"save\", \"save2\", \"save3\", \"save4\", \"save5\", \"save6\", \"continue\" or \"\".\n  - \"save\" - custom save, achieved by pressing SAVE button in the pause menu\n  - \"autosave\" - automatic checkpoint, saved using saveGame command\n  - \"continue\" - saved when leaving a mission to the main menu"},{"heading":"Map (Arma 3 v1.62)","level":5,"markdown":"Triggered when map is opened or closed either by user action or script command openMap.\n\n```sqf\naddMissionEventHandler [\"Map\", {\n    params [\"_mapIsOpened\", \"_mapIsForced\"];\n}];\n```\n\n- mapIsOpened: Boolean - true if map is opened\n- mapIsForced: Boolean - true if map is forced"},{"heading":"MapSingleClick (Arma 3 v1.58)","level":5,"markdown":"Executes when the player clicks anywhere on the main map. Stackable version of onMapSingleClick with the limitation that it does not have the ability to override the click (e.g. to prevent the player from placing the custom waypoint with <kbd>LShift</kbd>+<kbd>LMB</kbd>). Since the introduction of `_thisArgs` for addMissionEventHandler in Arma 3 v2.04, this EH also supports custom arguments (just like onMapSingleClick).\n\n```sqf\naddMissionEventHandler [\"MapSingleClick\", {\n    params [\"_units\", \"_pos\", \"_alt\", \"_shift\"];\n}];\n```\n\n- units: Array - leader selected units, same as groupSelectedUnits (same as onMapSingleClick's `_units` variable)\n- pos: Array - world Position3D of the click in format `[x, y, 0]` (same as onMapSingleClick's `_pos` variable)\n- alt: Boolean - true if <kbd>Alt</kbd> key was pressed (same as onMapSingleClick's `_alt` variable)\n- shift: Boolean - true if <kbd>Shift</kbd> key was pressed (same as onMapSingleClick's `_shift` variable)"},{"heading":"MarkerCreated (Arma 3 v2.02)","level":5,"markdown":"Executes when a marker is created either by a user or via script command.\n\n```sqf\naddMissionEventHandler [\"MarkerCreated\", {\n    params [\"_marker\", \"_channelNumber\", \"_owner\", \"_local\"];\n}];\n```\n\n- marker: String - the name of the created marker, can be used with the marker commands\n- channelNumber: Number - channel in which the marker was created\n- owner: Object - player that created the marker or objNull\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network"},{"heading":"MarkerDeleted (Arma 3 v2.02)","level":5,"markdown":"Executes immediately before a marker is deleted either by a user or via script command.\n\n```sqf\naddMissionEventHandler [\"MarkerDeleted\", {\n    params [\"_marker\", \"_local\", \"_deleter\"];\n}];\n```\n\n- marker: String - the name of the deleted marker\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network\n- Arma 3 v2.20 deleter: Object - the player/curator unit that deleted the marker"},{"heading":"MarkerUpdated (Arma 3 v2.02)","level":5,"markdown":"Executes when a marker is changed.\n\n> [!WARNING]\n> Changing the marker in the EH code will lead to an infinite loop and the game will crash!\n\n```sqf\naddMissionEventHandler [\"MarkerUpdated\", {\n    params [\"_marker\", \"_local\"];\n}];\n```\n\n- marker: String - the name of the marker\n- Arma 3 v2.04 local: Boolean - true if the event originated locally, false if it came over the network"},{"heading":"OnUserConnected (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code on user joining server.\n\n```sqf\naddMissionEventHandler [\"OnUserConnected\", {\n    params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber) - always 1\n- clientState: String - client state (see getClientState) - always \"CREATED\""},{"heading":"OnUserDisconnected (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code on user leaving server.\n\n```sqf\naddMissionEventHandler [\"OnUserDisconnected\", {\n        params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber) - always 0\n- clientState: String - client state (see getClientState) - always \"NONE\""},{"heading":"OnUserClientStateChanged (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code for every stage of user client state change.\n\n```sqf\naddMissionEventHandler [\"OnUserClientStateChanged\", {\n    params [\"_networkId\", \"_clientStateNumber\", \"_clientState\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- clientStateNumber: Number - client state number (see getClientStateNumber)\n- clientState: String - client state (see getClientState)"},{"heading":"OnUserAdminStateChanged (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code after user logs in, gets voted in or logs out as admin.\n\n```sqf\naddMissionEventHandler [\"OnUserAdminStateChanged\", {\n    params [\"_networkId\", \"_loggedIn\", \"_votedIn\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- loggedIn: Boolean - true if user logged in or got voted in as admin, false if logged out (see admin)\n- votedIn: Boolean - true if user got voted in as admin, false otherwise (see admin)"},{"heading":"OnUserSelectedPlayer (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code after player object is selected for user to take over control, the ownership information is broadcast and request to sync is made but the object is still owned by previous owner for a short time.\n\n```sqf\naddMissionEventHandler [\"OnUserSelectedPlayer\", {\n        params [\"_networkId\", \"_playerObject\", \"_attempts\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- playerObject: Object - player object to be controlled by the user (see player, selectPlayer)\n- Arma 3 v2.18 attempts: Number - how many times server was trying to obtain non-null playerObject. Current threshold after which the event will fire anyway is 50.\n\n> [!IMPORTANT]\n> This is the earliest the player object is known when player joins the server, but it is not local to the user yet, so there is a wait time depending on network connection. When player respawns, the unit created on the client and so it might take a while before server has valid player object. From Arma 3 v2.18 the server will pospone this event until the object is not null, or until it tried 50 times, whichever is earlier. The best approach to handle this matter and get notified about completion of the transfer of the ownership is to use \"Local\" entity event handler, like so:\n>\n> ```sqf\n> addMissionEventHandler [\"OnUserSelectedPlayer\", {\n>     params [\"_networkId\", \"_playerObject\", \"_attempts\"];\n>     _playerObject addEventHandler [\"Local\",\n>     {\n>         params [\"_player\"];\n>         _player removeEventHandler [\"Local\", _thisEventHandler];\n>         // code to handle _player\n>     }];\n> }];\n> ```\n>\n> Note that the player object would change locality again if the user goes to lobby."},{"heading":"OnUserKicked (Arma 3 v2.06 Server Execution)","level":5,"markdown":"Executes assigned code after after a user has been kicked from the server providing kick reason. The possible values for 'kickTypeNumber' and 'kickType' are:\n0 : `\"TIMEOUT\"`, 1 : `\"DISCONNECTED\"`, 2 : `\"KICKED\"`, 3 : `\"BANNED\"`, 4 : `\"MISSING ADDON\"`, 5 : `\"BAD CD KEY\"`, 6 : `\"CD KEY IN USE\"`, 7 : `\"SESSION LOCKED\"`, 8 : `\"BATTLEYE\"`, 9 : `\"STEAM CHECK\"`, 10 : `\"DLC CONTENT\"`, 11 : `\"GS TIMEOUT\"`, 12 : `\"SCRIPT\"`, 13 : `\"OTHER\"`\n\n```sqf\naddMissionEventHandler [\"OnUserKicked\", {\n    params [\"_networkId\", \"_kickTypeNumber\", \"_kickType\", \"_kickReason\", \"_kickMessageIncReason\"];\n}];\n```\n\n- networkId: String - user network id (see getPlayerID, allUsers)\n- kickTypeNumber: Number - kick type number (see above)\n- kickType: String - kick type (see above)\n- kickReason: String - reason given for the kick by the admin or by other means\n- kickMessageIncReason: String - formatted engine message including the given reason"},{"heading":"PlayerConnected (Arma 3 v1.58 Server Execution)","level":5,"markdown":"Executes assigned code when client joins the mission in MP. Stackable version of onPlayerConnected.\n\n```sqf\naddMissionEventHandler [\"PlayerConnected\", {\n    params [\"_id\", \"_uid\", \"_name\", \"_jip\", \"_owner\", \"_idStr\"];\n}];\n```\n\n- id: Number - unique DirectPlay ID (very large number). It is also the same id used for user placed markers\n- uid: String - getPlayerUID of the joining client. The same as Steam ID\n- name: String - profileName of the joining client\n- jip: Boolean - didJIP of the joining client\n- owner: Number - owner id of the joining client\n- idStr: String - same as `_id` but in string format, so it can be exactly compared to user marker ids\n\n> [!NOTE]\n> **0** and **1** are special values:\n> - **0** means **everyone** (including the server)\n> - **1** means **current machine** but **is not implemented** and should **not** be used.\n\nIf a dedicated server was started without '-autoInit' option and this EH was created on server, on first GUI client this EH also fires against server, but after first client.\nIn mission's `initServer.sqf`:\n\n```sqf\naddMissionEventHandler [\"PlayerConnected\", {\n    diag_log \"Client connected\";\n    diag_log _this;\n}];\n```\n\nIn RPT:\n 2016/12/16, 15:39:09 \"Client connected\"\n 2016/12/16, 15:39:09 [1.51343e+009,\"7xxxxxxxxxxxxxxx1\",\"longbow\",false,3,\"1513430065\"]\n 2016/12/16, 15:39:34  Mission id: 5071d20b183e9580d0ee4f95f413ca18681d6165\n 2016/12/16, 15:39:34 \"Client connected\"\n 2016/12/16, 15:39:34 [2,\"\",\"__SERVER__\",false,2,\"2\"]\n\nThat happens only for GUI clients, if HC client connects first, EH does not fire for server.\n\nIf dedicated server was started with -autoInit option, this EH does not fire against server, only for future clients, and all further clients appear to be JIP'ed.\n\nInteresting moment for headless clients, for headless clients instead of getPlayerUID, handler gets string like \"HC12160\", where '12160' is headless client process ID (matches HC's PID observed in windows task manager)"},{"heading":"PlayerDisconnected (Arma 3 v1.58 Server Execution)","level":5,"markdown":"Executes assigned code when client leaves the mission in MP. Stackable version of onPlayerDisconnected.\n\n```sqf\naddMissionEventHandler [\"PlayerDisconnected\", {\n    params [\"_id\", \"_uid\", \"_name\", \"_jip\", \"_owner\", \"_idstr\"];\n}];\n```\n\n- id: Number - unique DirectPlay ID (very large number). It is also the same id used for user placed markers (same as `_id` param)\n- uid: String - getPlayerUID of the leaving client. The same as Steam ID (same as `_uid` param)\n- name: String - profileName of the leaving client (same as `_name` param)\n- jip: Boolean - didJIP of the leaving client (same as `_jip` param)\n- owner: Number - owner id of the leaving client (same as `_owner` param)\n- idstr: String - same as id but in string format, so could be exactly compared to user marker ids"},{"heading":"PlayerViewChanged (Arma 3 v1.66)","level":5,"markdown":"Fired on player view change. Player view changes when player is changing body due to teamSwitch, gets in out of a vehicle or operates UAV for example.\n\n```sqf\naddMissionEventHandler [\"PlayerViewChanged\", {\n    params [\n        \"_oldUnit\", \"_newUnit\", \"_vehicleIn\",\n        \"_oldCameraOn\", \"_newCameraOn\", \"_uav\"\n    ];\n}];\n```\n\n- oldUnit: Object - player body before EH fired\n- newUnit: Object - player body after EH fired\n- vehicleIn: Object - vehicle player is in (objNull if not in vehicle)\n- oldCameraOn: Object - cameraOn before EH fired\n- newCameraOn: Object - cameraOn after EH fired\n- uav: Object - UAV reference if player is operating one (objNull if not operating UAV)"},{"heading":"PreloadStarted (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code before the mission preload screen. Stackable version of onPreloadStarted.\n\n> [!IMPORTANT]\n> This event handler also fires on client after user closes the main map.\n\n```sqf\naddMissionEventHandler [\"PreloadStarted\", {\n    // no params\n}];\n```"},{"heading":"PreloadFinished (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code after the mission preload screen. Stackable version of onPreloadFinished.\n\n> [!IMPORTANT]\n> This event handler also fires on client after user closes the main map.\n\n```sqf\naddMissionEventHandler [\"PreloadFinished\", {\n    // no params\n}];\n```"},{"heading":"ProjectileCreated (Arma 3 v2.10)","level":5,"markdown":"Triggered when a projectile is created.\n\n```sqf\naddMissionEventHandler [\"ProjectileCreated\", {\n    params [\"_projectile\"];\n}];\n```"},{"heading":"SaveGame (Arma 3 v2.18)","level":5,"markdown":"Triggered just BEFORE the game saving process started but isSaving is already set to true. To know when the saving is finished check when isSaving returns false.\n\n```sqf\naddMissionEventHandler [\"SaveGame\", {\n    params [\"_saveType\"];\n}];\n```\n\n- saveType: String - one of \"autosaveold\", \"autosave\", \"save\", \"save2\", \"save3\", \"save4\", \"save5\", \"save6\", \"continue\" or \"\"."},{"heading":"ScriptError (Arma 3 v2.14)","level":5,"markdown":"Triggered when a script error occurs. See also the `-showScriptErrors` startup parameter.\n\n> [!NOTE]\n> Event Handlers have a recursion check. Most of them have a level limit set to **1**;\n> **ScriptError** has it set to **2** - meaning that an error occuring inside the Event Handler will trigger once more the EH, but no more than two times total.\n\n```sqf\naddMissionEventHandler [\"ScriptError\", {\n    params [\"_errorText\", \"_sourceFile\", \"_lineNumber\", \"_errorPos\", \"_content\", \"_stackTraceOutput\"];\n}];\n```\n\n- errorText: String - e.g. \"Zero Divisor\"\n- sourceFile: String - empty string if spawned Code\n- lineNumber: Number - script's line number\n- errorPos: Number - script's error byte position in the script *content*\n- content: String - the whole script's Code as String\n- stackTraceOutput: Array - see diag_stacktrace output"},{"heading":"ScriptSpawned (Arma 3 v2.22)","level":5,"markdown":"Executes when any script is spawned.\n\n```sqf\naddMissionEventHandler [\"ScriptSpawned\", {\n    params [\"_data\"];\n}];\n```\n\n- _data: Array with [fileName, content, hash, parentFileName, parentLine, parentScript]\n  - fileName: String - file name of the spawned script, empty when not available\n  - content: String - content of the spawned script\n  - hash: String - hash value of the Script Handle\n  - parentFileName String - file name of the parent script, empty when not available\n  - parentLine: Number - line number of the parent script\n  - parentScript: String - content of the parent script"},{"heading":"SelectedActionPerformed","level":5,"markdown":"RTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality"},{"heading":"SelectedActionChanged","level":5,"markdown":"RTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality"},{"heading":"SelectedRotorLibActionPerformed","level":5,"markdown":"RTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedRotorLibActionPerformed\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Works only for key press combination `RightCtrl` + `W`, which is the binding for helicopter wheels brakes. It fires with or without Advanced Flight Model enabled. The enum number returned is 4 and 5, probably because the enum is structured like this:\n>\n> 0: HelicopterAutoTrimOn\n>\n> 1: HelicopterAutoTrimOff\n>\n> 2: HelicopterTrimOn\n>\n> 3: HelicopterTrimOff\n>\n> 4: WheelsBrakeOn\n>\n> 5: WheelsBrakeOff"},{"heading":"SelectedRotorLibActionChanged","level":5,"markdown":"RTM helicopter user action event\n\n```sqf\naddMissionEventHandler [\"SelectedRotorLibActionChanged\", {\n    params [\"_caller\", \"_target\", \"_enumNumber\", \"_actionId\"];\n}];\n```\n\n> [!IMPORTANT]\n> Limited or non-existent functionality"},{"heading":"Service (Arma 3 v2.12)","level":5,"markdown":"Executes assigned code when a serviced vehicle gets rearmed, repaired or refueled. The code executes with interval while the serviced vehicle receives service. If the code returns true the default on-screen service message is not shown.\n\n```sqf\naddMissionEventHandler [\"Service\", {\n    params [\"_serviceVehicle\", \"_servicedVehicle\", \"_serviceType\", \"_needsService\", \"_autoSupply\"];\n}];\n```\n\n- serviceVehicle: Object - service vehicle\n- servicedVehicle: Object - vehicle receiving service\n- serviceType: Number - 0 - MINOR REPAIR, 1 - REPAIR, 2 - REFUEL, 3 - REARM\n- needsService: Number - how much serviced vehicle needsSevice, 0..1 where 0 - no need, 1 - need a lot\n- autoSupply: Boolean - true if supply started by proximity, false if supply started due to user action"},{"heading":"TeamSwitch (Arma 3 v1.58)","level":5,"markdown":"Executes assigned code when player teamswitches. Stackable version of onTeamSwitch.\n\n```sqf\naddMissionEventHandler [\"TeamSwitch\", {\n    params [\"_previousUnit\", \"_newUnit\"];\n}];\n```\n\n- previousUnit: Object - switching from unit (same as `_from` param)\n- newUnit: Object - switching to unit (same as `_to` param)"},{"heading":"UAVCrewCreated (Arma 3 v2.14)","level":5,"markdown":"Fires when UAV or UGV is assembled from Backpack after the AI crew is created\n\n```sqf\naddMissionEventHandler [\"UAVCrewCreated\", {\n    params [\"_uav\", \"_driver\", \"_gunner\"];\n}];\n```\n\n- uav: Object - the assembled weapon\n- driver: Object - AI driver\n- gunner: Object - AI gunner"}],"categories":["Event Handlers","Introduced with Arma 3 version 0.50"],"groups":["Event Handlers"]},{"name":"Arma 3: Remote Execution","title":"Arma 3: Remote Execution","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Remote_Execution","revid":352065,"updated":"2024-02-01T23:24:38Z","aliases":["Arma 3 Remote Execution","Remote Execution"],"markdown":"Remote Execution is one of the cornerstones of Multiplayer Scripting in Arma 3. It is primarily needed to properly use commands that have *local effect* (Local Effect) or only take *local arguments* (Local Argument) in multiplayer.\n\n### Remote Execution Framework\n\nThe Remote Execution Framework currently consists of five commands:\n- remoteExec\n- remoteExecCall\n- remoteExecutedOwner\n- isRemoteExecuted\n- isRemoteExecutedJIP\nFurthermore, the framework encompasses an optional config entry to manage security settings: CfgRemoteExec.\n\n> [!NOTE]\n> While primarily designed and used for multiplayer, remoteExec and remoteExecCall also work in singleplayer; the behaviour is the same as in multiplayer.\n\n### Use Case Example\n\nTo understand why remote execution is needed and what it is used for, consider the following use case example: Let's say we want to use hint to display an announcement to all the players in our multiplayer mission at the same time.\n\nWe already know how to use the hint command:\n\n```sqf\nhint \"You have 5 minutes left!\"; // Normal use of hint.\n```\n\nThe problem is that hint only has *local effect*. This means that only the machine where hint is executed will display our \"You have 5 minutes left!\" message.\nBut we do not want to display our message to just a single player, we want to display our message to every player.\n\nSo in order to solve this problem, we need to make use of remote execution:\n\n```sqf\n\"You have 5 minutes left!\" remoteExec [\"hint\"];        // remote execution of hint.\n\"You have 5 minutes left!\" remoteExec [\"hint\", 0];    // identical to the line above\n```\n\nNow all machines that are taking part in our multiplayer session will execute `hint \"You have 5 minutes left!\";`, which means that our message will be displayed to every player at the same time - and we have achieved our goal.\n\n> [!NOTE]\n> If it is available, information about the multiplayer behaviour of a function / command can be found at the top of the documentation page of that function / command. Look for these icons: Local Argument, Global Argument, Local Effect, Global Effect and Server Execution. Hover above the icons to view a tooltip explaining what each icon means.\n\n### Environment\n\n|  |  |  |  |\n|---|---|---|---|\n| + Execution in Scheduled Environment |  | Commands | Functions |\n| remoteExec | ✗ | ✓ |  |\n| remoteExecCall | ✗ | ✗ |  |\n\n### History\n\nPrior to Arma 3 v1.50 there was no engine based remote execution. The only officially supported way to execute code on a non-local machine was provided in the form of BIS_fnc_MP. This scripted framework suffered from several issues, mainly poor network traffic optimization and insufficient security control. The network traffic was optimized in Arma 3 v1.46, but the security issues of the scripted framework could not be fixed properly.\n\nTo fully address these issues, remote execution was implemented directly into the game engine, with Arma 3 v1.50 introducing two new script commands - remoteExec and remoteExecCall - as well as a new CfgRemoteExec, finally allowing for proper and secure remote execution from all machines.\n\nAs of Arma 3 v1.54, BIS_fnc_MP has been rewritten to internally use remoteExec and remoteExecCall, retaining full backwards compatibility and enabling it to work with the updated CfgRemoteExec. **Despite this, BIS_fnc_MP is now deprecated and should no longer be used!**\n\n### Advanced Techniques & Functionality Insight\n\n#### JIP Queue\n\nWhen a command or function is executed through remoteExec or remoteExecCall, it can be flagged as persistent. If it is flagged, the statement is stored in the JIP queue on the server (under its unique JIP ID). When a player joins a multiplayer session that has already started (JIP stands for *Join-In-Progress*), all entries stored in the JIP queue are executed on that player's machine.\n\n##### Overwriting JIP message in the queue\n\nEvery JIP message is stored in the queue. If you need to overwrite the JIP message with another message, use the same JIP id for the new message. This way the new message will be stored in the queue under the provided id and will overwrite the previously stored message that used the same id.\n\n##### Deleting JIP message from the queue\n\nTo remove a specific JIP message from the queue call the remoteExec with function/command name set to an empty string, the JIP id of the message you want to remove and no other params.\n\n```sqf\nremoteExec [\"\", \"JIPid\"];\n```\n\n#### Validity Verification\n\nThe validity of a remote execution request is verified in two steps:\n1. When the request is initiated (issued from a client machine)\n1. Before the server broadcasts the request\n\nIf the request is initialized directly from the server, step 1 is skipped (this also applies to hosted servers).\n\nA remote execution request has to meet the following criteria to be considered valid:\n1. The input parameters must be defined properly\n1. The function / command must exist on the machine\n1. The function / command must be allowed by CfgRemoteExec: Remote execution must either be fully allowed (`mode = 2`) or the particular function / command must be whitelisted.\n1. If JIP is used, JIP must be allowed by CfgRemoteExec (`jip = 1`)\n\nIf any of these conditions is not met, the remote execution request is blocked.\n\n### See Also\n\n- Multiplayer Scripting\n- Multiplayer Scripting Commands\n\nArma 3 Remote Execution","sections":[{"heading":null,"level":1,"markdown":"Remote Execution is one of the cornerstones of Multiplayer Scripting in Arma 3. It is primarily needed to properly use commands that have *local effect* (Local Effect) or only take *local arguments* (Local Argument) in multiplayer."},{"heading":"Remote Execution Framework","level":3,"markdown":"The Remote Execution Framework currently consists of five commands:\n- remoteExec\n- remoteExecCall\n- remoteExecutedOwner\n- isRemoteExecuted\n- isRemoteExecutedJIP\nFurthermore, the framework encompasses an optional config entry to manage security settings: CfgRemoteExec.\n\n> [!NOTE]\n> While primarily designed and used for multiplayer, remoteExec and remoteExecCall also work in singleplayer; the behaviour is the same as in multiplayer."},{"heading":"Use Case Example","level":3,"markdown":"To understand why remote execution is needed and what it is used for, consider the following use case example: Let's say we want to use hint to display an announcement to all the players in our multiplayer mission at the same time.\n\nWe already know how to use the hint command:\n\n```sqf\nhint \"You have 5 minutes left!\"; // Normal use of hint.\n```\n\nThe problem is that hint only has *local effect*. This means that only the machine where hint is executed will display our \"You have 5 minutes left!\" message.\nBut we do not want to display our message to just a single player, we want to display our message to every player.\n\nSo in order to solve this problem, we need to make use of remote execution:\n\n```sqf\n\"You have 5 minutes left!\" remoteExec [\"hint\"];        // remote execution of hint.\n\"You have 5 minutes left!\" remoteExec [\"hint\", 0];    // identical to the line above\n```\n\nNow all machines that are taking part in our multiplayer session will execute `hint \"You have 5 minutes left!\";`, which means that our message will be displayed to every player at the same time - and we have achieved our goal.\n\n> [!NOTE]\n> If it is available, information about the multiplayer behaviour of a function / command can be found at the top of the documentation page of that function / command. Look for these icons: Local Argument, Global Argument, Local Effect, Global Effect and Server Execution. Hover above the icons to view a tooltip explaining what each icon means."},{"heading":"Environment","level":3,"markdown":"|  |  |  |  |\n|---|---|---|---|\n| + Execution in Scheduled Environment |  | Commands | Functions |\n| remoteExec | ✗ | ✓ |  |\n| remoteExecCall | ✗ | ✗ |  |"},{"heading":"History","level":3,"markdown":"Prior to Arma 3 v1.50 there was no engine based remote execution. The only officially supported way to execute code on a non-local machine was provided in the form of BIS_fnc_MP. This scripted framework suffered from several issues, mainly poor network traffic optimization and insufficient security control. The network traffic was optimized in Arma 3 v1.46, but the security issues of the scripted framework could not be fixed properly.\n\nTo fully address these issues, remote execution was implemented directly into the game engine, with Arma 3 v1.50 introducing two new script commands - remoteExec and remoteExecCall - as well as a new CfgRemoteExec, finally allowing for proper and secure remote execution from all machines.\n\nAs of Arma 3 v1.54, BIS_fnc_MP has been rewritten to internally use remoteExec and remoteExecCall, retaining full backwards compatibility and enabling it to work with the updated CfgRemoteExec. **Despite this, BIS_fnc_MP is now deprecated and should no longer be used!**"},{"heading":"Advanced Techniques & Functionality Insight","level":3,"markdown":""},{"heading":"JIP Queue","level":4,"markdown":"When a command or function is executed through remoteExec or remoteExecCall, it can be flagged as persistent. If it is flagged, the statement is stored in the JIP queue on the server (under its unique JIP ID). When a player joins a multiplayer session that has already started (JIP stands for *Join-In-Progress*), all entries stored in the JIP queue are executed on that player's machine."},{"heading":"Overwriting JIP message in the queue","level":5,"markdown":"Every JIP message is stored in the queue. If you need to overwrite the JIP message with another message, use the same JIP id for the new message. This way the new message will be stored in the queue under the provided id and will overwrite the previously stored message that used the same id."},{"heading":"Deleting JIP message from the queue","level":5,"markdown":"To remove a specific JIP message from the queue call the remoteExec with function/command name set to an empty string, the JIP id of the message you want to remove and no other params.\n\n```sqf\nremoteExec [\"\", \"JIPid\"];\n```"},{"heading":"Validity Verification","level":4,"markdown":"The validity of a remote execution request is verified in two steps:\n1. When the request is initiated (issued from a client machine)\n1. Before the server broadcasts the request\n\nIf the request is initialized directly from the server, step 1 is skipped (this also applies to hosted servers).\n\nA remote execution request has to meet the following criteria to be considered valid:\n1. The input parameters must be defined properly\n1. The function / command must exist on the machine\n1. The function / command must be allowed by CfgRemoteExec: Remote execution must either be fully allowed (`mode = 2`) or the particular function / command must be whitelisted.\n1. If JIP is used, JIP must be allowed by CfgRemoteExec (`jip = 1`)\n\nIf any of these conditions is not met, the remote execution request is blocked."},{"heading":"See Also","level":3,"markdown":"- Multiplayer Scripting\n- Multiplayer Scripting Commands\n\nArma 3 Remote Execution"}],"categories":["Arma 3: Remote Execution","Introduced with Arma 3 version 1.50"],"groups":["Scripting"]},{"name":"Arma 3: Scripted Event Handlers","title":"Arma 3: Scripted Event Handlers","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Scripted_Event_Handlers","revid":378628,"updated":"2026-05-15T10:43:40Z","aliases":["Arma 3: Event Handlers/ScriptedEventHandlers"],"markdown":"Scripted Event Handlers are triggered by some of BI's modules and functions. When triggered any code registered for one of these events via BIS_fnc_addScriptedEventHandler will be executed.\nAll the events exists as variables within a namespace, whether this is one of the main Namespaces like missionNamespace or uiNamespace or it could be a specific namespace like a Group or Object etc.\nThe event also has a set of parameters passed to the executed code.\nYou can even implement your own scripted eventHandlers by using BIS_fnc_callScriptedEventHandler.\nFor all other available Event Handlers, see Arma 3: Event Handlers.\n\n### Functions\n\n- BIS_fnc_addScriptedEventHandler\n- BIS_fnc_removeScriptedEventHandler\n- BIS_fnc_removeAllScriptedEventHandlers\n- BIS_fnc_callScriptedEventHandler\n\n### Examples\n\n#### Subscribe\n\n```sqf\n[missionNamespace, \"localPlayerNearFourArmedRobot\", {\n    hint \"Hello there\";\n}] call BIS_fnc_addScriptedEventHandler;\n```\n\n```sqf\n[missionNamespace, \"arsenalOpened\", {\n    hint \"Player opened the Arsenal\"; // hint message to the player when he opens the Arsenal\n}] call BIS_fnc_addScriptedEventHandler;\n```\n\n#### Trigger\n\n```sqf\nwaitUntil { sleep 1; player distance _GG < 10 };\n[missionNamespace, \"localPlayerNearFourArmedRobot\", [player, _GG]] call BIS_fnc_callScriptedEventHandler;\n```\n\n### Events\n\nThis is a list of all available scripted events that exist through BI's functions and modules.\nEach event is listed under the system that calls them whether this be a specific function or a module. List last updated for Arma 3 v2.10\n\n| Event namespace | Event name | Event passed parameters |\n|---|---|---|\n| #### EG Spectator Display |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnCursorObjectFocused\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnCursorObjectUnfocused\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnFocusChanged\" | ```sqf<br>params [\"_newFocus\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnUiVisibilityChanged\" | ```sqf<br>params [\"_isVisible\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_MapStateChanged\" | ```sqf<br>params [\"_isMapVisible\"];<br>``` |\n| #### Player opens pause menu |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnGameInterrupt\" | ```sqf<br>params [\"_display\"];<br>``` |\n| #### Player exits Game Options menu |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnGameOptionsExited\" Arma 3 v2.02 | ```sqf<br>params [\"_okButtonPressed\"];<br>``` |\n| #### Probing Beam (enoch) |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"probingStarted\" | ```sqf<br>params [\"_cursorTarget\", \"_data\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"probingEnded\" | ```sqf<br>params [\"_data\", \"_isEnded\"];<br>``` |\n| #### Respawn Display |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayRespawnKeyDown\" | ```sqf<br>params [\"_display\", \"_keyCode\", \"_shift\", \"_ctrl\", \"_alt\"];<br>``` |\n| #### Saving of the game, scripted or manual |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnSaveGame\" | N/A |\n| #### teamSwitchedScript.sqs |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"teamSwitched\" | ```sqf<br>params [\"_originalUnit\", \"_switchToUnit\"];<br>``` |\n| #### BIS_fnc_addScriptedEventHandler |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerAdded\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_animateFlag |  |  |\n| ```sqf<br>_flag<br>``` | \"FlagAnimationDone\" | ```sqf<br>params [\"_flag\", \"_phaseEnd\"];<br>``` |\n| #### BIS_fnc_arsenal |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalPreOpen\" Arma 3 v2.08 Fires just before Arsenal display is created | ```sqf<br>params [\"_missionDisplay\", \"_center\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalOpened\" | ```sqf<br>params [\"_display\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalClosed\" | ```sqf<br>params [\"_displayNull\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| #### BIS_fnc_bleedTickets |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"dominantSideChanged\" | ```sqf<br>params [\"_dominantSide\", \"_dominantSideOld\", \"_sides\"];<br>``` |\n| #### BIS_fnc_EGSpectatorCamera |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"EGSpectator_OnCameraModeChanged\" | ```sqf<br>params [\"_newMode\"];<br>``` |\n| #### BIS_fnc_garage |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"garageOpened\" | ```sqf<br>params [\"_display\", \"_toggleSpace\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"garageClosed\" | ```sqf<br>params [\"_displayNull\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| #### BIS_fnc_initDisplay (Arma 3 v2.04) |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnDisplayRegistered\" | ```sqf<br>params [\"_display\", \"_class\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"OnDisplayUnregistered\" | ```sqf<br>params [\"_display\", \"_class\"];<br>``` |\n| #### BIS_fnc_initInspectable |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"objectInspected\" | ```sqf<br>params [\"_object\", \"_texture\", \"_text\", \"_sound\", \"_textureRatio\"];<br>```<br>any data, shown as used by the Leaflets system |\n| #### BIS_fnc_initIntelObject |  |  |\n| _object | \"intelObjectFound\" | ```sqf<br>params [\"_object\", \"_foundBy\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"intelObjectFound\" | ```sqf<br>params [\"_curator\", \"_foundBy\", \"_object\"];<br>``` |\n| #### BIS_fnc_kbTellLocal |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_kbTellLocal_played\" | ```sqf<br>params [\"_from\", \"_to\", \"_sentence\", \"_channel\"];<br>``` |\n| #### BIS_fnc_packStaticWeapon |  |  |\n| ```sqf<br>_group<br>``` | \"StaticWeaponPacked\" | ```sqf<br>params [\"_group\", \"_leader\", \"_gunner\", \"_assistant\", \"_weaponBag\", \"_baseBag\"];<br>``` |\n| #### BIS_fnc_playVideo |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_playVideo_started\" | ```sqf<br>params [\"_video\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_playVideo_stopped\" | ```sqf<br>params [\"_video\"];<br>``` |\n| #### BIS_fnc_priorityQueue* system |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_onQueue%1Pop\" where %1 is ID returned from BIS_fnc_priorityQueue_Init | ```sqf<br>params [\"_handle\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_onQueue%1Push\" where %1 is ID returned from BIS_fnc_priorityQueue_Init | ```sqf<br>params [\"_handle\"];<br>``` |\n| #### BIS_fnc_removeAllScriptedEventHandlers |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerRemoved\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_removeScriptedEventHandler |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerRemoved\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_respawnTickets |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"respawnTicketsExhausted\" | ```sqf<br>params [\"_target\"];<br>``` |\n| #### BIS_fnc_unpackStaticWeapon |  |  |\n| ```sqf<br>_group<br>``` | \"StaticWeaponUnpacked\" | ```sqf<br>params [\"_group\", \"_leader\", \"_gunner\", \"_assistant\", \"_weapon\"];<br>``` |\n| #### Structures |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"StructureDamaged\" Arma 3 v2.22 | ```sqf<br>params [\"_structure\", \"_shot\", \"_position\", \"_velocity\", \"_ammo\", \"_explosive\", \"_indirectHit\", \"_invArmor\", \"_explPow\", \"_damage\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"StructureDestroyed\" Arma 3 v2.22 | ```sqf<br>params [\"_structure\", \"_killer\", \"_instigator\", \"_useEffects\", \"_shot\", \"_real\"];<br>``` |\n| #### Module Curator RemoteControl |  |  |\n| ```sqf<br>_curator<br>``` | \"curatorObjectRemoteControlled\" | ```sqf<br>params [\"_curator\", \"_player\", \"_unit\", \"_isRemoteControlled\"];<br>```<br>- _isRemoteControlled is true when entering remote control, false when exiting |\n| #### Module End Game |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnStageChanged\" | ```sqf<br>params [\"_stage\", \"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnStartGameObjectiveCompleted\" | ```sqf<br>params [\"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveStateChanged\" | ```sqf<br>params [\"_objective\", \"_side\", \"_newState\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveCompleted\" | ```sqf<br>params [\"_objective\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveEnded\" | ```sqf<br>params [\"_objective\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnDownloadCompleted\" | ```sqf<br>params [\"_side\", \"_isUpload\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_Ended\" | ```sqf<br>params [\"_winnerSide\", \"_loserSide\", \"_isDraw\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"onUploadStateChanged\" | ```sqf<br>params [\"_side\"]; // can be nil<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"onPickupInfoChanged\" | ```sqf<br>params [\"_BIS_hvt_pickupInfo\"];<br>``` |\n| #### Module Game Master (Zeus) |  |  |\n| ```sqf<br>_curator<br>``` | \"curatorGroupPlaced\" | ```sqf<br>params [\"_group\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"curatorObjectPlaced\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"curatorUnitAssigned\" | ```sqf<br>params [\"_curator\", \"_player\"];<br>``` |\n| #### Module Rich Curve Key |  |  |\n| _curKey | \"reached\" | ```sqf<br>params [\"_curKey\"];<br>``` |\n| #### Module Sector |  |  |\n| ```sqf<br>_sector<br>``` | \"ownerChanged\" | ```sqf<br>params [\"_sector\", \"_owner\", \"_ownerOld\"];<br>``` |\n| #### Module Spawn AI: Sector Tactic |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_groupSpawned\" | ```sqf<br>params [\"_bis_groundSupport_groupSpawned\", \"_group\", \"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_wiped\" | ```sqf<br>params [\"_bis_groundSupport_wiped\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_inEnemySector\" | ```sqf<br>params [\"_bis_groundSupport_inEnemySector\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_destinationReached\" | ```sqf<br>params [\"_bis_groundSupport_destinationReached\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_groupTypeChanged\" | ```sqf<br>params [\"_bis_groundSupport_groupTypeChanged\", \"_group\", \"_type\", \"_currentType\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_decimated\" | ```sqf<br>params [\"_bis_groundSupport_decimated\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_farFromDestination\" | ```sqf<br>params [\"_bis_groundSupport_farFromDestination\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needTransport\" | ```sqf<br>params [\"_bis_groundSupport_needTransport\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_joined\" | ```sqf<br>params [\"_bis_groundSupport_joined\", \"_group\", \"_transportGroup\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_closeToDestination\" | ```sqf<br>params [\"_bis_groundSupport_closeToDestination\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needEvac\" | ```sqf<br>params [\"_bis_groundSupport_needEvac\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needAmmo\" | ```sqf<br>params [\"_bis_groundSupport_needAmmo\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needSupport\" | ```sqf<br>params [\"_bis_groundSupport_needSupport\", \"_group\", \"_reportedVehicle\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_boarded\" | ```sqf<br>params [\"_bis_groundSupport_boarded\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportStarted\" | ```sqf<br>params [\"_bis_groundSupport_transportStarted\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportEnded\" | ```sqf<br>params [\"_bis_groundSupport_transportEnded\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportAborted\" | ```sqf<br>params [\"_bis_groundSupport_transportAborted\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_disembarked\" | ```sqf<br>params [\"_bis_groundSupport_disembarked\", \"_group\", \"_transport\"];<br>``` |\n| #### Module Timeline |  |  |\n| ```sqf<br>_timeline<br>``` | \"finished\" | ```sqf<br>params [\"_timeline\"];<br>``` |\n| ```sqf<br>_timeline<br>``` | \"played\" | N/A |\n| ```sqf<br>_timeline<br>``` | \"looped\" | ```sqf<br>params [\"_timeline\"];<br>``` |\n| #### Module Trident |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_moduleTrident_updated\" | ```sqf<br>params [\"_sideA\", \"_sideB\", \"_areFriendly\"];<br>``` |\n| #### Module Vehicle Respawn |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"respawn\" | ```sqf<br>params [\"_newVeh\", \"_veh\"];<br>``` |\n| #### Spectrum Analyzer Device |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"SpectrumAnalyzerOpened\" | ```sqf<br>params [\"_display\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"SpectrumAnalyzerClosed\" | ```sqf<br>params [\"_display\"];<br>``` |\n\n### Arma 3 Contact Events\n\n> [!NOTE]\n> This content is exclusive to the Arma 3 Contact Expansion.\n\n- \"antennaAdded\"\n- \"antennaDeleted\"\n- \"arsenalPreOpen\"\n- \"behaviourChanged\"\n- \"currentSignalChanged\"\n- \"dangerZoneEntered\"\n- \"dangerZoneExited\"\n- \"diaryRecordSet\"\n- \"dominantSideChanged\"\n- \"gravitPulseHit\"\n- \"gravitPulseRewarded\"\n- \"handleCombat\"\n- \"handleWarningShot\"\n- \"moveToModelSpaceCompleted\"\n- \"puzzleReset\"\n- \"puzzleStepCompleted\"\n- \"puzzleTerminated\"\n- \"refresh\"\n- \"respawnTicketsExhausted\"\n- \"rotationChanged\"\n- \"signalEnded\"\n- \"signalScanned\"\n- \"signalStartedPassive\"\n- \"siteSpawned\"\n- \"taskSet\"\n- \"translationChanged\"\n- \"transmittingEnded\"\n- \"transmittingStarted\"\n- \"wpPatrolEnded\"\n- \"wpPatrolStarted\"","sections":[{"heading":null,"level":1,"markdown":"Scripted Event Handlers are triggered by some of BI's modules and functions. When triggered any code registered for one of these events via BIS_fnc_addScriptedEventHandler will be executed.\nAll the events exists as variables within a namespace, whether this is one of the main Namespaces like missionNamespace or uiNamespace or it could be a specific namespace like a Group or Object etc.\nThe event also has a set of parameters passed to the executed code.\nYou can even implement your own scripted eventHandlers by using BIS_fnc_callScriptedEventHandler.\nFor all other available Event Handlers, see Arma 3: Event Handlers."},{"heading":"Functions","level":3,"markdown":"- BIS_fnc_addScriptedEventHandler\n- BIS_fnc_removeScriptedEventHandler\n- BIS_fnc_removeAllScriptedEventHandlers\n- BIS_fnc_callScriptedEventHandler"},{"heading":"Examples","level":3,"markdown":""},{"heading":"Subscribe","level":4,"markdown":"```sqf\n[missionNamespace, \"localPlayerNearFourArmedRobot\", {\n    hint \"Hello there\";\n}] call BIS_fnc_addScriptedEventHandler;\n```\n\n```sqf\n[missionNamespace, \"arsenalOpened\", {\n    hint \"Player opened the Arsenal\"; // hint message to the player when he opens the Arsenal\n}] call BIS_fnc_addScriptedEventHandler;\n```"},{"heading":"Trigger","level":4,"markdown":"```sqf\nwaitUntil { sleep 1; player distance _GG < 10 };\n[missionNamespace, \"localPlayerNearFourArmedRobot\", [player, _GG]] call BIS_fnc_callScriptedEventHandler;\n```"},{"heading":"Events","level":3,"markdown":"This is a list of all available scripted events that exist through BI's functions and modules.\nEach event is listed under the system that calls them whether this be a specific function or a module. List last updated for Arma 3 v2.10\n\n| Event namespace | Event name | Event passed parameters |\n|---|---|---|\n| #### EG Spectator Display |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnCursorObjectFocused\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnCursorObjectUnfocused\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnFocusChanged\" | ```sqf<br>params [\"_newFocus\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_OnUiVisibilityChanged\" | ```sqf<br>params [\"_isVisible\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayEGSpectator_MapStateChanged\" | ```sqf<br>params [\"_isMapVisible\"];<br>``` |\n| #### Player opens pause menu |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnGameInterrupt\" | ```sqf<br>params [\"_display\"];<br>``` |\n| #### Player exits Game Options menu |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnGameOptionsExited\" Arma 3 v2.02 | ```sqf<br>params [\"_okButtonPressed\"];<br>``` |\n| #### Probing Beam (enoch) |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"probingStarted\" | ```sqf<br>params [\"_cursorTarget\", \"_data\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"probingEnded\" | ```sqf<br>params [\"_data\", \"_isEnded\"];<br>``` |\n| #### Respawn Display |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"RscDisplayRespawnKeyDown\" | ```sqf<br>params [\"_display\", \"_keyCode\", \"_shift\", \"_ctrl\", \"_alt\"];<br>``` |\n| #### Saving of the game, scripted or manual |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnSaveGame\" | N/A |\n| #### teamSwitchedScript.sqs |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"teamSwitched\" | ```sqf<br>params [\"_originalUnit\", \"_switchToUnit\"];<br>``` |\n| #### BIS_fnc_addScriptedEventHandler |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerAdded\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_animateFlag |  |  |\n| ```sqf<br>_flag<br>``` | \"FlagAnimationDone\" | ```sqf<br>params [\"_flag\", \"_phaseEnd\"];<br>``` |\n| #### BIS_fnc_arsenal |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalPreOpen\" Arma 3 v2.08 Fires just before Arsenal display is created | ```sqf<br>params [\"_missionDisplay\", \"_center\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalOpened\" | ```sqf<br>params [\"_display\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| ```sqf<br>missionNamespace<br>``` | \"arsenalClosed\" | ```sqf<br>params [\"_displayNull\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| #### BIS_fnc_bleedTickets |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"dominantSideChanged\" | ```sqf<br>params [\"_dominantSide\", \"_dominantSideOld\", \"_sides\"];<br>``` |\n| #### BIS_fnc_EGSpectatorCamera |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"EGSpectator_OnCameraModeChanged\" | ```sqf<br>params [\"_newMode\"];<br>``` |\n| #### BIS_fnc_garage |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"garageOpened\" | ```sqf<br>params [\"_display\", \"_toggleSpace\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"garageClosed\" | ```sqf<br>params [\"_displayNull\", \"_toggleSpace\"];<br>```<br>- _toggleSpace: Boolean - `uiNamespace getVariable [\"bis_fnc_arsenal_toggleSpace\", false]];` |\n| #### BIS_fnc_initDisplay (Arma 3 v2.04) |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"OnDisplayRegistered\" | ```sqf<br>params [\"_display\", \"_class\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"OnDisplayUnregistered\" | ```sqf<br>params [\"_display\", \"_class\"];<br>``` |\n| #### BIS_fnc_initInspectable |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"objectInspected\" | ```sqf<br>params [\"_object\", \"_texture\", \"_text\", \"_sound\", \"_textureRatio\"];<br>```<br>any data, shown as used by the Leaflets system |\n| #### BIS_fnc_initIntelObject |  |  |\n| _object | \"intelObjectFound\" | ```sqf<br>params [\"_object\", \"_foundBy\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"intelObjectFound\" | ```sqf<br>params [\"_curator\", \"_foundBy\", \"_object\"];<br>``` |\n| #### BIS_fnc_kbTellLocal |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_kbTellLocal_played\" | ```sqf<br>params [\"_from\", \"_to\", \"_sentence\", \"_channel\"];<br>``` |\n| #### BIS_fnc_packStaticWeapon |  |  |\n| ```sqf<br>_group<br>``` | \"StaticWeaponPacked\" | ```sqf<br>params [\"_group\", \"_leader\", \"_gunner\", \"_assistant\", \"_weaponBag\", \"_baseBag\"];<br>``` |\n| #### BIS_fnc_playVideo |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_playVideo_started\" | ```sqf<br>params [\"_video\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_playVideo_stopped\" | ```sqf<br>params [\"_video\"];<br>``` |\n| #### BIS_fnc_priorityQueue* system |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_onQueue%1Pop\" where %1 is ID returned from BIS_fnc_priorityQueue_Init | ```sqf<br>params [\"_handle\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_onQueue%1Push\" where %1 is ID returned from BIS_fnc_priorityQueue_Init | ```sqf<br>params [\"_handle\"];<br>``` |\n| #### BIS_fnc_removeAllScriptedEventHandlers |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerRemoved\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_removeScriptedEventHandler |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"ScriptedEventHandlerRemoved\" | ```sqf<br>params [\"_namespace\", \"_name\", \"_handlerID\"];<br>``` |\n| #### BIS_fnc_respawnTickets |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"respawnTicketsExhausted\" | ```sqf<br>params [\"_target\"];<br>``` |\n| #### BIS_fnc_unpackStaticWeapon |  |  |\n| ```sqf<br>_group<br>``` | \"StaticWeaponUnpacked\" | ```sqf<br>params [\"_group\", \"_leader\", \"_gunner\", \"_assistant\", \"_weapon\"];<br>``` |\n| #### Structures |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"StructureDamaged\" Arma 3 v2.22 | ```sqf<br>params [\"_structure\", \"_shot\", \"_position\", \"_velocity\", \"_ammo\", \"_explosive\", \"_indirectHit\", \"_invArmor\", \"_explPow\", \"_damage\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"StructureDestroyed\" Arma 3 v2.22 | ```sqf<br>params [\"_structure\", \"_killer\", \"_instigator\", \"_useEffects\", \"_shot\", \"_real\"];<br>``` |\n| #### Module Curator RemoteControl |  |  |\n| ```sqf<br>_curator<br>``` | \"curatorObjectRemoteControlled\" | ```sqf<br>params [\"_curator\", \"_player\", \"_unit\", \"_isRemoteControlled\"];<br>```<br>- _isRemoteControlled is true when entering remote control, false when exiting |\n| #### Module End Game |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnStageChanged\" | ```sqf<br>params [\"_stage\", \"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnStartGameObjectiveCompleted\" | ```sqf<br>params [\"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveStateChanged\" | ```sqf<br>params [\"_objective\", \"_side\", \"_newState\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveCompleted\" | ```sqf<br>params [\"_objective\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnObjectiveEnded\" | ```sqf<br>params [\"_objective\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_OnDownloadCompleted\" | ```sqf<br>params [\"_side\", \"_isUpload\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"EndGame_Ended\" | ```sqf<br>params [\"_winnerSide\", \"_loserSide\", \"_isDraw\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"onUploadStateChanged\" | ```sqf<br>params [\"_side\"]; // can be nil<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"onPickupInfoChanged\" | ```sqf<br>params [\"_BIS_hvt_pickupInfo\"];<br>``` |\n| #### Module Game Master (Zeus) |  |  |\n| ```sqf<br>_curator<br>``` | \"curatorGroupPlaced\" | ```sqf<br>params [\"_group\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"curatorObjectPlaced\" | ```sqf<br>params [\"_object\"];<br>``` |\n| ```sqf<br>_curator<br>``` | \"curatorUnitAssigned\" | ```sqf<br>params [\"_curator\", \"_player\"];<br>``` |\n| #### Module Rich Curve Key |  |  |\n| _curKey | \"reached\" | ```sqf<br>params [\"_curKey\"];<br>``` |\n| #### Module Sector |  |  |\n| ```sqf<br>_sector<br>``` | \"ownerChanged\" | ```sqf<br>params [\"_sector\", \"_owner\", \"_ownerOld\"];<br>``` |\n| #### Module Spawn AI: Sector Tactic |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_groupSpawned\" | ```sqf<br>params [\"_bis_groundSupport_groupSpawned\", \"_group\", \"_side\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_wiped\" | ```sqf<br>params [\"_bis_groundSupport_wiped\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_inEnemySector\" | ```sqf<br>params [\"_bis_groundSupport_inEnemySector\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_destinationReached\" | ```sqf<br>params [\"_bis_groundSupport_destinationReached\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_groupTypeChanged\" | ```sqf<br>params [\"_bis_groundSupport_groupTypeChanged\", \"_group\", \"_type\", \"_currentType\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_decimated\" | ```sqf<br>params [\"_bis_groundSupport_decimated\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_farFromDestination\" | ```sqf<br>params [\"_bis_groundSupport_farFromDestination\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needTransport\" | ```sqf<br>params [\"_bis_groundSupport_needTransport\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_joined\" | ```sqf<br>params [\"_bis_groundSupport_joined\", \"_group\", \"_transportGroup\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_closeToDestination\" | ```sqf<br>params [\"_bis_groundSupport_closeToDestination\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needEvac\" | ```sqf<br>params [\"_bis_groundSupport_needEvac\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needAmmo\" | ```sqf<br>params [\"_bis_groundSupport_needAmmo\", \"_group\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_needSupport\" | ```sqf<br>params [\"_bis_groundSupport_needSupport\", \"_group\", \"_reportedVehicle\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_boarded\" | ```sqf<br>params [\"_bis_groundSupport_boarded\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportStarted\" | ```sqf<br>params [\"_bis_groundSupport_transportStarted\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportEnded\" | ```sqf<br>params [\"_bis_groundSupport_transportEnded\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_transportAborted\" | ```sqf<br>params [\"_bis_groundSupport_transportAborted\", \"_group\", \"_transport\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"bis_groundSupport_disembarked\" | ```sqf<br>params [\"_bis_groundSupport_disembarked\", \"_group\", \"_transport\"];<br>``` |\n| #### Module Timeline |  |  |\n| ```sqf<br>_timeline<br>``` | \"finished\" | ```sqf<br>params [\"_timeline\"];<br>``` |\n| ```sqf<br>_timeline<br>``` | \"played\" | N/A |\n| ```sqf<br>_timeline<br>``` | \"looped\" | ```sqf<br>params [\"_timeline\"];<br>``` |\n| #### Module Trident |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"BIS_fnc_moduleTrident_updated\" | ```sqf<br>params [\"_sideA\", \"_sideB\", \"_areFriendly\"];<br>``` |\n| #### Module Vehicle Respawn |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"respawn\" | ```sqf<br>params [\"_newVeh\", \"_veh\"];<br>``` |\n| #### Spectrum Analyzer Device |  |  |\n| ```sqf<br>missionNamespace<br>``` | \"SpectrumAnalyzerOpened\" | ```sqf<br>params [\"_display\"];<br>``` |\n| ```sqf<br>missionNamespace<br>``` | \"SpectrumAnalyzerClosed\" | ```sqf<br>params [\"_display\"];<br>``` |"},{"heading":"Arma 3 Contact Events","level":3,"markdown":"> [!NOTE]\n> This content is exclusive to the Arma 3 Contact Expansion.\n\n- \"antennaAdded\"\n- \"antennaDeleted\"\n- \"arsenalPreOpen\"\n- \"behaviourChanged\"\n- \"currentSignalChanged\"\n- \"dangerZoneEntered\"\n- \"dangerZoneExited\"\n- \"diaryRecordSet\"\n- \"dominantSideChanged\"\n- \"gravitPulseHit\"\n- \"gravitPulseRewarded\"\n- \"handleCombat\"\n- \"handleWarningShot\"\n- \"moveToModelSpaceCompleted\"\n- \"puzzleReset\"\n- \"puzzleStepCompleted\"\n- \"puzzleTerminated\"\n- \"refresh\"\n- \"respawnTicketsExhausted\"\n- \"rotationChanged\"\n- \"signalEnded\"\n- \"signalScanned\"\n- \"signalStartedPassive\"\n- \"siteSpawned\"\n- \"taskSet\"\n- \"translationChanged\"\n- \"transmittingEnded\"\n- \"transmittingStarted\"\n- \"wpPatrolEnded\"\n- \"wpPatrolStarted\""}],"categories":["Event Handlers"],"groups":["Event Handlers"]},{"name":"Arma 3: Tree View Path","title":"Arma 3: Tree View Path","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Tree_View_Path","revid":338770,"updated":"2023-04-05T16:50:45Z","aliases":["Tree View Path"],"markdown":"Tree View path for referencing Tree View item is not the same as the path used for adding items to the Tree View.\nThis may cause quite a bit of confusion as to the usage of the Tree View commands.\nIn short, when adding new items to the Tree View, one needs to give the path of the parent item to which the item is added and not the desired path for the new item.\nThe command will then return index of added item relative to the parent item. If parent item doesn't exist (happens when item is added to the main trunk of the tree), the parent path needs to be an empty array `[]`.\n\nThis is only relevant to the tvAdd command. All other Tree View commands reference the actual item path. So here are 2 examples for tvAdd and tvDelete:\n\n```sqf\n_index1   = _ctrl tvAdd [[], \"Item1\"];        // adds \"Item1\" to main branch. Item path [_index1] or [0]  \n_index1_1 = _ctrl tvAdd [[0], \"Item1_1\"];    // adds \"Item1_1\" to \"Item1\". Item path [0,_index1_1] or [0,0]\n_index1_2 = _ctrl tvAdd [[0], \"Item1_2\"];    // adds \"Item1_2\" to \"Item1\". Item path [0,_index1_2] or [0,1]\n_index2_1 = _ctrl tvAdd [[0,0], \"Item2_1\"];    // adds \"Item2_1\" to \"Item1_1\". Item path [0,0,_index2_1] or [0,1,0]\n```\n\nAs you can see, the parent item path is referenced in each tvAdd command. Let's look at tvDelete. The item path will be the actual path to the item.\n\n```sqf\n_ctrl tvDelete [0,0]; // deletes \"Item1_1\"\n_ctrl tvDelete [0,1]; // doesn't delete \"Item1_2\"\n```\n\nThe reason \"Item1_2\" is not deleted is because its path changed from [0,1] to [0,0] after we deleted \"Item1_1\".\n\n```sqf\n_ctrl tvDelete [0,0]; // deletes \"Item1_2\"\n```\n\nNow \"Item1_2\" is also deleted because the path for it is now correct.\n\nCode used to generate the Tree View thumbnail:\n\n```sqf\n_disp = findDisplay 46 createDisplay \"RscDisplayEmpty\";\n_bg = _disp ctrlCreate [\"RscText\", -1];\n_bg ctrlSetPosition [safeZoneX, safeZoneY, safeZoneW, safeZoneH];\n_bg ctrlSetBackgroundColor [0.5, 0.5, 0.5, 1];\n_bg ctrlCommit 0;\n_ctrl = _disp ctrlCreate [\"RscTree\", -1];\n_ctrl ctrlSetPosition [0, 0, 1, 1];\n_ctrl ctrlCommit 0;\n_ctrl ctrlSetFontHeight 0.03;\n_ctrl ctrlSetFont \"PuristaMedium\";\nfor \"_i\" from 0 to 1 do \n{\n    _color = [1, 1, 1, 1];\n    _ctrl tvAdd [[], format [\"Parent Path: %1 | Item Path: %2\", [], [_i]]];\n    _ctrl tvSetColor [[_i], _color];\n    for \"_j\" from 0 to 1 do \n    {\n        _color = [1, 0, 0, 1];\n        _ctrl tvAdd [[_i], format [\"Parent Path: %1 | Item Path: %2\", [_i], [_i, _j]]];\n        _ctrl tvSetColor [[_i, _j], _color];\n        for \"_k\" from 0 to 1 do \n        {\n            _color = [0, 1, 0, 1];\n            _ctrl tvAdd [[_i, _j], format [\"Parent Path: %1 | Item Path: %2\", [_i, _j], [_i, _j, _k]]];\n            _ctrl tvSetColor [[_i, _j, _k], _color];\n            for \"_n\" from 0 to 1 do \n            {\n                _color = [0, 0, 1, 1];\n                _ctrl tvAdd [[_i, _j, _k], format [\"Parent Path: %1 | Item Path: %2\", [_i, _j, _k], [_i, _j, _k, _n]]];\n                _ctrl tvSetColor [[_i, _j, _k, _n], _color];\n            };\n        };\n    };\n};\n\ntvExpandAll _ctrl;\n_ctrl ctrlAddEventHandler [\"TreeSelChanged\", { hint format [\"Item Path: %1\", _this select 1] }];\n```","sections":[{"heading":null,"level":1,"markdown":"Tree View path for referencing Tree View item is not the same as the path used for adding items to the Tree View.\nThis may cause quite a bit of confusion as to the usage of the Tree View commands.\nIn short, when adding new items to the Tree View, one needs to give the path of the parent item to which the item is added and not the desired path for the new item.\nThe command will then return index of added item relative to the parent item. If parent item doesn't exist (happens when item is added to the main trunk of the tree), the parent path needs to be an empty array `[]`.\n\nThis is only relevant to the tvAdd command. All other Tree View commands reference the actual item path. So here are 2 examples for tvAdd and tvDelete:\n\n```sqf\n_index1   = _ctrl tvAdd [[], \"Item1\"];        // adds \"Item1\" to main branch. Item path [_index1] or [0]  \n_index1_1 = _ctrl tvAdd [[0], \"Item1_1\"];    // adds \"Item1_1\" to \"Item1\". Item path [0,_index1_1] or [0,0]\n_index1_2 = _ctrl tvAdd [[0], \"Item1_2\"];    // adds \"Item1_2\" to \"Item1\". Item path [0,_index1_2] or [0,1]\n_index2_1 = _ctrl tvAdd [[0,0], \"Item2_1\"];    // adds \"Item2_1\" to \"Item1_1\". Item path [0,0,_index2_1] or [0,1,0]\n```\n\nAs you can see, the parent item path is referenced in each tvAdd command. Let's look at tvDelete. The item path will be the actual path to the item.\n\n```sqf\n_ctrl tvDelete [0,0]; // deletes \"Item1_1\"\n_ctrl tvDelete [0,1]; // doesn't delete \"Item1_2\"\n```\n\nThe reason \"Item1_2\" is not deleted is because its path changed from [0,1] to [0,0] after we deleted \"Item1_1\".\n\n```sqf\n_ctrl tvDelete [0,0]; // deletes \"Item1_2\"\n```\n\nNow \"Item1_2\" is also deleted because the path for it is now correct.\n\nCode used to generate the Tree View thumbnail:\n\n```sqf\n_disp = findDisplay 46 createDisplay \"RscDisplayEmpty\";\n_bg = _disp ctrlCreate [\"RscText\", -1];\n_bg ctrlSetPosition [safeZoneX, safeZoneY, safeZoneW, safeZoneH];\n_bg ctrlSetBackgroundColor [0.5, 0.5, 0.5, 1];\n_bg ctrlCommit 0;\n_ctrl = _disp ctrlCreate [\"RscTree\", -1];\n_ctrl ctrlSetPosition [0, 0, 1, 1];\n_ctrl ctrlCommit 0;\n_ctrl ctrlSetFontHeight 0.03;\n_ctrl ctrlSetFont \"PuristaMedium\";\nfor \"_i\" from 0 to 1 do \n{\n    _color = [1, 1, 1, 1];\n    _ctrl tvAdd [[], format [\"Parent Path: %1 | Item Path: %2\", [], [_i]]];\n    _ctrl tvSetColor [[_i], _color];\n    for \"_j\" from 0 to 1 do \n    {\n        _color = [1, 0, 0, 1];\n        _ctrl tvAdd [[_i], format [\"Parent Path: %1 | Item Path: %2\", [_i], [_i, _j]]];\n        _ctrl tvSetColor [[_i, _j], _color];\n        for \"_k\" from 0 to 1 do \n        {\n            _color = [0, 1, 0, 1];\n            _ctrl tvAdd [[_i, _j], format [\"Parent Path: %1 | Item Path: %2\", [_i, _j], [_i, _j, _k]]];\n            _ctrl tvSetColor [[_i, _j, _k], _color];\n            for \"_n\" from 0 to 1 do \n            {\n                _color = [0, 0, 1, 1];\n                _ctrl tvAdd [[_i, _j, _k], format [\"Parent Path: %1 | Item Path: %2\", [_i, _j, _k], [_i, _j, _k, _n]]];\n                _ctrl tvSetColor [[_i, _j, _k, _n], _color];\n            };\n        };\n    };\n};\n\ntvExpandAll _ctrl;\n_ctrl ctrlAddEventHandler [\"TreeSelChanged\", { hint format [\"Item Path: %1\", _this select 1] }];\n```"}],"categories":["Arrays","Introduced with Arma 3 version 0.74"],"groups":["Scripting"]},{"name":"Arma 3: Writing a Function","title":"Arma 3: Writing a Function","type":"topic","url":"https://community.bistudio.com/wiki/Arma_3:_Writing_a_Function","revid":341512,"updated":"2023-06-07T07:16:14Z","aliases":[],"markdown":"The most important thing to remember when writing a function is that other people are going to use it.\nMost of them won't understand how it works, expecting it to do its job without problems.\n\nThe function must be **robust**. It should not allow passing arguments of incorrect Data Types in.\nWhen some values are incorrect, it should throw an error explaining what went wrong and how to fix it.\nAnd above all, its header must provide complete explanation of usage.\n\n> [!IMPORTANT]\n>\n\n### Header\n\n| Template | Example |\n|---|---|\n| `/* Author: <author nickname> Description: <function description> Parameter(s): 0: can be one of: <type> - <description> <type> - <description> 1: <type> - (Optional, default <default value>) <description> Returns: <return type> Examples: <example> */` | `/* Author: Karel Moricky Description: Ends mission with specific ending. Parameter(s): 0: can be one of: STRING - (Optional, default \"end1\") end name ARRAY in format [endName, ID] - will be assembled as \"endName_ID\" string 1: BOOLEAN - (Optional, default true) true to end mission, false to fail mission 2: (Optional, default true) can be one of: BOOLEAN - true for signature closing shot (default: true) NUMBER - duration of a simple fade out to black Returns: BOOLEAN Example: [] call BIS_fnc_endMission */` |\n\n### Taking Arguments\n\nArguments are the only way to interact with a function. Let's now see how to make sure they are loaded properly.\n\nHere is this very simple function which will let a unit watch a position:\n\n```sqf\nparams [\"_unit\", \"_target\"];\n_unit doWatch _target;\n```\n\nExpected way how to call the function is by correctly defining all arguments:\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[player, getPosASL myCar] call TAG_fnc_myFunction;<br>``` |\n\nHowever, the function will break down when tried with only one argument:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player] call TAG_fnc_myFunction;<br>``` |\n\nFurthermore, using wrong data type will also lead to a problem:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player, 0] call TAG_fnc_myFunction;<br>``` |\n\nVariable *_target* expects position array in format [x,y,z]. Scripting error will appear when a different number of elements is used:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player, [1, 2, 3, 4]] call TAG_fnc_myFunction;<br>``` |\n\nAs shown there, the most common problems are:\n1. **Param of wrong data type is sent**\n1. **Param is missing**\n1. **Param is an array expecting specific number of elements, but different number is sent**\n\nRather than check for all these exceptions manually, it is more than advised to use the param command:\n _unit = param [0, objNull, [objNull]];\nFor multiple parameters, use the params command instead.\n params [\n \t[\"_unit\", objNull, [objNull]],\n \t[\"_target\", [0, 0, 0], [[], objNull], [2, 3]]\n ];\n _unit doWatch _target;\n- In a params array first argument is the name of the **private variable**. In param it is the **index** number.\n- Second argument is the **default value**. It will be used when the argument is missing, is nil or when wrong data type is used.\n- Next is optional **array of compatible data types**. They are defined by an example of the type, e.g. objNull will mean an object is allowed. When wrong data type is sent into the function, param will log an error message explaining what went wrong and use the default value.\n- The last, also optional argument is an **array of required array sizes**. [2,3] means only array with 2 or 3 elements are allowed. When incorrectly large array is sent into the function, param will log an error message explaining what went wrong and use the default value.\n\nLet's see what happens with wrong examples now:\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[player] call TAG_fnc_myFunction;<br>``` |\n\n*_target* is undefined. Default [0, 0, 0] is used instead. No error message is logged.\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[nil, getPosASL myCar] call TAG_fnc_myFunction;<br>``` |\n\n*_unit* is undefined (nil is passed instead). Default objNull is used instead. No error message is logged.\n\n|  |  |\n|---|---|\n|  | ```sqf<br>[player, 0] call TAG_fnc_myFunction;<br>``` |\n\n*_target* has wrong type. Default [0, 0, 0] is used instead. Error message is logged.\n\n|  |  |\n|---|---|\n|  | ```sqf<br>[player, [1, 2, 3, 4]] call TAG_fnc_myFunction;<br>``` |\n\n*_target* has wrong size. Default [0, 0, 0] is used instead. Error message is logged.\n\nAdditionally, when only one argument is used, it can be sent into the function directly without the need to have it in an array.\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>player call TAG_fnc_myFunction;<br>``` |\n\n### Returning Value\n\nA function can return a result (object reference, script handle, etc) that can then be saved by the user. If no value is returned, the variable would be nil and could lead to script errors.\n\n```sqf\n_myVar = [player, getPosASL myCar] call TAG_fnc_myFunction;\n```\n\nIt is a good practice to **always** return a value, even if it would be a simple true marking the function as completed. Let's use the example function from above:\n\n```sqf\nparams [\n    [\"_unit\", objNull, [objNull]],\n    [\"_target\", [0, 0, 0], [[], objNull], [2, 3]]\n];\n_unit doWatch _target;\ntrue;\n```\n\n> [!NOTE]\n> Note that a spawned function will always return a Script Handle, as per spawn command's behaviour.\n\n### Showing Errors\n\nWhile param and params can filter out the most common issues, the function will sometimes have special rules which will need to be handled.\nLet's return back to the example function, where we would want to terminate the function with error when *_unit* is dead:\n\n```sqf\nparams [[\"_unit\", objNull, [objNull]], [\"_target\", [0, 0, 0], [[], objNull], [2, 3]]];\nif (!alive _unit) exitWith { [\"Unit %1 must be alive.\", _unit] call BIS_fnc_error; false; };\n_unit doWatch _target;\ntrue;\n```\n\nNotice that we're returning false at the end of exitWith code.\n\n> [!IMPORTANT]\n> Error states must always return value of the same type as when everything is fine (Boolean in this case).\n\nBIS_fnc_error accepts String and Array of formatted ext. The error is logged into RPT and if the mission is previewd from the editor, it will also appear on screen.\n\n|  |  |\n|---|---|\n| RPT | \"User1/log: ERROR: [BIS_fnc_respawnTickets] #0: 0 is type SCALAR, must be NAMESPACE, SIDE, GROUP, OBJECT, BOOL. true used instead.\" |\n| In-game |  |\n\n### Logging\n\nApart from errors, it is possible to print any needed debug message. Use one of the following functions:\n- BIS_fnc_log - log a data of any type (e.g., String, Number, Object, ...)\n- BIS_fnc_logFormat - log formatted text\nProfile name and function name will automatically appear in the output text, to help identifying the source.\n\nUsage examples:\n\n| Expression | RPT Output |\n|---|---|\n| \"Hello World\" call BIS_fnc_log; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] Hello World\" |\n| 42 call BIS_fnc_log; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] 42\" |\n| [\"I'm playing %1\", missionName] call BIS_fnc_logFormat; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] I'm playing FalconWing\" |\n\nTo prevent RPT spam, logging is by default enabled only when previewing a mission from the editor. To force it in the mission everywhere, use the following Description.ext attribute:\n\n```cpp\nallowFunctionsLog = 1;\n```\n\n### Recompiling\n\nOnce compiled, functions remain unchanged and editing their file won't have any effect in the game.\nTo adjust functions on the fly, their recompilation can be manually triggered - see Arma 3: Functions Viewer and BIS_fnc_recompile.\n\n### Meta Variables\n\nSystem is adding header with basic meta data to all functions. Following local variables are declared there:\n- **_fnc_scriptName**: String - Function name (e.g., TAG_fnc_myFunction)\n- **_fnc_scriptNameParent**: String - Name of q function from which the current one was called (_fnc_scriptName used when not defined)\n\n> [!IMPORTANT]\n> Do not modify these values!\n\n### See Also\n\n- Arma 3: Functions Library\n- Arma 2: Functions Library\n- Take On Helicopters: Functions Library\n\nArma 3 Tutorials","sections":[{"heading":null,"level":1,"markdown":"The most important thing to remember when writing a function is that other people are going to use it.\nMost of them won't understand how it works, expecting it to do its job without problems.\n\nThe function must be **robust**. It should not allow passing arguments of incorrect Data Types in.\nWhen some values are incorrect, it should throw an error explaining what went wrong and how to fix it.\nAnd above all, its header must provide complete explanation of usage.\n\n> [!IMPORTANT]\n>"},{"heading":"Header","level":3,"markdown":"| Template | Example |\n|---|---|\n| `/* Author: <author nickname> Description: <function description> Parameter(s): 0: can be one of: <type> - <description> <type> - <description> 1: <type> - (Optional, default <default value>) <description> Returns: <return type> Examples: <example> */` | `/* Author: Karel Moricky Description: Ends mission with specific ending. Parameter(s): 0: can be one of: STRING - (Optional, default \"end1\") end name ARRAY in format [endName, ID] - will be assembled as \"endName_ID\" string 1: BOOLEAN - (Optional, default true) true to end mission, false to fail mission 2: (Optional, default true) can be one of: BOOLEAN - true for signature closing shot (default: true) NUMBER - duration of a simple fade out to black Returns: BOOLEAN Example: [] call BIS_fnc_endMission */` |"},{"heading":"Taking Arguments","level":3,"markdown":"Arguments are the only way to interact with a function. Let's now see how to make sure they are loaded properly.\n\nHere is this very simple function which will let a unit watch a position:\n\n```sqf\nparams [\"_unit\", \"_target\"];\n_unit doWatch _target;\n```\n\nExpected way how to call the function is by correctly defining all arguments:\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[player, getPosASL myCar] call TAG_fnc_myFunction;<br>``` |\n\nHowever, the function will break down when tried with only one argument:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player] call TAG_fnc_myFunction;<br>``` |\n\nFurthermore, using wrong data type will also lead to a problem:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player, 0] call TAG_fnc_myFunction;<br>``` |\n\nVariable *_target* expects position array in format [x,y,z]. Scripting error will appear when a different number of elements is used:\n\n|  |  |\n|---|---|\n| ✗ | ```sqf<br>[player, [1, 2, 3, 4]] call TAG_fnc_myFunction;<br>``` |\n\nAs shown there, the most common problems are:\n1. **Param of wrong data type is sent**\n1. **Param is missing**\n1. **Param is an array expecting specific number of elements, but different number is sent**\n\nRather than check for all these exceptions manually, it is more than advised to use the param command:\n _unit = param [0, objNull, [objNull]];\nFor multiple parameters, use the params command instead.\n params [\n \t[\"_unit\", objNull, [objNull]],\n \t[\"_target\", [0, 0, 0], [[], objNull], [2, 3]]\n ];\n _unit doWatch _target;\n- In a params array first argument is the name of the **private variable**. In param it is the **index** number.\n- Second argument is the **default value**. It will be used when the argument is missing, is nil or when wrong data type is used.\n- Next is optional **array of compatible data types**. They are defined by an example of the type, e.g. objNull will mean an object is allowed. When wrong data type is sent into the function, param will log an error message explaining what went wrong and use the default value.\n- The last, also optional argument is an **array of required array sizes**. [2,3] means only array with 2 or 3 elements are allowed. When incorrectly large array is sent into the function, param will log an error message explaining what went wrong and use the default value.\n\nLet's see what happens with wrong examples now:\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[player] call TAG_fnc_myFunction;<br>``` |\n\n*_target* is undefined. Default [0, 0, 0] is used instead. No error message is logged.\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>[nil, getPosASL myCar] call TAG_fnc_myFunction;<br>``` |\n\n*_unit* is undefined (nil is passed instead). Default objNull is used instead. No error message is logged.\n\n|  |  |\n|---|---|\n|  | ```sqf<br>[player, 0] call TAG_fnc_myFunction;<br>``` |\n\n*_target* has wrong type. Default [0, 0, 0] is used instead. Error message is logged.\n\n|  |  |\n|---|---|\n|  | ```sqf<br>[player, [1, 2, 3, 4]] call TAG_fnc_myFunction;<br>``` |\n\n*_target* has wrong size. Default [0, 0, 0] is used instead. Error message is logged.\n\nAdditionally, when only one argument is used, it can be sent into the function directly without the need to have it in an array.\n\n|  |  |\n|---|---|\n| ✓ | ```sqf<br>player call TAG_fnc_myFunction;<br>``` |"},{"heading":"Returning Value","level":3,"markdown":"A function can return a result (object reference, script handle, etc) that can then be saved by the user. If no value is returned, the variable would be nil and could lead to script errors.\n\n```sqf\n_myVar = [player, getPosASL myCar] call TAG_fnc_myFunction;\n```\n\nIt is a good practice to **always** return a value, even if it would be a simple true marking the function as completed. Let's use the example function from above:\n\n```sqf\nparams [\n    [\"_unit\", objNull, [objNull]],\n    [\"_target\", [0, 0, 0], [[], objNull], [2, 3]]\n];\n_unit doWatch _target;\ntrue;\n```\n\n> [!NOTE]\n> Note that a spawned function will always return a Script Handle, as per spawn command's behaviour."},{"heading":"Showing Errors","level":3,"markdown":"While param and params can filter out the most common issues, the function will sometimes have special rules which will need to be handled.\nLet's return back to the example function, where we would want to terminate the function with error when *_unit* is dead:\n\n```sqf\nparams [[\"_unit\", objNull, [objNull]], [\"_target\", [0, 0, 0], [[], objNull], [2, 3]]];\nif (!alive _unit) exitWith { [\"Unit %1 must be alive.\", _unit] call BIS_fnc_error; false; };\n_unit doWatch _target;\ntrue;\n```\n\nNotice that we're returning false at the end of exitWith code.\n\n> [!IMPORTANT]\n> Error states must always return value of the same type as when everything is fine (Boolean in this case).\n\nBIS_fnc_error accepts String and Array of formatted ext. The error is logged into RPT and if the mission is previewd from the editor, it will also appear on screen.\n\n|  |  |\n|---|---|\n| RPT | \"User1/log: ERROR: [BIS_fnc_respawnTickets] #0: 0 is type SCALAR, must be NAMESPACE, SIDE, GROUP, OBJECT, BOOL. true used instead.\" |\n| In-game |  |"},{"heading":"Logging","level":3,"markdown":"Apart from errors, it is possible to print any needed debug message. Use one of the following functions:\n- BIS_fnc_log - log a data of any type (e.g., String, Number, Object, ...)\n- BIS_fnc_logFormat - log formatted text\nProfile name and function name will automatically appear in the output text, to help identifying the source.\n\nUsage examples:\n\n| Expression | RPT Output |\n|---|---|\n| \"Hello World\" call BIS_fnc_log; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] Hello World\" |\n| 42 call BIS_fnc_log; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] 42\" |\n| [\"I'm playing %1\", missionName] call BIS_fnc_logFormat; | \"User1/BIS_fnc_log: [TAG_fnc_myFunction] I'm playing FalconWing\" |\n\nTo prevent RPT spam, logging is by default enabled only when previewing a mission from the editor. To force it in the mission everywhere, use the following Description.ext attribute:\n\n```cpp\nallowFunctionsLog = 1;\n```"},{"heading":"Recompiling","level":3,"markdown":"Once compiled, functions remain unchanged and editing their file won't have any effect in the game.\nTo adjust functions on the fly, their recompilation can be manually triggered - see Arma 3: Functions Viewer and BIS_fnc_recompile."},{"heading":"Meta Variables","level":3,"markdown":"System is adding header with basic meta data to all functions. Following local variables are declared there:\n- **_fnc_scriptName**: String - Function name (e.g., TAG_fnc_myFunction)\n- **_fnc_scriptNameParent**: String - Name of q function from which the current one was called (_fnc_scriptName used when not defined)\n\n> [!IMPORTANT]\n> Do not modify these values!"},{"heading":"See Also","level":3,"markdown":"- Arma 3: Functions Library\n- Arma 2: Functions Library\n- Take On Helicopters: Functions Library\n\nArma 3 Tutorials"}],"categories":["Arma 3: Tutorials","Scripting Topics"],"groups":["Scripting"]},{"name":"Array","title":"Array","type":"topic","url":"https://community.bistudio.com/wiki/Array","revid":378805,"updated":"2026-06-29T16:53:01Z","aliases":[],"markdown":"An **Array** is a list of items of varying variable types (including other arrays). Different types can coexist within the same array.\n\nSee also: Arrays\n\n> [!WARNING]\n> Since Arma 3 v1.56, arrays are limited to maximum of **9,999,999** (sometimes 10,000,000) elements.\n\n### Working With Arrays\n\n#### Array Properties\n\nAn array variable is a **reference** to the array (see [Wikipedia reference page](https://en.wikipedia.org/wiki/Reference_(computer_science)));\nthis means that if the array is edited, all the scripts/functions using a reference to this array will see the edition.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = _myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // will be \"z\"\n```\n\nAn array set through setVariable does not need to be assigned again if you modify it by reference:\n\n```sqf\nplayer setVariable [\"myArray\", [\"a\", \"b\", \"c\"]];\nprivate _myArray = player getVariable \"myArray\";\n_myArray set [1, \"z\"];\nplayer getVariable \"myArray\"; // is [\"a\", \"z\", \"c\"]\n```\n\n#### Array Creation\n\n```sqf\n// Example of an empty array\nprivate _myArray = [];\ncount _myArray;            // returns 0\n\n// Example of a filled array\nprivate _myFilledArray = [\"abc\", \"def\"];\ncount _myFilledArray;    // returns 2\n```\n\nAn array can hold another array within it, that can hold another array itself, etc:\n\n```sqf\nprivate _myArray = [[\"my\", \"subArray\", 1], [\"mySubArray2\"], [[\"my\", \"sub\", \"sub\", \"array\"]]];\ncount   _myArray;                        // returns 3\ncount  (_myArray select 0);                // returns 3\ncount  (_myArray select 1);                // returns 1\ncount  (_myArray select 2);                // returns 1\ncount ((_myArray select 2) select 0);    // returns 4\n```\n\n#### Getting an element\n\nAn array uses a zero-based index for its elements:\n\n```sqf\nprivate _myArray = [\"first item\", \"second item\", \"third item\"];\n_myArray select 0;    // returns \"first item\"\n_myArray # 2;        // returns \"third item\" - Arma 3 only\n```\n\n#### Setting an Element\n\n```sqf\nprivate _myArray = [\"first item\", \"second item\", \"third item\"];\n_myArray select 1;                    // returns \"second item\"\n_myArray set [1, \"hello there\"];    // _myArray is [\"first item\", \"hello there\", \"third item\"]\n```\n\n> [!IMPORTANT]\n> If the index given to the set command is out of bounds, the array will resize to incorporate the index *as its last value*.\n> All the \"empty spaces\" between the last valid element and the new set element will be filled with nil\n\n#### Counting elements\n\n```sqf\nprivate _myArray = [\"first item\", [\"second item's subitem 1\", \"second item's subitem 2\"], \"third item\"];\ncount _myArray; // returns 3 - arrays are not counted recursively\n```\n\n#### Changing array size\n\nThe resize command is made to reduce or expand an array:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray resize 3; // _myArray is [\"a\", \"b\", \"c\"]\n```\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray resize 5; // _myArray is [\"a\", \"b\", \"c\", nil, nil]\n```\n\n> [!IMPORTANT]\n> You do **not** need to extend an array before adding any elements.\n\n#### Array Copy\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = _myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // will be \"z\"\n```\n\n```sqf\nprivate _myArray = [[\"a\", \"b\", \"c\"], [\"d\", \"e\", \"f\"]];\nprivate _subArray1 = _myArray select 0;\n_subArray1 set [1, \"z\"];\n// _subArray1 is now [\"a\", \"z\", \"c\"]\n// _myArray is now [[\"a\", \"z\", \"c\"], [\"d\", \"e\", \"f\"]]\n```\n\nIn order to avoid this behaviour, **copy** the array with + (plus):\n\n```sqf\n// making copy\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = +_myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // still \"b\"\n```\n\nSub-arrays are also deep-copied; `_myNewArray` will not point at the same sub-array instances.\n\n#### Adding (Appending) Elements\n\nIn Arma 3 use append and pushBack commands:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray pushBack \"d\";        // _myArray is [\"a\", \"b\", \"c\", \"d\"] - pushback = add the element at the end\n_myArray append [\"e\", \"f\"];    // _myArray is [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"] - append = pushback for each provided items\n```\n\nYou could also use the plus (+) operator to add arrays.\nThe difference is that addition returns a copy of array and thus a little slower than append and pushBack, which modify the target array.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray = _myArray + [\"d\"];        // _myArray is [\"a\", \"b\", \"c\", \"d\"]\n_myArray = _myArray + [\"e\", \"f\"];    // _myArray is [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]\n```\n\n#### Removing (Deleting) Elements\n\nIn Arma 3 the deleteAt and deleteRange commands are available:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray deleteAt 0; // _myArray is [\"b\", \"c\", \"d\", \"e\"]\n```\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray deleteRange [1, 2];    // _myArray is [\"a\", \"d\", \"e\"]\n```\n\nYou can also use the minus (-) operator to subtract arrays.\nThe subtraction returns array copy, just like addition, and is not as fast as deleteAt and deleteRange which modify target arrays.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray = _myArray - [\"a\"]; // _myArray is [\"b\", \"c\", \"d\", \"e\"]\n```\n\nIn Arma 3 it became possible to also subtract nested arrays:\n\n```sqf\nprivate _myArray = [[\"a\", \"b\", \"c\"], [\"d\", \"e\", \"f\"], [\"g\", \"h\", \"i\"]];\n_myArray = _myArray - [[\"d\", \"e\", \"f\"]]; // _myArray is [[\"a\", \"b\", \"c\"], [\"g\", \"h\", \"i\"]]\n```\n\nThe subtraction will remove *all* elements of the second array from the first one:\n\n```sqf\n_myArray = [\"a\", \"b\", \"c\", \"a\", \"b\", \"c\"] - [\"a\", \"b\"]; // _myArray is [\"c\", \"c\"]\n```\n\nThe solution to this issue is the combined use of set and an item that you know is **not** present in the array:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"a\", \"b\", \"c\"];\n_myArray set [2, objNull];            // _myArray is [\"a\", \"b\", objNull, \"a\", \"b\", \"c\"]\n_myArray = _myArray - [objNull];    // _myArray is [\"a\", \"b\", \"a\", \"b\", \"c\"]\n```\n\nUsing this technique, it is possible to mimic deleteRange behaviour this way:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n{ _myArray set [_x, objNull] } forEach [1, 2];    // _myArray is [\"a\", objNull, objNull, \"d\", \"e\"]\n_array = _array - [objNull];                    // _myArray is [\"a\", \"d\", \"e\"]\n```\n\n#### Going Through the Array\n\nThe simplest way to iterate through an array is the forEach command:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n{ systemChat _x } forEach _myArray;\n```\n\nA combination of for, count and select can also be used:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\nfor \"_i\" from 0 to (count _myArray) -1 do { // count returns 5, but it is a zero-based index\n    systemChat (_myArray select _i);\n};\n```\n\n### Advanced Usage\n\n#### apply\n\nSimilar to the [\"map\" function in Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map),\napply allows to apply code to every elements in an array and return a copy:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n_myArray = _myArray apply { _x * 2 }; // _myArray is [2, 4, 6, 8, 10]\n\n// same as (but faster than)\n_myArray = + _myArray;\nfor \"_i\" from 0 to count _myArray -1 do\n{\n    private _element = _myArray select _i;\n    _myArray set [_i, _element * 2];\n};\n```\n\n#### select\n\nA simple way to filter an array (and obtain a new one) is using select's alternative syntax:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\nprivate _filteredArray = _myArray select { _x > 3 }; // _filteredArray is [4, 5]\n\n// same as\nprivate _filteredArray = [];\n{ if (_x > 3) then { _filteredArray pushBack _x } } forEach _myArray;\n```\n\n#### findIf\n\nThe findIf command was introduced in Arma 3 and allows you to go through the whole list and stop **as soon as the condition is met**, returning the condition-meeting element's array index:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n_myArray findIf { _x == 3 } > -1; // returns true, meaning there is an element that equals 3\n_myArray findIf { _x == 6 } > -1; // returns false, meaning there is no element that is equal to 6\n```\n\nYou could use count to achieve the same result, however count won't stop until it iterated through the whole array, so it might take longer.\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n{ _x == 3 } count _myArray > 0; // returns true, meaning there is an element that equals 3\n{ _x == 6 } count _myArray > 0; // returns false, meaning there is no element that is equal to 6\n```\n\n#### arrayIntersect\n\nThe arrayIntersect command returns a new array filled with the items found in both provided lists:\n\n```sqf\nprivate _array1 = [1, 2, 3, 4];\nprivate _array2 = [3, 4, 5, 6];\nprivate _result = _array1 arrayIntersect _array2; // _result is [3, 4]\n```\n\n**You can remove duplicates (get unique items) with this command:**\n\n```sqf\nprivate _myArray = [1, 2, 2, 3, 4];\nprivate _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]\n```\n\nBe wary that nil elements get removed by this method:\n\n```sqf\nprivate _myArray = [1, 2, nil, 3, 4];\nprivate _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]\n```\n\n#### Selective Removal\n\nSelectively filter out single elements from `_arrayA` based on `_arrayB`.\n\nThis is useful in the case where *some* duplicates must be removed.\n\n```sqf\nprivate _arrayA = [1, 2, 3, 2, 4, 5, 4];\nprivate _arrayB = [2, 2, 4];\n\n{\n    private _index = _arrayA find _x;\n    if (_index != -1) then\n    {\n        _arrayA deleteAt _index;\n    };\n} forEach _arrayB;\n\n_arrayA; // is now [1, 3, 5, 4]\n```\n\n#### Sorting\n\n##### sort\n\nThe sort command allows for sorting an array of String, Number or sub-Arrays of string/number. It modifies the original array and **does not return anything**:\n\n```sqf\nprivate _myArray = [\"zzz\", \"aaa\", \"ccc\"];\n_myArray sort true; // _myArray is [\"aaa\", \"ccc\", \"zzz\"]\n```\n\n```sqf\nprivate _myArray = [666, 57, 1024, 42];\n_myArray sort false; // _myArray is [1024, 666, 57, 42]\n```\n\n```sqf\nprivate _myArray = [[\"zzz\", 0], [\"aaa\", 42], [\"ccc\", 33]];\n_myArray sort true; // _myArray is [[\"aaa\", 42], [\"ccc\", 33], [\"zzz\", 0]]\n```\n\n##### reverse\n\nThe reverse command simply reverses the array order:\n\n```sqf\nprivate _myArray = [99, 33, 17, 24, \"a\", [3,2,1], 7777];\nreverse _myArray; // _myArray is [7777, [3,2,1], \"a\", 24, 17, 33, 99]\n```\n\n##### BIS_fnc_sortBy\n\nThe function BIS_fnc_sortBy has been created for more complex sorting. Its algorithm input must return a number:\n\n```sqf\nprivate _closestHelicopters = [[_heli1, _heli2, _heli3], [], { player distance _x }, \"ASCEND\"] call BIS_fnc_sortBy;\n```\n\n### Common Errors\n\n#### Index Rounding\n\nIn Real Virtuality scripts, indices are rounded to the nearest whole number.\nA boundary case (X.5, where X is any whole number) rounds to the nearest **even** whole number.\n\n**Boundary cases:**\n- -0.5 <= index <= 0.5 rounds to 0\n-  0.5 <  index <  1.5 rounds to 1\n-  1.5 <= index <= 2.5 rounds to 2\n-  2.5 <  index <  3.5 rounds to 3\n\n**In short:**\n- -0.5 rounds **up** to 0\n-  0.5 rounds **down** to 0\n-  1.5 rounds **up** to 2\n-  2.5 rounds **down** to 2\n-  3.5 rounds **up** to 4\netc.\n\n> [!NOTE]\n> This behaviour is different from random's behaviour.\n\n#### Index out of Range\n\nThe following code lists Arma 3 behaviour on wrong indices:\n\n```sqf\nprivate _myArray = [\"element0\"];\n_myArray select -1; // throws a Error Zero Divisor error message\n_myArray select  0; // returns \"element0\"\n_myArray select  1; // returns nil\n_myArray select  2; // throws a Error Zero Divisor error message\n```\n\n##### param\n\nUse the param command in order to avoid out of range error:\n\n```sqf\nprivate _myArray = [0, 1, 2];\n_myArray select 5;            // error: out of range\n_myArray param [5];            // returns nil\n_myArray param [5, \"abc\"];    // returns default value \"abc\" on invalid index\n```\n\n> [!NOTE]\n> See also params to define multiple items at once.\n\n##### set\n\nIf the index given to the set command is out of bounds:\n- if the index rounded to a negative number, then an Error Zero Divisor message will be displayed in game.\n- if the index rounded to a positive number, then the array will resize to incorporate the index *as its last value*. Each element between the last valid element, and the new set element, will be the null type\n\n#### Zero Divisor\n\nSee above - a used array index may be negative.\n\n#### Unexpected \",\"\n\nThis error originates from a bad syntax:\n\n```sqf\nprivate _myErroneousArray = [\"Weapon1\", \"Weapon2\", \"Weapon3\",]; // The last element in an array must not end by \",\"\n\n// this mostly happens in vertical arrays\nprivate _myErroneousArray = [\n    \"element1\",\n    \"element2\",\n    \"element3\", // this one comma is wrong\n];\n```\n\n#### Reserved variable in expression\n\nThis issue arises when trying to modify a read-only array (such as select arrays that are returned from an addon, or eventually a trigger's thisList).\n\nTo combat this, *copy* said array with the plus (+) command before modifying:\n\n```sqf\nprivate _readOnlyArray = thisList;    // assuming the code is called from within a trigger\n_readOnlyArray set [1, \"test\"];        // Error: Reserved variable in expression - thisList return value is read-only\n\n// No Error\nprivate _normalArray = +_readOnlyArray;    // shallow-copy the array instead of using a reference\n_normalArray set [1, \"test\"];            // perfectly fine\n```\n\n### See Also\n\n- Arrays\n- Command Group: Arrays\n- Function Group: Arrays","sections":[{"heading":null,"level":1,"markdown":"An **Array** is a list of items of varying variable types (including other arrays). Different types can coexist within the same array.\n\nSee also: Arrays\n\n> [!WARNING]\n> Since Arma 3 v1.56, arrays are limited to maximum of **9,999,999** (sometimes 10,000,000) elements."},{"heading":"Working With Arrays","level":3,"markdown":""},{"heading":"Array Properties","level":4,"markdown":"An array variable is a **reference** to the array (see [Wikipedia reference page](https://en.wikipedia.org/wiki/Reference_(computer_science)));\nthis means that if the array is edited, all the scripts/functions using a reference to this array will see the edition.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = _myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // will be \"z\"\n```\n\nAn array set through setVariable does not need to be assigned again if you modify it by reference:\n\n```sqf\nplayer setVariable [\"myArray\", [\"a\", \"b\", \"c\"]];\nprivate _myArray = player getVariable \"myArray\";\n_myArray set [1, \"z\"];\nplayer getVariable \"myArray\"; // is [\"a\", \"z\", \"c\"]\n```"},{"heading":"Array Creation","level":4,"markdown":"```sqf\n// Example of an empty array\nprivate _myArray = [];\ncount _myArray;            // returns 0\n\n// Example of a filled array\nprivate _myFilledArray = [\"abc\", \"def\"];\ncount _myFilledArray;    // returns 2\n```\n\nAn array can hold another array within it, that can hold another array itself, etc:\n\n```sqf\nprivate _myArray = [[\"my\", \"subArray\", 1], [\"mySubArray2\"], [[\"my\", \"sub\", \"sub\", \"array\"]]];\ncount   _myArray;                        // returns 3\ncount  (_myArray select 0);                // returns 3\ncount  (_myArray select 1);                // returns 1\ncount  (_myArray select 2);                // returns 1\ncount ((_myArray select 2) select 0);    // returns 4\n```"},{"heading":"Getting an element","level":4,"markdown":"An array uses a zero-based index for its elements:\n\n```sqf\nprivate _myArray = [\"first item\", \"second item\", \"third item\"];\n_myArray select 0;    // returns \"first item\"\n_myArray # 2;        // returns \"third item\" - Arma 3 only\n```"},{"heading":"Setting an Element","level":4,"markdown":"```sqf\nprivate _myArray = [\"first item\", \"second item\", \"third item\"];\n_myArray select 1;                    // returns \"second item\"\n_myArray set [1, \"hello there\"];    // _myArray is [\"first item\", \"hello there\", \"third item\"]\n```\n\n> [!IMPORTANT]\n> If the index given to the set command is out of bounds, the array will resize to incorporate the index *as its last value*.\n> All the \"empty spaces\" between the last valid element and the new set element will be filled with nil"},{"heading":"Counting elements","level":4,"markdown":"```sqf\nprivate _myArray = [\"first item\", [\"second item's subitem 1\", \"second item's subitem 2\"], \"third item\"];\ncount _myArray; // returns 3 - arrays are not counted recursively\n```"},{"heading":"Changing array size","level":4,"markdown":"The resize command is made to reduce or expand an array:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray resize 3; // _myArray is [\"a\", \"b\", \"c\"]\n```\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray resize 5; // _myArray is [\"a\", \"b\", \"c\", nil, nil]\n```\n\n> [!IMPORTANT]\n> You do **not** need to extend an array before adding any elements."},{"heading":"Array Copy","level":4,"markdown":"```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = _myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // will be \"z\"\n```\n\n```sqf\nprivate _myArray = [[\"a\", \"b\", \"c\"], [\"d\", \"e\", \"f\"]];\nprivate _subArray1 = _myArray select 0;\n_subArray1 set [1, \"z\"];\n// _subArray1 is now [\"a\", \"z\", \"c\"]\n// _myArray is now [[\"a\", \"z\", \"c\"], [\"d\", \"e\", \"f\"]]\n```\n\nIn order to avoid this behaviour, **copy** the array with + (plus):\n\n```sqf\n// making copy\nprivate _myArray = [\"a\", \"b\", \"c\"];\nprivate _myNewArray = +_myArray;\n_myArray set [1, \"z\"];\n_myNewArray select 1; // still \"b\"\n```\n\nSub-arrays are also deep-copied; `_myNewArray` will not point at the same sub-array instances."},{"heading":"Adding (Appending) Elements","level":4,"markdown":"In Arma 3 use append and pushBack commands:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray pushBack \"d\";        // _myArray is [\"a\", \"b\", \"c\", \"d\"] - pushback = add the element at the end\n_myArray append [\"e\", \"f\"];    // _myArray is [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"] - append = pushback for each provided items\n```\n\nYou could also use the plus (+) operator to add arrays.\nThe difference is that addition returns a copy of array and thus a little slower than append and pushBack, which modify the target array.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\"];\n_myArray = _myArray + [\"d\"];        // _myArray is [\"a\", \"b\", \"c\", \"d\"]\n_myArray = _myArray + [\"e\", \"f\"];    // _myArray is [\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"]\n```"},{"heading":"Removing (Deleting) Elements","level":4,"markdown":"In Arma 3 the deleteAt and deleteRange commands are available:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray deleteAt 0; // _myArray is [\"b\", \"c\", \"d\", \"e\"]\n```\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray deleteRange [1, 2];    // _myArray is [\"a\", \"d\", \"e\"]\n```\n\nYou can also use the minus (-) operator to subtract arrays.\nThe subtraction returns array copy, just like addition, and is not as fast as deleteAt and deleteRange which modify target arrays.\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n_myArray = _myArray - [\"a\"]; // _myArray is [\"b\", \"c\", \"d\", \"e\"]\n```\n\nIn Arma 3 it became possible to also subtract nested arrays:\n\n```sqf\nprivate _myArray = [[\"a\", \"b\", \"c\"], [\"d\", \"e\", \"f\"], [\"g\", \"h\", \"i\"]];\n_myArray = _myArray - [[\"d\", \"e\", \"f\"]]; // _myArray is [[\"a\", \"b\", \"c\"], [\"g\", \"h\", \"i\"]]\n```\n\nThe subtraction will remove *all* elements of the second array from the first one:\n\n```sqf\n_myArray = [\"a\", \"b\", \"c\", \"a\", \"b\", \"c\"] - [\"a\", \"b\"]; // _myArray is [\"c\", \"c\"]\n```\n\nThe solution to this issue is the combined use of set and an item that you know is **not** present in the array:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"a\", \"b\", \"c\"];\n_myArray set [2, objNull];            // _myArray is [\"a\", \"b\", objNull, \"a\", \"b\", \"c\"]\n_myArray = _myArray - [objNull];    // _myArray is [\"a\", \"b\", \"a\", \"b\", \"c\"]\n```\n\nUsing this technique, it is possible to mimic deleteRange behaviour this way:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n{ _myArray set [_x, objNull] } forEach [1, 2];    // _myArray is [\"a\", objNull, objNull, \"d\", \"e\"]\n_array = _array - [objNull];                    // _myArray is [\"a\", \"d\", \"e\"]\n```"},{"heading":"Going Through the Array","level":4,"markdown":"The simplest way to iterate through an array is the forEach command:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\n{ systemChat _x } forEach _myArray;\n```\n\nA combination of for, count and select can also be used:\n\n```sqf\nprivate _myArray = [\"a\", \"b\", \"c\", \"d\", \"e\"];\nfor \"_i\" from 0 to (count _myArray) -1 do { // count returns 5, but it is a zero-based index\n    systemChat (_myArray select _i);\n};\n```"},{"heading":"Advanced Usage","level":3,"markdown":""},{"heading":"apply","level":4,"markdown":"Similar to the [\"map\" function in Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map),\napply allows to apply code to every elements in an array and return a copy:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n_myArray = _myArray apply { _x * 2 }; // _myArray is [2, 4, 6, 8, 10]\n\n// same as (but faster than)\n_myArray = + _myArray;\nfor \"_i\" from 0 to count _myArray -1 do\n{\n    private _element = _myArray select _i;\n    _myArray set [_i, _element * 2];\n};\n```"},{"heading":"select","level":4,"markdown":"A simple way to filter an array (and obtain a new one) is using select's alternative syntax:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\nprivate _filteredArray = _myArray select { _x > 3 }; // _filteredArray is [4, 5]\n\n// same as\nprivate _filteredArray = [];\n{ if (_x > 3) then { _filteredArray pushBack _x } } forEach _myArray;\n```"},{"heading":"findIf","level":4,"markdown":"The findIf command was introduced in Arma 3 and allows you to go through the whole list and stop **as soon as the condition is met**, returning the condition-meeting element's array index:\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n_myArray findIf { _x == 3 } > -1; // returns true, meaning there is an element that equals 3\n_myArray findIf { _x == 6 } > -1; // returns false, meaning there is no element that is equal to 6\n```\n\nYou could use count to achieve the same result, however count won't stop until it iterated through the whole array, so it might take longer.\n\n```sqf\nprivate _myArray = [1, 2, 3, 4, 5];\n{ _x == 3 } count _myArray > 0; // returns true, meaning there is an element that equals 3\n{ _x == 6 } count _myArray > 0; // returns false, meaning there is no element that is equal to 6\n```"},{"heading":"arrayIntersect","level":4,"markdown":"The arrayIntersect command returns a new array filled with the items found in both provided lists:\n\n```sqf\nprivate _array1 = [1, 2, 3, 4];\nprivate _array2 = [3, 4, 5, 6];\nprivate _result = _array1 arrayIntersect _array2; // _result is [3, 4]\n```\n\n**You can remove duplicates (get unique items) with this command:**\n\n```sqf\nprivate _myArray = [1, 2, 2, 3, 4];\nprivate _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]\n```\n\nBe wary that nil elements get removed by this method:\n\n```sqf\nprivate _myArray = [1, 2, nil, 3, 4];\nprivate _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]\n```"},{"heading":"Selective Removal","level":4,"markdown":"Selectively filter out single elements from `_arrayA` based on `_arrayB`.\n\nThis is useful in the case where *some* duplicates must be removed.\n\n```sqf\nprivate _arrayA = [1, 2, 3, 2, 4, 5, 4];\nprivate _arrayB = [2, 2, 4];\n\n{\n    private _index = _arrayA find _x;\n    if (_index != -1) then\n    {\n        _arrayA deleteAt _index;\n    };\n} forEach _arrayB;\n\n_arrayA; // is now [1, 3, 5, 4]\n```"},{"heading":"Sorting","level":4,"markdown":""},{"heading":"sort","level":5,"markdown":"The sort command allows for sorting an array of String, Number or sub-Arrays of string/number. It modifies the original array and **does not return anything**:\n\n```sqf\nprivate _myArray = [\"zzz\", \"aaa\", \"ccc\"];\n_myArray sort true; // _myArray is [\"aaa\", \"ccc\", \"zzz\"]\n```\n\n```sqf\nprivate _myArray = [666, 57, 1024, 42];\n_myArray sort false; // _myArray is [1024, 666, 57, 42]\n```\n\n```sqf\nprivate _myArray = [[\"zzz\", 0], [\"aaa\", 42], [\"ccc\", 33]];\n_myArray sort true; // _myArray is [[\"aaa\", 42], [\"ccc\", 33], [\"zzz\", 0]]\n```"},{"heading":"reverse","level":5,"markdown":"The reverse command simply reverses the array order:\n\n```sqf\nprivate _myArray = [99, 33, 17, 24, \"a\", [3,2,1], 7777];\nreverse _myArray; // _myArray is [7777, [3,2,1], \"a\", 24, 17, 33, 99]\n```"},{"heading":"BIS_fnc_sortBy","level":5,"markdown":"The function BIS_fnc_sortBy has been created for more complex sorting. Its algorithm input must return a number:\n\n```sqf\nprivate _closestHelicopters = [[_heli1, _heli2, _heli3], [], { player distance _x }, \"ASCEND\"] call BIS_fnc_sortBy;\n```"},{"heading":"Common Errors","level":3,"markdown":""},{"heading":"Index Rounding","level":4,"markdown":"In Real Virtuality scripts, indices are rounded to the nearest whole number.\nA boundary case (X.5, where X is any whole number) rounds to the nearest **even** whole number.\n\n**Boundary cases:**\n- -0.5 <= index <= 0.5 rounds to 0\n-  0.5 <  index <  1.5 rounds to 1\n-  1.5 <= index <= 2.5 rounds to 2\n-  2.5 <  index <  3.5 rounds to 3\n\n**In short:**\n- -0.5 rounds **up** to 0\n-  0.5 rounds **down** to 0\n-  1.5 rounds **up** to 2\n-  2.5 rounds **down** to 2\n-  3.5 rounds **up** to 4\netc.\n\n> [!NOTE]\n> This behaviour is different from random's behaviour."},{"heading":"Index out of Range","level":4,"markdown":"The following code lists Arma 3 behaviour on wrong indices:\n\n```sqf\nprivate _myArray = [\"element0\"];\n_myArray select -1; // throws a Error Zero Divisor error message\n_myArray select  0; // returns \"element0\"\n_myArray select  1; // returns nil\n_myArray select  2; // throws a Error Zero Divisor error message\n```"},{"heading":"param","level":5,"markdown":"Use the param command in order to avoid out of range error:\n\n```sqf\nprivate _myArray = [0, 1, 2];\n_myArray select 5;            // error: out of range\n_myArray param [5];            // returns nil\n_myArray param [5, \"abc\"];    // returns default value \"abc\" on invalid index\n```\n\n> [!NOTE]\n> See also params to define multiple items at once."},{"heading":"set","level":5,"markdown":"If the index given to the set command is out of bounds:\n- if the index rounded to a negative number, then an Error Zero Divisor message will be displayed in game.\n- if the index rounded to a positive number, then the array will resize to incorporate the index *as its last value*. Each element between the last valid element, and the new set element, will be the null type"},{"heading":"Zero Divisor","level":4,"markdown":"See above - a used array index may be negative."},{"heading":"Unexpected \",\"","level":4,"markdown":"This error originates from a bad syntax:\n\n```sqf\nprivate _myErroneousArray = [\"Weapon1\", \"Weapon2\", \"Weapon3\",]; // The last element in an array must not end by \",\"\n\n// this mostly happens in vertical arrays\nprivate _myErroneousArray = [\n    \"element1\",\n    \"element2\",\n    \"element3\", // this one comma is wrong\n];\n```"},{"heading":"Reserved variable in expression","level":4,"markdown":"This issue arises when trying to modify a read-only array (such as select arrays that are returned from an addon, or eventually a trigger's thisList).\n\nTo combat this, *copy* said array with the plus (+) command before modifying:\n\n```sqf\nprivate _readOnlyArray = thisList;    // assuming the code is called from within a trigger\n_readOnlyArray set [1, \"test\"];        // Error: Reserved variable in expression - thisList return value is read-only\n\n// No Error\nprivate _normalArray = +_readOnlyArray;    // shallow-copy the array instead of using a reference\n_normalArray set [1, \"test\"];            // perfectly fine\n```"},{"heading":"See Also","level":3,"markdown":"- Arrays\n- Command Group: Arrays\n- Function Group: Arrays"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Boolean","title":"Boolean","type":"topic","url":"https://community.bistudio.com/wiki/Boolean","revid":245309,"updated":"2021-02-10T16:02:46Z","aliases":["BOOL","boolean"],"markdown":"**Description:**\n\nA Boolean can either be true or false.\nNote that Booleans are **real** types in the scripting language.\n\nIn config.cpp (addons), a boolean is simply a poetic licence, a convenience, for a zero/non zero integer.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\n\nA Boolean can either be true or false.\nNote that Booleans are **real** types in the scripting language.\n\nIn config.cpp (addons), a boolean is simply a poetic licence, a convenience, for a zero/non zero integer."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Code","title":"Code","type":"topic","url":"https://community.bistudio.com/wiki/Code","revid":378166,"updated":"2026-03-02T16:38:58Z","aliases":["Block"],"markdown":"**Code** represents data consisting of commands and their parameters.\nIt is defined in script by being wrapped in `{`/`}` brackets, and is precompiled by the game engine.\n\nThe contents of SQF and SQS files are Code.\n\nExamples:\n\n```sqf\nwhile { alive player } do { sleep 1; hintSilent format [\"Health: %1/100\", round ((1 - damage player) * 100)]; };\nunit addEventHandler [\"Killed\", { systemChat format [\"%1 is dead\", name (_this select 0)]; }];\nonMapSingleClick { systemChat format [\"You clicked at %1\", _pos]; };\n```\n\n> [!NOTE]\n> See Code vs. Strings for more information on code/string data typing.","sections":[{"heading":null,"level":1,"markdown":"**Code** represents data consisting of commands and their parameters.\nIt is defined in script by being wrapped in `{`/`}` brackets, and is precompiled by the game engine.\n\nThe contents of SQF and SQS files are Code.\n\nExamples:\n\n```sqf\nwhile { alive player } do { sleep 1; hintSilent format [\"Health: %1/100\", round ((1 - damage player) * 100)]; };\nunit addEventHandler [\"Killed\", { systemChat format [\"%1 is dead\", name (_this select 0)]; }];\nonMapSingleClick { systemChat format [\"You clicked at %1\", _pos]; };\n```\n\n> [!NOTE]\n> See Code vs. Strings for more information on code/string data typing."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Code Best Practices","title":"Code Best Practices","type":"topic","url":"https://community.bistudio.com/wiki/Code_Best_Practices","revid":369844,"updated":"2024-10-16T13:51:56Z","aliases":[],"markdown":"### Getting Started\n\nIn the domain of development, any rule is a rule of thumb.\nIf a rule states for example that it is better that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it.\nIf you have a good structure, **do not** change your code to enforce a single arbitrary rule.\nIf you break many of them, you may have to change something; again, this is according to your judgement.\n\nWith that being said, let's go!\n\n#### Prerequisites\n\n- An advanced text editor such as Visual Studio Code or Notepad++ - see Community Tools#Code Edition for useful tools and plugins\n- Some English knowledge, helped if needed by a translator tool such as [Google Translate](https://www.google.com/translate) or [DeepL](https://www.deepl.com/)\n- Access to this wiki is a plus (the Swiss flag is, too)\n- Tutorials/examples (YouTube tutorials, community tutorials, Example Code)\n- Google-Fu (a.k.a search engine skills)\n- Arma Discord server: [ARMA](https://discord.gg/arma), channel `1. arma3_scripting`\n\n### Best Practices\n\n#### Code Format\n\n- Whatever you do about your code's format, **be consistent**.\n- Choose an indentation format **and stick to it**. There is not especially one indent better than another (*but there sure are terrible ones*), again the important point here being *consistency*.\n  - Common indentation styles are:\n    - [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R_style) indenting\n    - [Allman style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) indenting\n  - Use empty space. Line return, spaces before and after brackets, if this improves readability, use it: space is free.\n  - indent with two/four spaces **or** one tab. Do not mix these.\n  - *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n-  **was** \"useful\" only for editor fields that for no apparent reason refused commands returning a value. You do **not** need it in script files, and don't need it in editor fields anymore **since Arma 3 v2.04**.\n\n#### Variable Format\n\n- Name your variables and functions properly: While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being.\n  - Your variable names must have a meaning: variables like **_u** instead of **_uniform** should not exist. **_i** is an accepted iteration variable name (e.g in for loops).\n  - It is recommended to use [camel-case](https://en.wikipedia.org/wiki/Camel_case) your variables; camel-casing (namingLikeThis) your variables and functions make the code naturally more readable, especially for long names.\n- Prefix your public variables and setVariable with your tag in order to avoid any conflict about other mods, scripts or mission variables.\n- Make your variables **private** thanks to the private or params keyword in order to avoid accidental upper-scope overwriting of variables of the same name.\n- Defined constants must be UPPERCASE_WITH_UNDERSCORES (e.g `#define SOME_CONST`).\n\n#### Code Structuration\n\n- **DRY:** **D**on't **R**epeat **Y**ourself. If you write the same code block or the same logic many times, export this code as a function and use parameters with it.\n  - If your code has too many levels, it is time to split and rethink it - maybe using exitWith (e.g `if (a) then { if (b) then { if (c) then { /* etc */  }; }; };`)\n  - Do NOT use macros as functions - these hinder readability. Use functions instead.\n- `// Comments` in your code must not explain *what* the code does, but *why* it is done this way (if needed). Your code organisation combined to your variable names must be enough to be read by a human.\n\n#### Code/Files Organisation\n\n- Use CfgFunctions to declare the functions that will be called frequently.\n  - One Functions directory, with sub-directories if needed.\n- Use Event Scripts as needed.\n- Don't put **any code** in a unit's init box *but eventually* local commands for this specific unit - **all** unit's init boxes are run client-side on client connection.\n\n### Examples\n\n| Bad Example | Good Example |\n|---|---|\n| #### Good Practice examples |  |\n| _unit = player; | **private** _unit = player; |\n| private _uB = allUnits select { side _x == blufor }; | private **_bluforUnits** = allUnits select { side _x == blufor }; |\n| private _plead = leader player; | private **_playersLeader** = leader player; |\n| finalAssault = true; publicVariable \"finalAssault\"; | **PREFIX_**finalAssault = true; publicVariable \"**PREFIX_**finalAssault\"; |\n| player setVariable [\"MoneyInPocket\", 250, true]; | player setVariable [\"**PREFIX_**MoneyInPocket\", 250, true]; |\n| #define KILL(UNIT) UNIT setDamage 1<br> // ...<br> {<br> \tKILL(_x);<br> } forEach (units group player - [player]); | private _killFnc = { _this setDamage 1; };<br> // ...<br> {<br> \t_x call _killFnc;<br> } forEach (units group player - [player]); |\n| `// if player has less than 3/4 health`<br> if (damage player > 0.25) then<br> {<br> \t`// if the player has no first aid kit`<br> \tif (not (\"FirstAidKit\" in items player))<br> \t{<br> \t\t`// if player has room for first aid kit`<br> \t\tif (player canAdd \"FirstAidKit\") then<br> \t\t{<br> \t\t\t `// add first aid kit to the player`<br> \t\t\tplayer addItem \"FirstAidKit\";<br> \t\t}<br> \t\telse<br> \t\t{<br> \t\t\t`// set player's damage to 1/4`<br> \t\t\tplayer setDamage 0.25;<br> \t\t};<br> \t};<br> }; | `// player will need health at this stage of the mission`<br> if (<br> \tdamage player > 0.25 &&<br> \tnot (\"FirstAidKit\" in items player)) then<br> {<br> \tif (player canAdd \"FirstAidKit\") then<br> \t{<br> \t\tplayer addItem \"FirstAidKit\";<br> \t}<br> \telse `// let's help him anyway`<br> \t{<br> \t\tplayer setDamage 0.25;<br> \t};<br> }; |\n| #### Flow Logic examples |  |\n| if (alive player && damage player >= 0.9) then {<br> \thint \"very damaged\";<br> };<br> if (alive player && damage player >= 0.5 && damage player < 0.9) then {<br> \thint \"quite damaged\";<br> };<br> if (alive player && damage player > 0 && damage player < 0.5) then {<br> \thint \"slightly damaged\";<br> };<br> if (alive player && damage player == 0) then {<br> \thint \"pristine state\";<br> };<br> if (not alive player) then {<br> \thint \"dead\";<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n| if (cond1) then<br> {<br> \tif (cond2) then<br> \t{<br> \t\tif (cond3) then<br> \t\t{<br> \t\t\t// hadouken code<br> \t\t}<br> \t\telse { `/* failure 3 */` };<br> \t}<br> \telse { `/* failure 2 */` };<br> }<br> else { `/* failure 1 */` }; | if (!cond1) exitWith { `/* failure 1 */` };<br> if (!cond2) exitWith { `/* failure 2 */` };<br> if (!cond3) exitWith { `/* failure 3 */` };<br> // code |\n| #### Format examples |  |\n| if (not alive player) exitWith<br> { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> case (_playerDamage >= 0.9): {hint \"very damaged\";};<br> case (_playerDamage >= 0.5): {<br> \thint  \"quite damaged\";};<br> case (_playerDamage > 0): { hint \"slightly damaged\"; };<br>   default<br> {<br>    hint \"pristine\";<br>   };<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n\n### Final Words\n\n- Remember: **consistency** is the most important thing!\n- The Arma Discord server and its community can help: [ARMA](https://discord.gg/arma) (channel `1. arma3_scripting`)\n- Learn from others's scripts but do not steal code and pretend it is yours — be a decent human being. Stealing code and its consequences:\n  - It soils your reputation and devaluates your actions once it is found out — and it *always* get found out. DMCA's are filled on Steam every day.\n  - It makes people in the community get less helpful and more reluctant in giving advices. It can also prevent them to *release* an interesting feature!\n- Don't try to obfuscate your code: it is considered rude, especially since you learnt from others.\n  - Obfuscated code only makes it *harder* to get, but does not make it *copy-protected*. If the engine can read it, it can be obtained.\n  - Obfuscated code is also slower on parsing and, depending on the quality of code and obfuscation, on execution too.\n- Do not hesitate to help newcomers even if you do not know the whole topic: both sides will learn from it!\n- Most important of all, have fun!\n\n### See also\n\n- Code Optimisation\n- Code Positivity\n- Mission Optimisation\n- Multiplayer Scripting","sections":[{"heading":"Getting Started","level":3,"markdown":"In the domain of development, any rule is a rule of thumb.\nIf a rule states for example that it is better that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it.\nIf you have a good structure, **do not** change your code to enforce a single arbitrary rule.\nIf you break many of them, you may have to change something; again, this is according to your judgement.\n\nWith that being said, let's go!"},{"heading":"Prerequisites","level":4,"markdown":"- An advanced text editor such as Visual Studio Code or Notepad++ - see Community Tools#Code Edition for useful tools and plugins\n- Some English knowledge, helped if needed by a translator tool such as [Google Translate](https://www.google.com/translate) or [DeepL](https://www.deepl.com/)\n- Access to this wiki is a plus (the Swiss flag is, too)\n- Tutorials/examples (YouTube tutorials, community tutorials, Example Code)\n- Google-Fu (a.k.a search engine skills)\n- Arma Discord server: [ARMA](https://discord.gg/arma), channel `1. arma3_scripting`"},{"heading":"Best Practices","level":3,"markdown":""},{"heading":"Code Format","level":4,"markdown":"- Whatever you do about your code's format, **be consistent**.\n- Choose an indentation format **and stick to it**. There is not especially one indent better than another (*but there sure are terrible ones*), again the important point here being *consistency*.\n  - Common indentation styles are:\n    - [K&R style](https://en.wikipedia.org/wiki/Indentation_style#K&R_style) indenting\n    - [Allman style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style) indenting\n  - Use empty space. Line return, spaces before and after brackets, if this improves readability, use it: space is free.\n  - indent with two/four spaces **or** one tab. Do not mix these.\n  - *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n-  **was** \"useful\" only for editor fields that for no apparent reason refused commands returning a value. You do **not** need it in script files, and don't need it in editor fields anymore **since Arma 3 v2.04**."},{"heading":"Variable Format","level":4,"markdown":"- Name your variables and functions properly: While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being.\n  - Your variable names must have a meaning: variables like **_u** instead of **_uniform** should not exist. **_i** is an accepted iteration variable name (e.g in for loops).\n  - It is recommended to use [camel-case](https://en.wikipedia.org/wiki/Camel_case) your variables; camel-casing (namingLikeThis) your variables and functions make the code naturally more readable, especially for long names.\n- Prefix your public variables and setVariable with your tag in order to avoid any conflict about other mods, scripts or mission variables.\n- Make your variables **private** thanks to the private or params keyword in order to avoid accidental upper-scope overwriting of variables of the same name.\n- Defined constants must be UPPERCASE_WITH_UNDERSCORES (e.g `#define SOME_CONST`)."},{"heading":"Code Structuration","level":4,"markdown":"- **DRY:** **D**on't **R**epeat **Y**ourself. If you write the same code block or the same logic many times, export this code as a function and use parameters with it.\n  - If your code has too many levels, it is time to split and rethink it - maybe using exitWith (e.g `if (a) then { if (b) then { if (c) then { /* etc */  }; }; };`)\n  - Do NOT use macros as functions - these hinder readability. Use functions instead.\n- `// Comments` in your code must not explain *what* the code does, but *why* it is done this way (if needed). Your code organisation combined to your variable names must be enough to be read by a human."},{"heading":"Code/Files Organisation","level":4,"markdown":"- Use CfgFunctions to declare the functions that will be called frequently.\n  - One Functions directory, with sub-directories if needed.\n- Use Event Scripts as needed.\n- Don't put **any code** in a unit's init box *but eventually* local commands for this specific unit - **all** unit's init boxes are run client-side on client connection."},{"heading":"Examples","level":3,"markdown":"| Bad Example | Good Example |\n|---|---|\n| #### Good Practice examples |  |\n| _unit = player; | **private** _unit = player; |\n| private _uB = allUnits select { side _x == blufor }; | private **_bluforUnits** = allUnits select { side _x == blufor }; |\n| private _plead = leader player; | private **_playersLeader** = leader player; |\n| finalAssault = true; publicVariable \"finalAssault\"; | **PREFIX_**finalAssault = true; publicVariable \"**PREFIX_**finalAssault\"; |\n| player setVariable [\"MoneyInPocket\", 250, true]; | player setVariable [\"**PREFIX_**MoneyInPocket\", 250, true]; |\n| #define KILL(UNIT) UNIT setDamage 1<br> // ...<br> {<br> \tKILL(_x);<br> } forEach (units group player - [player]); | private _killFnc = { _this setDamage 1; };<br> // ...<br> {<br> \t_x call _killFnc;<br> } forEach (units group player - [player]); |\n| `// if player has less than 3/4 health`<br> if (damage player > 0.25) then<br> {<br> \t`// if the player has no first aid kit`<br> \tif (not (\"FirstAidKit\" in items player))<br> \t{<br> \t\t`// if player has room for first aid kit`<br> \t\tif (player canAdd \"FirstAidKit\") then<br> \t\t{<br> \t\t\t `// add first aid kit to the player`<br> \t\t\tplayer addItem \"FirstAidKit\";<br> \t\t}<br> \t\telse<br> \t\t{<br> \t\t\t`// set player's damage to 1/4`<br> \t\t\tplayer setDamage 0.25;<br> \t\t};<br> \t};<br> }; | `// player will need health at this stage of the mission`<br> if (<br> \tdamage player > 0.25 &&<br> \tnot (\"FirstAidKit\" in items player)) then<br> {<br> \tif (player canAdd \"FirstAidKit\") then<br> \t{<br> \t\tplayer addItem \"FirstAidKit\";<br> \t}<br> \telse `// let's help him anyway`<br> \t{<br> \t\tplayer setDamage 0.25;<br> \t};<br> }; |\n| #### Flow Logic examples |  |\n| if (alive player && damage player >= 0.9) then {<br> \thint \"very damaged\";<br> };<br> if (alive player && damage player >= 0.5 && damage player < 0.9) then {<br> \thint \"quite damaged\";<br> };<br> if (alive player && damage player > 0 && damage player < 0.5) then {<br> \thint \"slightly damaged\";<br> };<br> if (alive player && damage player == 0) then {<br> \thint \"pristine state\";<br> };<br> if (not alive player) then {<br> \thint \"dead\";<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |\n| if (cond1) then<br> {<br> \tif (cond2) then<br> \t{<br> \t\tif (cond3) then<br> \t\t{<br> \t\t\t// hadouken code<br> \t\t}<br> \t\telse { `/* failure 3 */` };<br> \t}<br> \telse { `/* failure 2 */` };<br> }<br> else { `/* failure 1 */` }; | if (!cond1) exitWith { `/* failure 1 */` };<br> if (!cond2) exitWith { `/* failure 2 */` };<br> if (!cond3) exitWith { `/* failure 3 */` };<br> // code |\n| #### Format examples |  |\n| if (not alive player) exitWith<br> { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> case (_playerDamage >= 0.9): {hint \"very damaged\";};<br> case (_playerDamage >= 0.5): {<br> \thint  \"quite damaged\";};<br> case (_playerDamage > 0): { hint \"slightly damaged\"; };<br>   default<br> {<br>    hint \"pristine\";<br>   };<br> }; | if (not alive player) exitWith { hint \"dead\"; };<br> private _playerDamage = damage player;<br> switch (true) do {<br> \tcase (_playerDamage >= 0.9): { hint \"very damaged\"; };<br> \tcase (_playerDamage >= 0.5): { hint \"quite damaged\"; };<br> \tcase (_playerDamage > 0)   : { hint \"slightly damaged\"; };<br> \tdefault { hint \"pristine\"; };<br> }; |"},{"heading":"Final Words","level":3,"markdown":"- Remember: **consistency** is the most important thing!\n- The Arma Discord server and its community can help: [ARMA](https://discord.gg/arma) (channel `1. arma3_scripting`)\n- Learn from others's scripts but do not steal code and pretend it is yours — be a decent human being. Stealing code and its consequences:\n  - It soils your reputation and devaluates your actions once it is found out — and it *always* get found out. DMCA's are filled on Steam every day.\n  - It makes people in the community get less helpful and more reluctant in giving advices. It can also prevent them to *release* an interesting feature!\n- Don't try to obfuscate your code: it is considered rude, especially since you learnt from others.\n  - Obfuscated code only makes it *harder* to get, but does not make it *copy-protected*. If the engine can read it, it can be obtained.\n  - Obfuscated code is also slower on parsing and, depending on the quality of code and obfuscation, on execution too.\n- Do not hesitate to help newcomers even if you do not know the whole topic: both sides will learn from it!\n- Most important of all, have fun!"},{"heading":"See also","level":3,"markdown":"- Code Optimisation\n- Code Positivity\n- Mission Optimisation\n- Multiplayer Scripting"}],"categories":["Arma Scripting Tutorials"],"groups":["Scripting"]},{"name":"Code Optimisation","title":"Code Optimisation","type":"topic","url":"https://community.bistudio.com/wiki/Code_Optimisation","revid":378687,"updated":"2026-05-26T00:40:51Z","aliases":[],"markdown":"> [!NOTE]\n> This page is about Code Optimisation. For *conception* optimisation, see Mission Optimisation.\n\nThis article will try to be a general guide about improving your code **and** its performance.\n- The first part (Rules) focuses on having a clean, readable and maintainable code.\n- The second part (Code optimisation) is about **improving performance**, sometimes trading it against code readability.\n- The third part (Equivalent commands performance) mentions commands that in appearance have identical effects but may differ in terms of performance according to the use you may have of them.\n- The fourth part (Conversion from earlier versions) is a hopefully helpful, short guide about useful new commands or syntaxes to replace the old ways.\n\n### Rules\n\nIn the domain of development, any rule is a rule of thumb. If a rule states for example that it is *better* that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it. If you have a good structure, **do not** change your code to enforce a single arbitrary rule. If you break many of them, you may have to change something. Again, this is according to your judgement.\n\nWith that being said, here are the three basic rules to get yourself in the clear:\n\n1. Make it work\n1. Make it readable\n1. Optimise then\n\n#### Make It Work\n\n> Premature optimization is the root of all evil.\n\nYour first goal when coding is to make your code do what you want it does. A good way to reach this objective is to read and getting inspired by other people's code. If you understand it by reading it once, it is probably a good source of inspiration.\n\n- When starting from scratch if you know what you want but miss the specific steps to get to your point, it is a good practice to write down in your native language what you want to do. E.g *Get all the units near the city, and for each west soldier in them, add 30% damage*.\n- Use -showScriptErrors startup parameter and **make sure your code doesn't throw errors.** Not only will your code run slower but it may also *not work at all*. Be sure to read the error, isolate the issue and sort it out thanks to this Wiki.\n- Read your Arma RPT (report) to read more details about the error that happened in your code.\n\n#### Make It Readable\n\nWhether you are cleaning your code or a different person's, you must understand the code without twisting your brain:\n\n- While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being. Variables like **_u** instead of **_uniform** should not be present.\n- *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n- Indentation is important for the human mind, and space is too. Space is free, use it.\n- Same goes for line return; it helps to see a code block wrapping multiple common instructions instead of having to guess where it starts and stops.\n- Do you see the same code multiple times, only with different parameters? Now is the time to write a function!\n- If you have a lot of if..else, you may want to look at a switch condition, or again break your code in smaller functions.\n- Is your function code far too long? Break it in understandable-sized bites for your own sanity.\n- Finally, camel-casing (namingLikeThis) your variables will naturally make the code more readable, especially for long names.\n\n> [!NOTE]\n> See **Code Best Practices** for more information.\n\nSee the following code:\n _w=[]; {_w pushbackunique primaryweapon _x} foreach((allunits+alldeadmen) select{_x call BIS_fnc_objectside==east});\n\nThe same example is far more readable with proper spacing, good variable names and intermediate results:\n _weaponNames = [];\n _allUnitsAliveAndDead = allUnits + allDeadMen;\n _allEastAliveAndDead = _allUnitsAliveAndDead select { _x call BIS_fnc_objectSide == east };\n { _weaponNames pushBackUnique primaryWeapon _x } forEach _allEastAliveAndDead;\n\n##### Constants\n\nUsing a hard-coded constant more than once? Use preprocessor directives rather than storing it in memory or cluttering your code with numbers. Such as:\n\n```sqf\na = _x + 1.053;\nb = _y + 1.053;\n```\n\nAnd\n\n```sqf\n_buffer = 1.053;\na = _x + _buffer;\nb = _y + _buffer;\n```\n\nBecomes\n\n```sqf\n#define BUFFER 1.053 // note: no semicolon\n_a = _x + BUFFER;\n_b = _y + BUFFER;\n```\n\n> [!NOTE]\n> Using the `#define` macro only works within the current SQF *file*. Such definition will not propagate anywhere else.\n\n**Global** \"constants\" can be defined via a Description.ext declaration, though, and accessed using getMissionConfigValue command:\n\nDeclaration in Description.ext:\n\n```cpp\nvar1 = 123;\nvar2 = \"123\";\nvar3[] = { 1, 2, 3 };\nrand = __EVAL(random 999);\n```\n\nUsage in code:\n\n```sqf\nhint str getMissionConfigValue \"var1\"; // 123                                    // 0.0007 ms\nhint str getMissionConfigValue \"var2\"; // \"123\"                                    // 0.0008 ms\nhint str getMissionConfigValue \"var3\"; // [1,2,3]                                // 0.0017 ms\nhint str getMissionConfigValue \"rand\"; // constant random, for example 935.038    // 0.0007 ms\n```\n\nThe getMissionConfigValue command searching Description.ext from top to bottom,\nit is better for a matter of performance to put all your definitions at the top of the file.\n\n#### Optimise Then\n\nOnce you know what is what, you can understand your code better.\n- Use private variables instead of global variables (preceded by an underscore) as much as possible.\n- You were iterating multiple times on the same array?\n  - You should be able to spot your issue now.\n- Are you using execVM on the same file, many times?\n  - Store your function in memory to avoid file reading every call ( e.g `_myFunction = compile preprocessFileLineNumbers \"myFile.sqf\";`).\n- Is your variable name far too long?\n  - Find a smaller name, according to the variable scope;e.g:\n\n```sqf\n{ _opforUnitUniform = uniform _x; systemChat _opforUnitUniform; } forEach _allOpforUnits;\n```\n\nbecomes\n\n```sqf\n{ _uniform = uniform _x; systemChat _uniform; } forEach _allOpforUnits;\n```\n\n### Code Optimisation\n\n> [!IMPORTANT]\n> **Please note:** Tests and benchmarks were done with the latest Arma 3 version at the time Arma 3 v1.82 with **Tank DLC**. Game engine performance may have changed since.\n> Benchmark result in milliseconds (ms) is an average for **10000** iterations.\n\n> [!NOTE]\n> ● means you **must** change your ways today, *or with us you will ride…*\n>\n> ● means you may want to look at it if you are targeting pure performance\n>\n> ● means the gain is little to insignificant. Going through your code for this replacement is not worth it. You *may* only consider it for future code.\n\n#### Scheduled and Unscheduled Environment\n\nThere are two code environment types, scheduled and unscheduled.\n- A **scheduled** script has an execution time limit of **3 ms** before being suspended to the benefit of another script until its turn comes back. It is a bit slower than unscheduled, but suspending (sleep, waitUntil) is allowed.\n- An **unscheduled** script is not watched and will run without limitations. It is recommended for time-critical scripts, but suspending (sleep, waitUntil) is **not** allowed!\n\n> [!NOTE]\n> See Scheduler for more information.\n\n#### ● Variable Assignment\n\n```sqf\nprivate _myVar = [33, 66] select false;                                            // 0.0013 ms\nprivate _myVar = if (false) then { 33; } else { 66; };                            // 0.0020 ms\nprivate \"_myVar\"; if (false) then { _myVar = 33; } else { _myVar = 66; };         // 0.0025 ms\n```\n\n#### ● Lazy Evaluation\n\nIn SQF the following code will evaluate every single condition, even if one fails:\n\n```sqf\nif (a && b && c) then {};\n```\n\nEven if `a` returns false (and thus the entire Boolean expression can no longer become true), `b` and `c` will still be executed and evaluated regardless.\n\nTo avoid this behaviour, one can either imbricate if statements or use **lazy evaluation**. The latter is done like so:\n\n```sqf\nif (a && { b && { c } }) then {};\n```\n\nIn the example above, condition evaluation stops once any condition evaluates to false.\n\n##### Influence on Semantics\n\nDepending on the arrangement of the curly brackets, lazy evaluation can change the precedence (and therefore the semantics) of a condition. Consider this example:\n\n| Expression | Condition Value | Evaluated Conditions | Result |  |  |\n|---|---|---|---|---|---|\n| `a` | `b` | `c` |  |  |  |\n| ```sqf<br>a &&  b  \\|\\|  c<br>``` | false | any Boolean | true | `a`, `b`, `c` | true |\n| ```sqf<br>a && {b} \\|\\| {c}<br>``` | `a`, `c` | true |  |  |  |\n| ```sqf<br>a && {b  \\|\\| {c}}<br>``` | `a` | false |  |  |  |\n\n##### Performance\n\nUsing lazy evaluation is not always the best way as it can both speed up and slow down the code, depending on the current condition being evaluated:\n\n```sqf\n[\"true  || { false  || {false}}\", nil, 100000] call BIS_fnc_codePerformance;    // 0.00080 ms\n[\"true  ||  {false} || {false} \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00105 ms\n[\"false ||   false  ||  false  \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00123 ms\n[\"true  ||   false  ||  false  \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00128 ms\n[\"false ||  {false} || {false} \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00200 ms\n```\n\n#### ● Concatenating Strings\n\n`myString = myString + otherString` works fine for small strings, however the bigger the string gets the slower the operation becomes:\n\n```sqf\nmyString = \"\"; for \"_i\" from 1 to 10000 do { myString = myString + \"123\" };        // 290 ms\n```\n\nThe solution is to use a string array that you will concatenate later:\n\n```sqf\nstrings = [];\nfor \"_i\" from 1 to 10000 do { strings pushBack \"123\" };\nstrings = strings joinString \"\";                                                // 30 ms\n```\n\n#### ● Array Manipulation\n\n##### Add Elements\n\nNew commands append and pushBack hold the best score.\n\n```sqf\n_array = [0,1,2,3]; _array append [4,5,6];                                        // 0.0020 ms\n_array = [0,1,2,3]; _array = _array + [4,5,6];                                    // 0.0023 ms\n_array = [0,1,2,3]; { _array set [count _array, _x]; } forEach [4,5,6];            // 0.0080 ms\n```\n\n```sqf\n_array = [0,1,2,3]; _array pushBack 4;                                            // 0.0016 ms\n_array = [0,1,2,3]; _array = _array + [4];                                        // 0.0021 ms\n_array = [0,1,2,3]; _array set [count _array, _x];                                 // 0.0022 ms\n```\n\n##### Iterate Elements\n\n**If _x is not required**, for is twice as fast as forEach - otherwise, use forEach (see results below).\n\n```sqf\nprivate _list = allUnits;                                                                // 64 units                256 units\n\n// if the amount of loops is known\nfor \"_i\" from 0 to 63 do {};                                                            // 0.0120 ms            0.0460 ms\nfor \"_i\" from 0 to count _list -1 do {};                                                // 0.0170 ms            0.0480 ms\nfor \"_i\" from 0 to count _list -1 do { private _x = _list select _i };                    // 0.0500 ms            0.1896 ms <\nfor \"_i\" from 0 to count _list -1 do { private _x = _list select _i; _x setDamage 0 };    // 0.107 ms                0.39 ms\n\n{} forEach _list;                                                                        // 0.0250 ms            0.098 ms\n{ _x setDamage 0 } forEach _list;                                                        // 0.0770 ms            0.312 ms\n\n_list apply {};                                                                            // 0.0250 ms            0.098 ms\n_list apply { _x setDamage 0 };                                                            // 0.0770 ms            0.312 ms\n\nprivate _i = 0;\nwhile { _i < 64 } do { _i = _i + 1; };                                                    // 0.048 ms                0.200 ms\n\n// counts array every loop\nprivate _i = 0;\nwhile { _i < count _list } do { _i = _i + 1; };                                            // 0.062 ms                0.247 ms\n\nprivate _i = 0;\nwhile { _i < 64 } do { private _x = _list select _i; _i = _i + 1; };                    // 0.086 ms                0.42 ms\n```\n\n##### Remove Elements\n\n```sqf\n_array = [0,1,2,3]; _array deleteAt 0;                                                                    // 0.0015 ms\n_array = [0,1,2,3]; _array set [0, objNull]; _array = _array - [objNull];                                // 0.0038 ms\n```\n\n```sqf\n_array = [0,1,2,3]; _array deleteRange [1, 2];                                                            // 0.0018 ms\n_array = [0,1,2,3]; { _array set [_x, objNull] } forEach [1,2]; _array = _array - [objNull];            // 0.0078 ms\n```\n\n#### ● Multiplayer Recommendations\n\n- Do not saturate the network with information: publicVariable or public setVariable shouldn't be used at high frequency, else **everyone's performance experience** is at risk!\n- The server is supposed to have a good CPU and a lot of memory, use it: store functions, run them from it, send only the result to the clients\n- publicVariable and setVariable variable name length impacts network, be sure to send well-named, understandable variables\n(*and not **playerNameBecauseThePlayerIsImportantAndWeNeedToKnowWhoTheyAreAllTheTimeEspeciallyInsideThisImpressiveFunction***)\n- Use, use and use remoteExec & remoteExecCall. Ditch BIS_fnc_MP for good!\n\n> [!NOTE]\n> See Multiplayer Scripting for more information.\n\n### Equivalent Commands Performance\n\n#### ● call\n\ncall without arguments is faster than call with arguments:\n\n```sqf\ncall {};                                // 0.0007 ms\n123 call {};                            // 0.0013 ms\n```\n\nSince the variables defined in the parent scope will be available in the called child scope, it could be possible to speed up the code by avoiding passing arguments all together, for example writing:\n\n```sqf\nplayer addEventHandler [\"HandleDamage\", { call my_fnc_damage }];\n```\n\ninstead of:\n\n```sqf\nplayer addEventHandler [\"HandleDamage\", { _this call my_fnc_damage }];\n```\n\n#### ● execVM and call\n\n> [!IMPORTANT]\n> Using execVM multiple times make the game read the file and recompile it every time.\n>\n> If you use the script more than once, store its code in a variable or better, make it a Function!\n\n```sqf\n// myFile.sqf is an EMPTY file\nprivate _myFunction = compile preprocessFileLineNumbers \"myFile.sqf\"; // compile time is done only once\ncall _myFunction;                // 0.0009 ms\nexecVM \"myFile.sqf\";            // 0.275 ms\n\n// myFile.sqf is BIS_fnc_showRespawnMenu\nprivate _myFunction = compile preprocessFileLineNumbers \"myFile.sqf\"; // compile time is done only once\n[\"close\"] call _myFunction;        // 0.0056 ms\n[\"close\"] execVM \"myFile.sqf\";    // 0.506 ms\n```\n\n#### ● loadFile, preprocessFile and preprocessFileLineNumbers\n\n```sqf\n// myFile.sqf is an empty file\nloadFile \"myFile.sqf\";                    // 0.219 ms\npreprocessFile \"myFile.sqf\";            // 0.353 ms\npreprocessFileLineNumbers \"myFile.sqf\";    // 0.355 ms\n```\n\n```sqf\n// myFile.sqf is BIS_fnc_showRespawnMenu\nloadFile \"myFile.sqf\";                    // 0.3516 ms\npreprocessFile \"myFile.sqf\";            // 2.75 ms\npreprocessFileLineNumbers \"myFile.sqf\"; // 2.73 ms\n```\n\n```sqf\n// myFile.sqf is a missing file\nloadFile \"myFile.sqf\";                    // 0.692 ms\npreprocessFile \"myFile.sqf\";            // 0.6225 ms\npreprocessFileLineNumbers \"myFile.sqf\";    // 0.6225 ms\n```\n\n> [!IMPORTANT]\n> The comparison of loadFile with preprocessFile* is not exactly fair as loadFile doesn't preprocess the file's content.\n>\n> On the other hand, the loaded file cannot contain any `//` or `/* */` comments nor any preprocessor instructions (including debug information like line numbers or file information).\n\n#### ● if\n\n```sqf\nif (condition) then { /* thenCode */ };                                    // 0.0011 ms\nif (condition) exitWith { /* exitCode */ };                                // 0.0014 ms\nif (condition) then { /* thenCode */ } else { /* elseCode */ };            // 0.0015 ms\nif (condition) then [{ /* thenCode */ }, { /* elseCode */ }];            // 0.0016 ms\n```\n\n#### ● if and select\n\nUse `[array] select boolean` instead of the lazy-evaluated if.\n\n```sqf\n_result = [\"false result\", \"true result\"] select true;                    // 0.0011 ms\n_result = if (true) then { \"true result\"; } else { \"false result\"; };    // 0.0017 ms\n```\n\n#### ● if and switch\n\n```sqf\n_result = call {\n    if (false) exitWith {};\n    if (false) exitWith {};\n    if (true)  exitWith {};\n    if (false) exitWith {};\n    if (false) exitWith {};\n};                            // 0.0032 ms\n```\n\n```sqf\n_result = switch (true) do {\n    case (false): {};\n    case (false): {};\n    case (true) : {};\n    case (false): {};\n    case (false): {};\n};                            // 0.0047 ms\n```\n\n#### ● if else and switch\n\n```sqf\n_mode = \"killed\";\n\nswitch _mode do {\n    case \"init\": {};\n    case \"killed\": {};\n    case \"respawned\": {};\n};                            // 0.0019 ms\n```\n\n```sqf\n_mode = \"killed\";\n\nif (_mode == \"init\") then {} else {\n    if (_mode == \"killed\") then {} else {\n        if (_mode == \"respawned\") then {};\n    };\n};                            // 0.0019 ms\n```\n\n#### ● in vs find\n\n```sqf\n// String search\n\"bar\" in \"foobar\"                                    // 0.0008 ms\n\"foobar\" find \"bar\" > -1                            // 0.0012 ms\n```\n\n```sqf\n// array search - case-sensitive\n\"bar\" in [\"foo\", \"Bar\", \"bar\", \"BAR\"];                // 0.0012 ms\n[\"foo\", \"Bar\", \"bar\", \"BAR\"] find \"bar\" > -1;        // 0.0016 ms\n```\n\n#### ● for\n\nThe `for..from..to..do` is twice as fast as its alternative syntax, `for..do`.\n\n```sqf\nfor \"_i\" from 0 to 10 do { /* forCode */ };                                        // 0.015 ms\nfor [{ _i = 0 }, { _i < 100 }, { _i = _i + 1 }] do { /* forCode */ };            // 0.030 ms\n```\n\n#### ● forEach vs count vs findIf\n\nBoth forEach and count commands will step through *all* the array elements and both commands will contain reference to current element with the _x variable.\nHowever, count loop is a little faster than forEach loop, but it does not benefit from the _forEachIndex variable.\n\nAlso, there is a limitation as the code inside count expects Boolean or Nothing while the command itself returns Number.\nThis limitation is very important if you try to replace your forEach by count. If you have to add an extra true/false/nil at the end to make count work, it will be slower than the forEach equivalent.\n\n```sqf\n{ diag_log _x } count   [1,2,3,4,5];                                            // 0.082 ms\n{ diag_log _x } forEach [1,2,3,4,5];                                            // 0.083 ms\n```\n\n```sqf\n// with an empty array\n_someoneIsNear = (allUnits findIf { _x  distance [0,0,0] < 1000 }) != -1;        // 0.0046 ms\n_someoneIsNear = { _x distance [0,0,0] < 1000 } count allUnits > 0;                // 0.0047 ms <\n_someoneIsNear = {\n    if (_x distance [0,0,0] < 1000) exitWith { true };\n    false\n} forEach allUnits;                                                                // 0.0060 ms\n```\n\n```sqf\n// with a 30 items array\n_someoneIsNear = (allUnits findIf { _x  distance [0,0,0] < 1000 }) != -1;        // 0.0275 ms\n_someoneIsNear = { _x distance [0,0,0] < 1000 } count allUnits > 0;                // 0.0645 ms <\n_someoneIsNear = {\n    if (_x distance [0,0,0] < 1000) exitWith { true };\n    false\n} forEach allUnits;                                                                // 0.0390 ms\n```\n\n#### ● findIf\n\nfindIf stops array iteration as soon as the condition is met.\n\n```sqf\n[0,1,2,3,4,5,6,7,8,9] findIf { _x == 2 };                                        // 0.0050 ms\n{ if (_x == 2) exitWith { _forEachIndex; }; } forEach [0,1,2,3,4,5,6,7,8,9];    // 0.0078 ms\n_quantity = { _x == 2 } count [0,1,2,3,4,5,6,7,8,9];                            // 0.0114 ms\n```\n\n#### ● format vs str\n\n```sqf\nstr 33;                // 0.0016 ms\nformat [\"%1\", 33];    // 0.0022 ms\n```\n\n#### ● + vs format vs joinString\n\nnon-String data:\n\n```sqf\n[33, 45, 78] joinString \"\";                // 0.0052 ms - no length limit\nformat [\"%1%2%3\", 33, 45, 78];            // 0.0054 ms - limited to ~8Kb\nstr 33 + str 45 + str 78;                // 0.0059 ms - no length limit\n```\n\nString data:\n\n```sqf\n[\"str1\", \"str2\", \"str3\"] joinString \"\";        // 0.0015 ms - no length limit\nformat [\"%1%2%3\", \"str1\", \"str2\", \"str3\"];    // 0.0015 ms - limited to ~8Kb\n\"str1\" + \"str2\" + \"str3\";                    // 0.0012 ms - no length limit\n```\n\n#### ● private\n\nDirect declaration (`private _var = value`) is faster than declaring *then* assigning the variable.\n\n```sqf\nprivate _a = 1;\nprivate _b = 2;\nprivate _c = 3;\nprivate _d = 4;\n// 0.0023 ms\n```\n\n```sqf\nprivate [\"_a\", \"_b\", \"_c\", \"_d\"];\n_a = 1;\n_b = 2;\n_c = 3;\n_d = 4;\n// 0.0040 ms\n```\n\nHowever, if you have to reuse the same variable in a loop, external declaration is faster.\n\nThe reason behind this is that a declaration in the loop will create, assign and delete the variable in each loop.\n\nAn external declaration creates the variable only once and the loop only assigns the value.\n\n```sqf\nprivate [\"_a\", \"_b\", \"_c\", \"_d\"];\nfor \"_i\" from 1 to 10 do\n{\n    _a = 1; _b = 2; _c = 3; _d = 4;\n};\n// 0.0195 ms\n```\n\n```sqf\nfor \"_i\" from 1 to 10 do\n{\n    private _a = 1; private _b = 2; private _c = 3; private _d = 4;\n};\n// 0.0235 ms\n```\n\n#### ● isNil\n\n```sqf\nisNil \"varName\";                    // 0.0007 ms\nisNil { varName };                    // 0.0012 ms\n```\n\n#### ● isEqualType and typeName\n\nisEqualType is much faster than typeName\n\n```sqf\n\"string\" isEqualType 33;            // 0.0006 ms\ntypeName \"string\" == typeName 33;    // 0.0018 ms\n```\n\n#### ● isEqualTo and count\n\n```sqf\n// with a items array\nallUnits isEqualTo [];                // 0.0040 ms\ncount allUnits == 0;                // 0.0043 ms\n```\n\n#### ● select and param\n\n```sqf\n[1,2,3] select 0;                    // 0.0008 ms\n[1,2,3] param [0];                    // 0.0011 ms\n```\n\n#### ● createSimpleObject vs createVehicle\n\n```sqf\n// createSimpleObject is over 43× faster than createVehicle!\ndeleteVehicle createSimpleObject [\"a3\\structures_f_mark\\vr\\shapes\\vr_shape_01_cube_1m_f.p3d\", [0,0,0]];    // ~0.08 ms\ndeleteVehicle createSimpleObject [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0]];                                // ~3.2 ms\ndeleteVehicle createVehicle [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0], [], 0, \"CAN_COLLIDE\"];                // ~2.7 ms\ndeleteVehicle createVehicle [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0], [], 0, \"NONE\"];                        // ~78 ms\n```\n\n#### ● objectParent and vehicle\n\n```sqf\nisNull objectParent player;            // 0.0013 ms\nvehicle player == player;            // 0.0022 ms\n```\n\n#### ● nearEntities and nearestObjects\n\nnearEntities is much faster than nearestObjects given on range and amount of objects within the given range.\nIf range is over 100 meters it is highly recommended to use nearEntities over nearestObjects.\n\n```sqf\n// tested with a NATO rifle squad amongst solar power plant panels on Altis at coordinates [20762,15837]\ngetPosATL player nearEntities [[\"CAManBase\"], 50];        // 0.0075 ms\nnearestObjects [getPosATL player, [\"CAManBase\"], 50];    // 0.0145 ms\n```\n\n> [!IMPORTANT]\n> nearEntities only searches for alive objects and on-foot soldiers.\n>\n> In-vehicle units, killed units, destroyed vehicles, static objects and buildings will be ignored.\n\n#### ● Global Variables vs Local Variables\n\nIf you need to use global variable repeatedly in a loop, copy its value to local variable and use local variable instead:\n\n```sqf\nSomeGlobalVariable = [123];\nfor \"_i\" from 1 to 100 do\n{\n    SomeGlobalVariable select 0;\n};\n// 0.13 ms\n```\n\nis noticeably slower than\n\n```sqf\nSomeGlobalVariable = [123];\nprivate _var = SomeGlobalVariable;\nfor \"_i\" from 1 to 100 do\n{\n    _var select 0;\n};\n// 0.08 ms\n```\n\n#### ● Config path delimiter\n\n`>>` is slightly faster than `/` when used in config path with configFile or missionConfigFile.\n\n```sqf\nconfigFile >> \"CfgVehicles\";        // 0.0019 ms\nconfigFile  / \"CfgVehicles\";        // 0.0023 ms\n```\n\n> [!NOTE]\n> A config path can be stored in a variable for later use, saving CPU time: `_cfgVehicles = configFile >> \"CfgVehicles\"`.\n\n#### ● getPos* and setPos*\n\n```sqf\ngetPosWorld                            // 0.0015 ms\ngetPosASL                            // 0.0016 ms\ngetPosATL                            // 0.0016 ms\ngetPosASLW                            // 0.0023 ms\ngetPos                                // 0.0030-0.0300 ms; performance depends on where this command is used - see its documentation\nposition                            // same as getPos\ngetPosVisual                        // same as getPos\nvisiblePosition                        // same as getPos\n```\n\n```sqf\nsetPosWorld                            // 0.0060 ms\nsetPosASL                            // 0.0060 ms\nsetPosATL                            // 0.0060 ms\nsetPos                                // 0.0063 ms\nsetPosASLW                            // 0.0068 ms\nsetVehiclePosition                    // 0.0077 ms with \"CAN_COLLIDE\"\n                                    // 0.0390 ms with \"NONE\"\n```\n\n#### ● toLower/toUpper vs toLowerANSI/toUpperANSI\n\n```sqf\n// _myString is a 100 chars \"aAaAaA(…)\" string\ntoLowerANSI _myString;                // 0.0006 ms\ntoLower _myString;                    // 0.0016 ms\n\ntoUpperANSI _myString;                // 0.0006 ms\ntoUpper _myString;                    // 0.0016 ms\n```\n\n### Equivalent Data Structures Performance\n\n#### Key-Value Data Structures\n\n```sqf\nprivate _hashMap = createHashMapFromArray [[\"id\", 123], [\"name\", \"player name\"], [\"unit\", player]]; // since Arma 3 v2.02\nprivate _goodFormat = [[\"id\", \"name\", \"unit\"], [123, \"player name\", player]];\nprivate _slowFormat = [[\"id\", 123], [\"name\", \"player name\"], [\"unit\", player]];\n```\n\n```sqf\nprivate _name = _hashMap get \"name\"; // 0.0018ms\n\n// this takes 0.0038ms:\nprivate _index = _goodFormat select 0 find \"name\"; // loop in engine\nprivate _name = _goodFormat select 1 select _index;\n\n// this takes 0.0116ms:\nprivate _index = _slowFormat findIf { _x select 0 == \"name\" }; // loop in script\nprivate _name = _slowFormat select _index select 1;\n```\n\n> [!NOTE]\n> Database Functions use a slow format.\n\n### Conversion From Earlier Versions\n\nEach iteration of Bohemia games (Operation Flashpoint, Armed Assault, Arma 2, Take On Helicopters, Arma 3) brought their own new commands, especially Arma 2 and Arma 3.\n\nFor that, if you are converting scripts from older versions of the engine, the following aspects should be reviewed.\n\n#### Loops\n\n- forEach loops, depending on the situation, can be replaced by:\n  - apply\n  - count\n  - findIf\n  - select\n\n#### Array Operations\n\n- **Adding an item:** `myArray + [element]` and `myArray set [count myArray, element]` have been replaced by pushBack\n- **Selecting a random item:** BIS_fnc_selectRandom has been replaced by selectRandom\n- **Removing items:** `myArray set [1, objNull]; myArray - [objNull]` has been replaced by deleteAt and deleteRange\n- **Concatenating:** `myArray = myArray + [element]` has been *reinforced* with append: if you don't need the original array to be modified, use +\n- **Comparing:** use isEqualTo instead of BIS_fnc_areEqual\n- **Finding common items:** in forEach loop has been replaced by arrayIntersect\n- **Condition filtering:** forEach can be replaced by select (alternative syntax)\n\n```sqf\nresult = (arrayOfNumbers select { _x % 2 == 0 });    // 1.55 ms\n```\n\n```sqf\nresult = [];\n{\n    if (_x % 2 == 0) then { result pushBack _x; };\n} forEach arrayOfNumbers;                            // 2.57 ms\n```\n\n#### Vector Operations\n\n- BIS_fnc_vectorMultiply has been replaced by vectorMultiply (at least 6x faster)\n- BIS_fnc_vectorDivide too, to an extent (see its page for more information)\n\n```sqf\nprivate _vector = [102, 687, 1543];\nprivate _factor = 53;\n\n_vector vectorMultiply _factor;                    // 0.0028 ms\n[_vector, _factor] call BIS_fnc_vectorMultiply;    // 0.0145 ms\n\n_vector vectorMultiply (1 / _factor);            // 0.003 ms - but beware of 0 divisor\n[_vector, _factor] call BIS_fnc_vectorDivide;    // 0.017 ms\n```\n\n#### String Operations\n\nString manipulation has been simplified with the following commands:\n- alternative syntax for select: `string select index`\n- toArray and toString have been *reinforced* with splitString and joinString\n\n#### Number Operations\n\n- BIS_fnc_linearConversion has been replaced by linearConversion. The command is **9 times faster**.\n- BIS_fnc_selectRandomWeighted has been replaced by selectRandomWeighted. The command is **7 times faster**.\n\n#### Type Comparison\n\n- typeName has been more than *reinforced* with isEqualType.\n\n#### Multiplayer\n\n- BIS_fnc_MP has been replaced by remoteExec and remoteExecCall and internally uses them. Use the engine commands from now on!\n\n> [!NOTE]\n> See also Multiplayer Scripting.\n\n#### Parameters\n\n- BIS_fnc_param has been replaced by param and params. The commands are approximately **14 times** faster. Use them!","sections":[{"heading":null,"level":1,"markdown":"> [!NOTE]\n> This page is about Code Optimisation. For *conception* optimisation, see Mission Optimisation.\n\nThis article will try to be a general guide about improving your code **and** its performance.\n- The first part (Rules) focuses on having a clean, readable and maintainable code.\n- The second part (Code optimisation) is about **improving performance**, sometimes trading it against code readability.\n- The third part (Equivalent commands performance) mentions commands that in appearance have identical effects but may differ in terms of performance according to the use you may have of them.\n- The fourth part (Conversion from earlier versions) is a hopefully helpful, short guide about useful new commands or syntaxes to replace the old ways."},{"heading":"Rules","level":3,"markdown":"In the domain of development, any rule is a rule of thumb. If a rule states for example that it is *better* that a line of code doesn't go over 80 characters, it doesn't mean that any line ***must not*** go over 80 characters; sometimes, the situation needs it. If you have a good structure, **do not** change your code to enforce a single arbitrary rule. If you break many of them, you may have to change something. Again, this is according to your judgement.\n\nWith that being said, here are the three basic rules to get yourself in the clear:\n\n1. Make it work\n1. Make it readable\n1. Optimise then"},{"heading":"Make It Work","level":4,"markdown":"> Premature optimization is the root of all evil.\n\nYour first goal when coding is to make your code do what you want it does. A good way to reach this objective is to read and getting inspired by other people's code. If you understand it by reading it once, it is probably a good source of inspiration.\n\n- When starting from scratch if you know what you want but miss the specific steps to get to your point, it is a good practice to write down in your native language what you want to do. E.g *Get all the units near the city, and for each west soldier in them, add 30% damage*.\n- Use -showScriptErrors startup parameter and **make sure your code doesn't throw errors.** Not only will your code run slower but it may also *not work at all*. Be sure to read the error, isolate the issue and sort it out thanks to this Wiki.\n- Read your Arma RPT (report) to read more details about the error that happened in your code."},{"heading":"Make It Readable","level":4,"markdown":"Whether you are cleaning your code or a different person's, you must understand the code without twisting your brain:\n\n- While SQF *is* (non-noticeably) impacted by variable name length, this should not take precedence on the fact that code must be readable by a human being. Variables like **_u** instead of **_uniform** should not be present.\n- *One-lining* (putting everything in one statement) memory improvement is most of the time not worth the headache it gives when trying to read it. Don't overuse it.\n- Indentation is important for the human mind, and space is too. Space is free, use it.\n- Same goes for line return; it helps to see a code block wrapping multiple common instructions instead of having to guess where it starts and stops.\n- Do you see the same code multiple times, only with different parameters? Now is the time to write a function!\n- If you have a lot of if..else, you may want to look at a switch condition, or again break your code in smaller functions.\n- Is your function code far too long? Break it in understandable-sized bites for your own sanity.\n- Finally, camel-casing (namingLikeThis) your variables will naturally make the code more readable, especially for long names.\n\n> [!NOTE]\n> See **Code Best Practices** for more information.\n\nSee the following code:\n _w=[]; {_w pushbackunique primaryweapon _x} foreach((allunits+alldeadmen) select{_x call BIS_fnc_objectside==east});\n\nThe same example is far more readable with proper spacing, good variable names and intermediate results:\n _weaponNames = [];\n _allUnitsAliveAndDead = allUnits + allDeadMen;\n _allEastAliveAndDead = _allUnitsAliveAndDead select { _x call BIS_fnc_objectSide == east };\n { _weaponNames pushBackUnique primaryWeapon _x } forEach _allEastAliveAndDead;"},{"heading":"Constants","level":5,"markdown":"Using a hard-coded constant more than once? Use preprocessor directives rather than storing it in memory or cluttering your code with numbers. Such as:\n\n```sqf\na = _x + 1.053;\nb = _y + 1.053;\n```\n\nAnd\n\n```sqf\n_buffer = 1.053;\na = _x + _buffer;\nb = _y + _buffer;\n```\n\nBecomes\n\n```sqf\n#define BUFFER 1.053 // note: no semicolon\n_a = _x + BUFFER;\n_b = _y + BUFFER;\n```\n\n> [!NOTE]\n> Using the `#define` macro only works within the current SQF *file*. Such definition will not propagate anywhere else.\n\n**Global** \"constants\" can be defined via a Description.ext declaration, though, and accessed using getMissionConfigValue command:\n\nDeclaration in Description.ext:\n\n```cpp\nvar1 = 123;\nvar2 = \"123\";\nvar3[] = { 1, 2, 3 };\nrand = __EVAL(random 999);\n```\n\nUsage in code:\n\n```sqf\nhint str getMissionConfigValue \"var1\"; // 123                                    // 0.0007 ms\nhint str getMissionConfigValue \"var2\"; // \"123\"                                    // 0.0008 ms\nhint str getMissionConfigValue \"var3\"; // [1,2,3]                                // 0.0017 ms\nhint str getMissionConfigValue \"rand\"; // constant random, for example 935.038    // 0.0007 ms\n```\n\nThe getMissionConfigValue command searching Description.ext from top to bottom,\nit is better for a matter of performance to put all your definitions at the top of the file."},{"heading":"Optimise Then","level":4,"markdown":"Once you know what is what, you can understand your code better.\n- Use private variables instead of global variables (preceded by an underscore) as much as possible.\n- You were iterating multiple times on the same array?\n  - You should be able to spot your issue now.\n- Are you using execVM on the same file, many times?\n  - Store your function in memory to avoid file reading every call ( e.g `_myFunction = compile preprocessFileLineNumbers \"myFile.sqf\";`).\n- Is your variable name far too long?\n  - Find a smaller name, according to the variable scope;e.g:\n\n```sqf\n{ _opforUnitUniform = uniform _x; systemChat _opforUnitUniform; } forEach _allOpforUnits;\n```\n\nbecomes\n\n```sqf\n{ _uniform = uniform _x; systemChat _uniform; } forEach _allOpforUnits;\n```"},{"heading":"Code Optimisation","level":3,"markdown":"> [!IMPORTANT]\n> **Please note:** Tests and benchmarks were done with the latest Arma 3 version at the time Arma 3 v1.82 with **Tank DLC**. Game engine performance may have changed since.\n> Benchmark result in milliseconds (ms) is an average for **10000** iterations.\n\n> [!NOTE]\n> ● means you **must** change your ways today, *or with us you will ride…*\n>\n> ● means you may want to look at it if you are targeting pure performance\n>\n> ● means the gain is little to insignificant. Going through your code for this replacement is not worth it. You *may* only consider it for future code."},{"heading":"Scheduled and Unscheduled Environment","level":4,"markdown":"There are two code environment types, scheduled and unscheduled.\n- A **scheduled** script has an execution time limit of **3 ms** before being suspended to the benefit of another script until its turn comes back. It is a bit slower than unscheduled, but suspending (sleep, waitUntil) is allowed.\n- An **unscheduled** script is not watched and will run without limitations. It is recommended for time-critical scripts, but suspending (sleep, waitUntil) is **not** allowed!\n\n> [!NOTE]\n> See Scheduler for more information."},{"heading":"● Variable Assignment","level":4,"markdown":"```sqf\nprivate _myVar = [33, 66] select false;                                            // 0.0013 ms\nprivate _myVar = if (false) then { 33; } else { 66; };                            // 0.0020 ms\nprivate \"_myVar\"; if (false) then { _myVar = 33; } else { _myVar = 66; };         // 0.0025 ms\n```"},{"heading":"● Lazy Evaluation","level":4,"markdown":"In SQF the following code will evaluate every single condition, even if one fails:\n\n```sqf\nif (a && b && c) then {};\n```\n\nEven if `a` returns false (and thus the entire Boolean expression can no longer become true), `b` and `c` will still be executed and evaluated regardless.\n\nTo avoid this behaviour, one can either imbricate if statements or use **lazy evaluation**. The latter is done like so:\n\n```sqf\nif (a && { b && { c } }) then {};\n```\n\nIn the example above, condition evaluation stops once any condition evaluates to false."},{"heading":"Influence on Semantics","level":5,"markdown":"Depending on the arrangement of the curly brackets, lazy evaluation can change the precedence (and therefore the semantics) of a condition. Consider this example:\n\n| Expression | Condition Value | Evaluated Conditions | Result |  |  |\n|---|---|---|---|---|---|\n| `a` | `b` | `c` |  |  |  |\n| ```sqf<br>a &&  b  \\|\\|  c<br>``` | false | any Boolean | true | `a`, `b`, `c` | true |\n| ```sqf<br>a && {b} \\|\\| {c}<br>``` | `a`, `c` | true |  |  |  |\n| ```sqf<br>a && {b  \\|\\| {c}}<br>``` | `a` | false |  |  |  |"},{"heading":"Performance","level":5,"markdown":"Using lazy evaluation is not always the best way as it can both speed up and slow down the code, depending on the current condition being evaluated:\n\n```sqf\n[\"true  || { false  || {false}}\", nil, 100000] call BIS_fnc_codePerformance;    // 0.00080 ms\n[\"true  ||  {false} || {false} \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00105 ms\n[\"false ||   false  ||  false  \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00123 ms\n[\"true  ||   false  ||  false  \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00128 ms\n[\"false ||  {false} || {false} \", nil, 100000] call BIS_fnc_codePerformance;    // 0.00200 ms\n```"},{"heading":"● Concatenating Strings","level":4,"markdown":"`myString = myString + otherString` works fine for small strings, however the bigger the string gets the slower the operation becomes:\n\n```sqf\nmyString = \"\"; for \"_i\" from 1 to 10000 do { myString = myString + \"123\" };        // 290 ms\n```\n\nThe solution is to use a string array that you will concatenate later:\n\n```sqf\nstrings = [];\nfor \"_i\" from 1 to 10000 do { strings pushBack \"123\" };\nstrings = strings joinString \"\";                                                // 30 ms\n```"},{"heading":"● Array Manipulation","level":4,"markdown":""},{"heading":"Add Elements","level":5,"markdown":"New commands append and pushBack hold the best score.\n\n```sqf\n_array = [0,1,2,3]; _array append [4,5,6];                                        // 0.0020 ms\n_array = [0,1,2,3]; _array = _array + [4,5,6];                                    // 0.0023 ms\n_array = [0,1,2,3]; { _array set [count _array, _x]; } forEach [4,5,6];            // 0.0080 ms\n```\n\n```sqf\n_array = [0,1,2,3]; _array pushBack 4;                                            // 0.0016 ms\n_array = [0,1,2,3]; _array = _array + [4];                                        // 0.0021 ms\n_array = [0,1,2,3]; _array set [count _array, _x];                                 // 0.0022 ms\n```"},{"heading":"Iterate Elements","level":5,"markdown":"**If _x is not required**, for is twice as fast as forEach - otherwise, use forEach (see results below).\n\n```sqf\nprivate _list = allUnits;                                                                // 64 units                256 units\n\n// if the amount of loops is known\nfor \"_i\" from 0 to 63 do {};                                                            // 0.0120 ms            0.0460 ms\nfor \"_i\" from 0 to count _list -1 do {};                                                // 0.0170 ms            0.0480 ms\nfor \"_i\" from 0 to count _list -1 do { private _x = _list select _i };                    // 0.0500 ms            0.1896 ms <\nfor \"_i\" from 0 to count _list -1 do { private _x = _list select _i; _x setDamage 0 };    // 0.107 ms                0.39 ms\n\n{} forEach _list;                                                                        // 0.0250 ms            0.098 ms\n{ _x setDamage 0 } forEach _list;                                                        // 0.0770 ms            0.312 ms\n\n_list apply {};                                                                            // 0.0250 ms            0.098 ms\n_list apply { _x setDamage 0 };                                                            // 0.0770 ms            0.312 ms\n\nprivate _i = 0;\nwhile { _i < 64 } do { _i = _i + 1; };                                                    // 0.048 ms                0.200 ms\n\n// counts array every loop\nprivate _i = 0;\nwhile { _i < count _list } do { _i = _i + 1; };                                            // 0.062 ms                0.247 ms\n\nprivate _i = 0;\nwhile { _i < 64 } do { private _x = _list select _i; _i = _i + 1; };                    // 0.086 ms                0.42 ms\n```"},{"heading":"Remove Elements","level":5,"markdown":"```sqf\n_array = [0,1,2,3]; _array deleteAt 0;                                                                    // 0.0015 ms\n_array = [0,1,2,3]; _array set [0, objNull]; _array = _array - [objNull];                                // 0.0038 ms\n```\n\n```sqf\n_array = [0,1,2,3]; _array deleteRange [1, 2];                                                            // 0.0018 ms\n_array = [0,1,2,3]; { _array set [_x, objNull] } forEach [1,2]; _array = _array - [objNull];            // 0.0078 ms\n```"},{"heading":"● Multiplayer Recommendations","level":4,"markdown":"- Do not saturate the network with information: publicVariable or public setVariable shouldn't be used at high frequency, else **everyone's performance experience** is at risk!\n- The server is supposed to have a good CPU and a lot of memory, use it: store functions, run them from it, send only the result to the clients\n- publicVariable and setVariable variable name length impacts network, be sure to send well-named, understandable variables\n(*and not **playerNameBecauseThePlayerIsImportantAndWeNeedToKnowWhoTheyAreAllTheTimeEspeciallyInsideThisImpressiveFunction***)\n- Use, use and use remoteExec & remoteExecCall. Ditch BIS_fnc_MP for good!\n\n> [!NOTE]\n> See Multiplayer Scripting for more information."},{"heading":"Equivalent Commands Performance","level":3,"markdown":""},{"heading":"● call","level":4,"markdown":"call without arguments is faster than call with arguments:\n\n```sqf\ncall {};                                // 0.0007 ms\n123 call {};                            // 0.0013 ms\n```\n\nSince the variables defined in the parent scope will be available in the called child scope, it could be possible to speed up the code by avoiding passing arguments all together, for example writing:\n\n```sqf\nplayer addEventHandler [\"HandleDamage\", { call my_fnc_damage }];\n```\n\ninstead of:\n\n```sqf\nplayer addEventHandler [\"HandleDamage\", { _this call my_fnc_damage }];\n```"},{"heading":"● execVM and call","level":4,"markdown":"> [!IMPORTANT]\n> Using execVM multiple times make the game read the file and recompile it every time.\n>\n> If you use the script more than once, store its code in a variable or better, make it a Function!\n\n```sqf\n// myFile.sqf is an EMPTY file\nprivate _myFunction = compile preprocessFileLineNumbers \"myFile.sqf\"; // compile time is done only once\ncall _myFunction;                // 0.0009 ms\nexecVM \"myFile.sqf\";            // 0.275 ms\n\n// myFile.sqf is BIS_fnc_showRespawnMenu\nprivate _myFunction = compile preprocessFileLineNumbers \"myFile.sqf\"; // compile time is done only once\n[\"close\"] call _myFunction;        // 0.0056 ms\n[\"close\"] execVM \"myFile.sqf\";    // 0.506 ms\n```"},{"heading":"● loadFile, preprocessFile and preprocessFileLineNumbers","level":4,"markdown":"```sqf\n// myFile.sqf is an empty file\nloadFile \"myFile.sqf\";                    // 0.219 ms\npreprocessFile \"myFile.sqf\";            // 0.353 ms\npreprocessFileLineNumbers \"myFile.sqf\";    // 0.355 ms\n```\n\n```sqf\n// myFile.sqf is BIS_fnc_showRespawnMenu\nloadFile \"myFile.sqf\";                    // 0.3516 ms\npreprocessFile \"myFile.sqf\";            // 2.75 ms\npreprocessFileLineNumbers \"myFile.sqf\"; // 2.73 ms\n```\n\n```sqf\n// myFile.sqf is a missing file\nloadFile \"myFile.sqf\";                    // 0.692 ms\npreprocessFile \"myFile.sqf\";            // 0.6225 ms\npreprocessFileLineNumbers \"myFile.sqf\";    // 0.6225 ms\n```\n\n> [!IMPORTANT]\n> The comparison of loadFile with preprocessFile* is not exactly fair as loadFile doesn't preprocess the file's content.\n>\n> On the other hand, the loaded file cannot contain any `//` or `/* */` comments nor any preprocessor instructions (including debug information like line numbers or file information)."},{"heading":"● if","level":4,"markdown":"```sqf\nif (condition) then { /* thenCode */ };                                    // 0.0011 ms\nif (condition) exitWith { /* exitCode */ };                                // 0.0014 ms\nif (condition) then { /* thenCode */ } else { /* elseCode */ };            // 0.0015 ms\nif (condition) then [{ /* thenCode */ }, { /* elseCode */ }];            // 0.0016 ms\n```"},{"heading":"● if and select","level":4,"markdown":"Use `[array] select boolean` instead of the lazy-evaluated if.\n\n```sqf\n_result = [\"false result\", \"true result\"] select true;                    // 0.0011 ms\n_result = if (true) then { \"true result\"; } else { \"false result\"; };    // 0.0017 ms\n```"},{"heading":"● if and switch","level":4,"markdown":"```sqf\n_result = call {\n    if (false) exitWith {};\n    if (false) exitWith {};\n    if (true)  exitWith {};\n    if (false) exitWith {};\n    if (false) exitWith {};\n};                            // 0.0032 ms\n```\n\n```sqf\n_result = switch (true) do {\n    case (false): {};\n    case (false): {};\n    case (true) : {};\n    case (false): {};\n    case (false): {};\n};                            // 0.0047 ms\n```"},{"heading":"● if else and switch","level":4,"markdown":"```sqf\n_mode = \"killed\";\n\nswitch _mode do {\n    case \"init\": {};\n    case \"killed\": {};\n    case \"respawned\": {};\n};                            // 0.0019 ms\n```\n\n```sqf\n_mode = \"killed\";\n\nif (_mode == \"init\") then {} else {\n    if (_mode == \"killed\") then {} else {\n        if (_mode == \"respawned\") then {};\n    };\n};                            // 0.0019 ms\n```"},{"heading":"● in vs find","level":4,"markdown":"```sqf\n// String search\n\"bar\" in \"foobar\"                                    // 0.0008 ms\n\"foobar\" find \"bar\" > -1                            // 0.0012 ms\n```\n\n```sqf\n// array search - case-sensitive\n\"bar\" in [\"foo\", \"Bar\", \"bar\", \"BAR\"];                // 0.0012 ms\n[\"foo\", \"Bar\", \"bar\", \"BAR\"] find \"bar\" > -1;        // 0.0016 ms\n```"},{"heading":"● for","level":4,"markdown":"The `for..from..to..do` is twice as fast as its alternative syntax, `for..do`.\n\n```sqf\nfor \"_i\" from 0 to 10 do { /* forCode */ };                                        // 0.015 ms\nfor [{ _i = 0 }, { _i < 100 }, { _i = _i + 1 }] do { /* forCode */ };            // 0.030 ms\n```"},{"heading":"● forEach vs count vs findIf","level":4,"markdown":"Both forEach and count commands will step through *all* the array elements and both commands will contain reference to current element with the _x variable.\nHowever, count loop is a little faster than forEach loop, but it does not benefit from the _forEachIndex variable.\n\nAlso, there is a limitation as the code inside count expects Boolean or Nothing while the command itself returns Number.\nThis limitation is very important if you try to replace your forEach by count. If you have to add an extra true/false/nil at the end to make count work, it will be slower than the forEach equivalent.\n\n```sqf\n{ diag_log _x } count   [1,2,3,4,5];                                            // 0.082 ms\n{ diag_log _x } forEach [1,2,3,4,5];                                            // 0.083 ms\n```\n\n```sqf\n// with an empty array\n_someoneIsNear = (allUnits findIf { _x  distance [0,0,0] < 1000 }) != -1;        // 0.0046 ms\n_someoneIsNear = { _x distance [0,0,0] < 1000 } count allUnits > 0;                // 0.0047 ms <\n_someoneIsNear = {\n    if (_x distance [0,0,0] < 1000) exitWith { true };\n    false\n} forEach allUnits;                                                                // 0.0060 ms\n```\n\n```sqf\n// with a 30 items array\n_someoneIsNear = (allUnits findIf { _x  distance [0,0,0] < 1000 }) != -1;        // 0.0275 ms\n_someoneIsNear = { _x distance [0,0,0] < 1000 } count allUnits > 0;                // 0.0645 ms <\n_someoneIsNear = {\n    if (_x distance [0,0,0] < 1000) exitWith { true };\n    false\n} forEach allUnits;                                                                // 0.0390 ms\n```"},{"heading":"● findIf","level":4,"markdown":"findIf stops array iteration as soon as the condition is met.\n\n```sqf\n[0,1,2,3,4,5,6,7,8,9] findIf { _x == 2 };                                        // 0.0050 ms\n{ if (_x == 2) exitWith { _forEachIndex; }; } forEach [0,1,2,3,4,5,6,7,8,9];    // 0.0078 ms\n_quantity = { _x == 2 } count [0,1,2,3,4,5,6,7,8,9];                            // 0.0114 ms\n```"},{"heading":"● format vs str","level":4,"markdown":"```sqf\nstr 33;                // 0.0016 ms\nformat [\"%1\", 33];    // 0.0022 ms\n```"},{"heading":"● + vs format vs joinString","level":4,"markdown":"non-String data:\n\n```sqf\n[33, 45, 78] joinString \"\";                // 0.0052 ms - no length limit\nformat [\"%1%2%3\", 33, 45, 78];            // 0.0054 ms - limited to ~8Kb\nstr 33 + str 45 + str 78;                // 0.0059 ms - no length limit\n```\n\nString data:\n\n```sqf\n[\"str1\", \"str2\", \"str3\"] joinString \"\";        // 0.0015 ms - no length limit\nformat [\"%1%2%3\", \"str1\", \"str2\", \"str3\"];    // 0.0015 ms - limited to ~8Kb\n\"str1\" + \"str2\" + \"str3\";                    // 0.0012 ms - no length limit\n```"},{"heading":"● private","level":4,"markdown":"Direct declaration (`private _var = value`) is faster than declaring *then* assigning the variable.\n\n```sqf\nprivate _a = 1;\nprivate _b = 2;\nprivate _c = 3;\nprivate _d = 4;\n// 0.0023 ms\n```\n\n```sqf\nprivate [\"_a\", \"_b\", \"_c\", \"_d\"];\n_a = 1;\n_b = 2;\n_c = 3;\n_d = 4;\n// 0.0040 ms\n```\n\nHowever, if you have to reuse the same variable in a loop, external declaration is faster.\n\nThe reason behind this is that a declaration in the loop will create, assign and delete the variable in each loop.\n\nAn external declaration creates the variable only once and the loop only assigns the value.\n\n```sqf\nprivate [\"_a\", \"_b\", \"_c\", \"_d\"];\nfor \"_i\" from 1 to 10 do\n{\n    _a = 1; _b = 2; _c = 3; _d = 4;\n};\n// 0.0195 ms\n```\n\n```sqf\nfor \"_i\" from 1 to 10 do\n{\n    private _a = 1; private _b = 2; private _c = 3; private _d = 4;\n};\n// 0.0235 ms\n```"},{"heading":"● isNil","level":4,"markdown":"```sqf\nisNil \"varName\";                    // 0.0007 ms\nisNil { varName };                    // 0.0012 ms\n```"},{"heading":"● isEqualType and typeName","level":4,"markdown":"isEqualType is much faster than typeName\n\n```sqf\n\"string\" isEqualType 33;            // 0.0006 ms\ntypeName \"string\" == typeName 33;    // 0.0018 ms\n```"},{"heading":"● isEqualTo and count","level":4,"markdown":"```sqf\n// with a items array\nallUnits isEqualTo [];                // 0.0040 ms\ncount allUnits == 0;                // 0.0043 ms\n```"},{"heading":"● select and param","level":4,"markdown":"```sqf\n[1,2,3] select 0;                    // 0.0008 ms\n[1,2,3] param [0];                    // 0.0011 ms\n```"},{"heading":"● createSimpleObject vs createVehicle","level":4,"markdown":"```sqf\n// createSimpleObject is over 43× faster than createVehicle!\ndeleteVehicle createSimpleObject [\"a3\\structures_f_mark\\vr\\shapes\\vr_shape_01_cube_1m_f.p3d\", [0,0,0]];    // ~0.08 ms\ndeleteVehicle createSimpleObject [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0]];                                // ~3.2 ms\ndeleteVehicle createVehicle [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0], [], 0, \"CAN_COLLIDE\"];                // ~2.7 ms\ndeleteVehicle createVehicle [\"Land_VR_Shape_01_cube_1m_F\", [0,0,0], [], 0, \"NONE\"];                        // ~78 ms\n```"},{"heading":"● objectParent and vehicle","level":4,"markdown":"```sqf\nisNull objectParent player;            // 0.0013 ms\nvehicle player == player;            // 0.0022 ms\n```"},{"heading":"● nearEntities and nearestObjects","level":4,"markdown":"nearEntities is much faster than nearestObjects given on range and amount of objects within the given range.\nIf range is over 100 meters it is highly recommended to use nearEntities over nearestObjects.\n\n```sqf\n// tested with a NATO rifle squad amongst solar power plant panels on Altis at coordinates [20762,15837]\ngetPosATL player nearEntities [[\"CAManBase\"], 50];        // 0.0075 ms\nnearestObjects [getPosATL player, [\"CAManBase\"], 50];    // 0.0145 ms\n```\n\n> [!IMPORTANT]\n> nearEntities only searches for alive objects and on-foot soldiers.\n>\n> In-vehicle units, killed units, destroyed vehicles, static objects and buildings will be ignored."},{"heading":"● Global Variables vs Local Variables","level":4,"markdown":"If you need to use global variable repeatedly in a loop, copy its value to local variable and use local variable instead:\n\n```sqf\nSomeGlobalVariable = [123];\nfor \"_i\" from 1 to 100 do\n{\n    SomeGlobalVariable select 0;\n};\n// 0.13 ms\n```\n\nis noticeably slower than\n\n```sqf\nSomeGlobalVariable = [123];\nprivate _var = SomeGlobalVariable;\nfor \"_i\" from 1 to 100 do\n{\n    _var select 0;\n};\n// 0.08 ms\n```"},{"heading":"● Config path delimiter","level":4,"markdown":"`>>` is slightly faster than `/` when used in config path with configFile or missionConfigFile.\n\n```sqf\nconfigFile >> \"CfgVehicles\";        // 0.0019 ms\nconfigFile  / \"CfgVehicles\";        // 0.0023 ms\n```\n\n> [!NOTE]\n> A config path can be stored in a variable for later use, saving CPU time: `_cfgVehicles = configFile >> \"CfgVehicles\"`."},{"heading":"● getPos* and setPos*","level":4,"markdown":"```sqf\ngetPosWorld                            // 0.0015 ms\ngetPosASL                            // 0.0016 ms\ngetPosATL                            // 0.0016 ms\ngetPosASLW                            // 0.0023 ms\ngetPos                                // 0.0030-0.0300 ms; performance depends on where this command is used - see its documentation\nposition                            // same as getPos\ngetPosVisual                        // same as getPos\nvisiblePosition                        // same as getPos\n```\n\n```sqf\nsetPosWorld                            // 0.0060 ms\nsetPosASL                            // 0.0060 ms\nsetPosATL                            // 0.0060 ms\nsetPos                                // 0.0063 ms\nsetPosASLW                            // 0.0068 ms\nsetVehiclePosition                    // 0.0077 ms with \"CAN_COLLIDE\"\n                                    // 0.0390 ms with \"NONE\"\n```"},{"heading":"● toLower/toUpper vs toLowerANSI/toUpperANSI","level":4,"markdown":"```sqf\n// _myString is a 100 chars \"aAaAaA(…)\" string\ntoLowerANSI _myString;                // 0.0006 ms\ntoLower _myString;                    // 0.0016 ms\n\ntoUpperANSI _myString;                // 0.0006 ms\ntoUpper _myString;                    // 0.0016 ms\n```"},{"heading":"Equivalent Data Structures Performance","level":3,"markdown":""},{"heading":"Key-Value Data Structures","level":4,"markdown":"```sqf\nprivate _hashMap = createHashMapFromArray [[\"id\", 123], [\"name\", \"player name\"], [\"unit\", player]]; // since Arma 3 v2.02\nprivate _goodFormat = [[\"id\", \"name\", \"unit\"], [123, \"player name\", player]];\nprivate _slowFormat = [[\"id\", 123], [\"name\", \"player name\"], [\"unit\", player]];\n```\n\n```sqf\nprivate _name = _hashMap get \"name\"; // 0.0018ms\n\n// this takes 0.0038ms:\nprivate _index = _goodFormat select 0 find \"name\"; // loop in engine\nprivate _name = _goodFormat select 1 select _index;\n\n// this takes 0.0116ms:\nprivate _index = _slowFormat findIf { _x select 0 == \"name\" }; // loop in script\nprivate _name = _slowFormat select _index select 1;\n```\n\n> [!NOTE]\n> Database Functions use a slow format."},{"heading":"Conversion From Earlier Versions","level":3,"markdown":"Each iteration of Bohemia games (Operation Flashpoint, Armed Assault, Arma 2, Take On Helicopters, Arma 3) brought their own new commands, especially Arma 2 and Arma 3.\n\nFor that, if you are converting scripts from older versions of the engine, the following aspects should be reviewed."},{"heading":"Loops","level":4,"markdown":"- forEach loops, depending on the situation, can be replaced by:\n  - apply\n  - count\n  - findIf\n  - select"},{"heading":"Array Operations","level":4,"markdown":"- **Adding an item:** `myArray + [element]` and `myArray set [count myArray, element]` have been replaced by pushBack\n- **Selecting a random item:** BIS_fnc_selectRandom has been replaced by selectRandom\n- **Removing items:** `myArray set [1, objNull]; myArray - [objNull]` has been replaced by deleteAt and deleteRange\n- **Concatenating:** `myArray = myArray + [element]` has been *reinforced* with append: if you don't need the original array to be modified, use +\n- **Comparing:** use isEqualTo instead of BIS_fnc_areEqual\n- **Finding common items:** in forEach loop has been replaced by arrayIntersect\n- **Condition filtering:** forEach can be replaced by select (alternative syntax)\n\n```sqf\nresult = (arrayOfNumbers select { _x % 2 == 0 });    // 1.55 ms\n```\n\n```sqf\nresult = [];\n{\n    if (_x % 2 == 0) then { result pushBack _x; };\n} forEach arrayOfNumbers;                            // 2.57 ms\n```"},{"heading":"Vector Operations","level":4,"markdown":"- BIS_fnc_vectorMultiply has been replaced by vectorMultiply (at least 6x faster)\n- BIS_fnc_vectorDivide too, to an extent (see its page for more information)\n\n```sqf\nprivate _vector = [102, 687, 1543];\nprivate _factor = 53;\n\n_vector vectorMultiply _factor;                    // 0.0028 ms\n[_vector, _factor] call BIS_fnc_vectorMultiply;    // 0.0145 ms\n\n_vector vectorMultiply (1 / _factor);            // 0.003 ms - but beware of 0 divisor\n[_vector, _factor] call BIS_fnc_vectorDivide;    // 0.017 ms\n```"},{"heading":"String Operations","level":4,"markdown":"String manipulation has been simplified with the following commands:\n- alternative syntax for select: `string select index`\n- toArray and toString have been *reinforced* with splitString and joinString"},{"heading":"Number Operations","level":4,"markdown":"- BIS_fnc_linearConversion has been replaced by linearConversion. The command is **9 times faster**.\n- BIS_fnc_selectRandomWeighted has been replaced by selectRandomWeighted. The command is **7 times faster**."},{"heading":"Type Comparison","level":4,"markdown":"- typeName has been more than *reinforced* with isEqualType."},{"heading":"Multiplayer","level":4,"markdown":"- BIS_fnc_MP has been replaced by remoteExec and remoteExecCall and internally uses them. Use the engine commands from now on!\n\n> [!NOTE]\n> See also Multiplayer Scripting."},{"heading":"Parameters","level":4,"markdown":"- BIS_fnc_param has been replaced by param and params. The commands are approximately **14 times** faster. Use them!"}],"categories":["Arma Scripting Tutorials"],"groups":["Scripting"]},{"name":"Color","title":"Color","type":"topic","url":"https://community.bistudio.com/wiki/Color","revid":376825,"updated":"2025-11-22T11:46:47Z","aliases":[],"markdown":"Color is a format of an Array,\nnamely an Array of Numbers in format `[r, g, b]` or `[r, g, b, a]`, values ranging from 0 to 1.\n\n- **r** is the intensity of **r**ed,\n- **g** is the intensity of **g**reen,\n- **b** is the intensity of **b**lue\n- **a**, if present, is **a**lpha (opacity). An alpha value of 0 means totally transparent and a value of 1 means totally opaque.\n\n> [!NOTE]\n> In config, the color array respects the RGBA format, only it is encapsulated by curly braces:\n>\n> ```cpp\n> myColor[] = { 1, 1, 1, 1 };\n> ```\n\n### Examples\n\n| Colour | SQF Array | HTML | Render |\n|---|---|---|---|\n| Mauve purple | ```sqf<br>[0.3, 0.3, 0.5, 1]<br>``` | ```html<br>#4D4D80<br>``` |  |\n| White | ```sqf<br>[1, 1, 1, 1]<br>``` | ```html<br>#FFFFFF<br>``` |  |\n| Camo green | ```sqf<br>[0, 0.2, 0, 1]<br>``` | ```html<br>#003300<br>``` |  |\n| Rust orange | ```sqf<br>[0.73, 0.24, 011, 1]<br>``` | ```html<br>#BA3D1C<br>``` |  |","sections":[{"heading":null,"level":1,"markdown":"Color is a format of an Array,\nnamely an Array of Numbers in format `[r, g, b]` or `[r, g, b, a]`, values ranging from 0 to 1.\n\n- **r** is the intensity of **r**ed,\n- **g** is the intensity of **g**reen,\n- **b** is the intensity of **b**lue\n- **a**, if present, is **a**lpha (opacity). An alpha value of 0 means totally transparent and a value of 1 means totally opaque.\n\n> [!NOTE]\n> In config, the color array respects the RGBA format, only it is encapsulated by curly braces:\n>\n> ```cpp\n> myColor[] = { 1, 1, 1, 1 };\n> ```"},{"heading":"Examples","level":3,"markdown":"| Colour | SQF Array | HTML | Render |\n|---|---|---|---|\n| Mauve purple | ```sqf<br>[0.3, 0.3, 0.5, 1]<br>``` | ```html<br>#4D4D80<br>``` |  |\n| White | ```sqf<br>[1, 1, 1, 1]<br>``` | ```html<br>#FFFFFF<br>``` |  |\n| Camo green | ```sqf<br>[0, 0.2, 0, 1]<br>``` | ```html<br>#003300<br>``` |  |\n| Rust orange | ```sqf<br>[0.73, 0.24, 011, 1]<br>``` | ```html<br>#BA3D1C<br>``` |  |"}],"categories":["Arrays"],"groups":["Scripting"]},{"name":"Config","title":"Config","type":"topic","url":"https://community.bistudio.com/wiki/Config","revid":26668,"updated":"2006-12-22T01:29:28Z","aliases":[],"markdown":"**Description:**\nConfig file entry.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nConfig file entry.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Control","title":"Control","type":"topic","url":"https://community.bistudio.com/wiki/Control","revid":149017,"updated":"2020-03-10T21:05:08Z","aliases":[],"markdown":"**Description:**\nControl UI object.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance.\n\nMore information can be found on the Arma: GUI Configuration page.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nControl UI object.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance.\n\nMore information can be found on the Arma: GUI Configuration page."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Control Structures","title":"Control Structures","type":"topic","url":"https://community.bistudio.com/wiki/Control_Structures","revid":363911,"updated":"2024-04-25T21:29:06Z","aliases":[],"markdown":"**Control Structures** are statements which are used to control execution flow in the scripts. They are sequences of scripting code which help to control complex procedures. You can use control structures to define code which is only executed under certain conditions or repeated for a couple of times.\n\n***Note for advanced readers:** in the Virtual Reality scripting language control structures are normal scripting commands, with no special handling compared to other commands. This is different from most imperative programming languages (like C), where control statements are implemented in the core language grammar. The \"controlling\" done by them is implemented by accepting code as an argument. The complex control structures like \"while ... do ...\" are implemented using helper types, like While Type.*\n\n### Requirements\n\nTo fully understand this article you should read the following articles:\n\n- Introduction to Arma Scripting\n- Variables\n- Operators\n\n### Conditional Structures\n\n**Conditional structures** help to define code which is only executed under certain circumstances. Often you will write code that depends on the game state, on other code or other conditions.\n\n#### `if`-Statement\n\nThe `if`-statement defines code that is only executed **if** a certain condition is met. The syntax of it looks like that:\n\n if (CONDITION) then `// The round braces are optional`\n {\n \tSTATEMENT;\n \t...\n };\n\n- `CONDITION` is a Boolean statement or variable which returns either `true` or `false`. The code nested in the following block is only executed if the condition is `true`, else ignored.\n- `STATEMENT` is a custom sequence of statements. That may be commands, assignments, control structures etc.\n\n**Example:**\n\n```sqf\nif (_temperature < 0) then\n{\n    hint \"Snow!\";\n};\n```\n\nIn this example, first the value of `_temperature` is checked:\n- If the value is 0 or greater than 0, the nested code is ignored.\n- If the value is less than 0, the command `hint \"Snow!\";` is executed.\n\n##### Alternative Code (else)\n\nYou can also define *alternative* code that is executed, when the condition is *not* `true`.\n\n if (CONDITION) then\n {\n \tSTATEMENT1;\n \t...\n }\n else\n {\n \tSTATEMENT2;\n \t...\n };\n\nAnother way of specifying an alternative code is done by feeding a 2-dimensional Array of Code into the then like this (but this alternative is CPU-heavier):\n\n if (CONDITION) then [{STATEMENT1; ...}, {STATEMENT2; ...}];\n\nIn fact the above syntax with the Array is the only possible syntax as else does nothing else than taking the code to its left and the one to its right and packs them both into an Array of Code which is then fed into the then operator. But using else is just as fine and in most cases better in case of readability of your code.\n\nHere you have a second sequence of statements executed when `CONDITION` is `false`.\n\n##### Conditional assignments\n\n`if..then` structures can also be used to assign conditional values to variables:\n\n```sqf\n_living = if (alive player) then { true } else { false };\n```\n\n##### SQS syntax (deprecated)\n\n> [!WARNING]\n> SQS Syntax is deprecated; SQF Syntax should be used instead.\n\nWithin SQS Syntax the use of goto labels is a way to execute more than one statement within if...then structures.\n\n if (CONDITION) then { goto \"label\" }\n ... some other statements\n #label\n   statement1\n   statement2\n   statement3\n\n**Example 1: (without else)**\n\n```sqs\nif (_temperature < 0) then { goto \"Snow\" }\n; ... some other statements\n\n#Snow\n  hint \"Snow!\"\n  echo \"There is snow!\"\n  variable = text \"Hey. Snow outside.\"\n```\n\n**Example 2: (with else)**\n\n```sqs\nif (_temperature < 0) then { goto \"Snow\" } else { goto \"Sunshine\" }\n; ... some other statements\ngoto \"Continue\"\n#Snow\n  hint \"Snow!\"\n  echo \"There is snow!\"\n  variable = text \"Hey. Snow outside.\"\n  goto \"Continue\"\n\n#Sunshine\n  hint \"No Snow but sunshine!\"\n  echo \"There is no snow!\"\n  variable = text \"Hey. No snow outside.\"\n  goto \"Continue\"\n\n#Continue\n; ...\n```\n\n##### Nested `if`-Statements\n\nSince the `if`-statement is itself a statement, you can also create **nested `if`-statements**.\n\n**Example:**\n\n```sqf\nif (alive player) then\n{\n    if (someAmmo player) then\n    {\n        hint \"The player is alive and has ammo!\";\n    }\n    else\n    {\n        hint \"The player is out of ammo!\";\n    };\n}\nelse\n{\n    hint \"The player is dead!\";\n};\n```\n\n#### `switch`-Statement (Armed Assault v1.00)\n\nIn some cases you may want to check a variable for several values and execute different code depending on the value.\nWith the above knowledge you could just write a sequence of `if`-statements.\n\n```sqf\nif (_color == \"blue\") then\n{\n    hint \"What a nice color\";\n}\nelse\n{\n    if (_color == \"red\") then\n    {\n        hint \"Don't you get aggressive?\";\n    }\n};\n```\n\nThe more values you want to compare, the longer gets this sequence. That is why the simplified `switch`-statement was introduced.\n\nThe `switch`-statement compares a variable against different values:\n\n switch (VARIABLE) do\n {\n \tcase VALUE1:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \tcase VALUE2:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \t...\n };\n\nThe structure compares `VARIABLE` against all given values (`VALUE1`, `VALUE2`, ...). If any of the values matches, the corresponding block of statements is executed.\n\n**Example:**\n\n```sqf\n[switch (_color) do\n{\n    case \"blue\":\n    {\n        hint \"What a nice color\";\n    };\n    case \"red\":\n    {\n        hint \"Don't you get aggressive?\";\n    };\n};\n```\n\n##### `default`-Block\n\nIn some cases you may want to define alternative code that is executed, when none of the values matches. You can write this code in a `default`-Block.\n\n switch (VARIABLE) do\n {\n \tcase VALUE1:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \tcase VALUE2:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \t...\n \tdefault `// No colon behind **default**`\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n };\n\n##### Variable Assignments\n\nSwitch can be used to assign different values to a variable:\n\n```sqf\nprivate _color = switch (side player) do\n{\n    case west: { \"ColorGreen\" };\n    case east: { \"ColorRed\" };\n};\n```\n\n### Loops\n\n**Loops** are used to execute the same code block for a specific or unspecific number of times.\n\n#### `while`-Loop\n\nThis loop repeats the same code block as long as a given Boolean condition is `true`.\n\n while {CONDITION} do `// Note the curly braces`\n {\n \tSTATEMENT;\n \t...\n };\n\n**Description:**\n\n1. `CONDITION` is evaluated. If it is `true`, go on to 2., else skip the block and go on with the code following the loop.\n1. Execution of all nested statements. Go back to 1.\n\nIf `CONDITION` is `false` from the beginning on, the statements within the block of the loop will never be executed.\n\nBecause the test of the while expression takes place before each execution of the loop, a while loop executes zero or more times.\n\n**Example:**\n\n```sqf\nprivate _counter = 0;\n\nwhile { _counter < 10 } do\n{\n    _counter = _counter + 1;\n};\n```\n\n#### `for`-Loop (Armed Assault v1.00)\n\nThe `for`-loop repeats the same code block for a specific number of times.\n\n for [{BEGIN}, {CONDITION}, {STEP}] do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `BEGIN` is a number of statements executed *before* the loop starts\n- `CONDITION` is a Boolean condition evaluated *before* each loop\n- `STEP` is a number of statements executed *after* each loop\n\nThe loop processes as follows:\n\n1. `BEGIN` is executed\n1. `CONDITION` is evaluated. If it is `true`, go on to 3., else skip the block and go on with the code following the loop.\n1. The statements in the code block are executed\n1. `STEP` is executed, go on to 2.\n\nIf `CONDITION` is `false` from the beginning on, the code block will never be executed.\n\n**Example:**\n\n```sqf\nfor [{ _i = 0 }, { _i < 10 }, { _i = _i + 1 }] do // a loop repeating 10 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\nwill display \"0\" then \"1\" then \"2\" then \"3\" then \"4\" then \"5\" then \"6\" then \"7\" then \"8\" then \"9\".\n\n**Description:**\n1. The variable `_i` is set to 0\n1. The condition `_i < 10` is evaluated, which is `true` until `_i` surpasses 9.\n1. The code `player globalChat _i;` is executed\n1. The variable `_i` is incremented by 1, back to step 2.\n\n##### `for`-`from`-`to`-Loop\n\nThere exists an alternate syntax of the `for`-loop, which simplifies the last example a bit.\n\n for \"VARNAME\" from STARTVALUE to ENDVALUE do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `VARNAME` is any name given to the variable used to count the loop\n- `STARTVALUE` is a Number value given to the counter variable before the loop starts\n- `ENDVALUE` is a Number value until which the counter is incremented\n\n> [!IMPORTANT]\n> Note: Unless using a custom step as seen below, ENDVALUE must be greater than STARTVALUE for the loop to execute\n\nThe loop processes as follows:\n\n1. A variable with the name `VARNAME` is initialized with `STARTVALUE`\n1. If `VARNAME` does not exceed `ENDVALUE`, the code block will be executed.\n1. The variable `VARNAME` is incremented by 1\n1. Go back to step 2\n\nThe following example is semantically equal to the last example.\n\n**Example:**\n\n```sqf\nfor \"_i\" from 0 to 9 do // a loop repeating 10 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\n**Description:**\n1. `_i` is set to 0\n1. `player globalChat 0` is executed\n1. `_i` is incremented by 1 => `_i` is now 1\n1. Back to step 2\n\n##### `for`-`from`-`to`-Loop with custom `step`\n\nThe default step to increment the variable in `for`-`from`-`to`-Loops is 1. You can set a custom step though using this syntax:\n\n for \"VARNAME\" from STARTVALUE to ENDVALUE step STEP do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `STEP` is a Number which defines the step by which the variable is incremented every loop\n\n> [!IMPORTANT]\n> Note: Utilizing this method, you can perform loops where VARNAME decrements by using a negative step value combined with a STARTVALUE that is greater than ENDVALUE\n\nThe rest is equal to the above section.\n\n**Example:**\n\n```sqf\nfor \"_i\" from 0 to 9 step 2 do // a loop repeating 5 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\n**Description:**\n\n1. `_i` is set to 0\n1. `player globalChat 0` is executed\n1. `_i` is incremented by 2 => `_i` is now 2\n1. Back to step 2\n\n#### `forEach`-Loop\n\nYou will often use the `forEach`-loop to increment over arrays.\nIt repeats the same code block for every item in an array.\n\n {\n \tSTATEMENT;\n \t...\n } forEach ARRAY;\n\nThe code block is executed exactly `(count ARRAY)` times.\n\nYou may use the magic variable `_x` within the code block, which always references to the current item of the array.\nMagic variable `_foreachindex` contains current index of the _x element in ARRAY.\n\n**Example:**\n\n```sqf\nprivate _array = [unit1, unit2, unit3];\n\n{\n    _x setDamage 1;\n}\nforEach _array;\n```\n\n**Description:**\n1. In the first loop, the statement `unit1 setDamage 1;` is executed\n1. In the second loop, the statement `unit2 setDamage 1;` is executed\n1. In the third loop, the statement `unit3 setDamage 1;` is executed\n\n> [!WARNING]\n> Each iteration will be executed within one frame, even if it consists of multiple instructions. So be aware of large and/or complex code blocks!\n\n### Return Values\n\nControl structures always return the **last expression evaluated** within the structure.\n\n**Example:**\n\n```sqf\nif (myCondition) then { myValueA; } else { myValueB; }; // returns myValueA or myValueB\n```\n\n### See Also\n\n- Command Group: Program Flow\n- Statement\n- Expression","sections":[{"heading":null,"level":1,"markdown":"**Control Structures** are statements which are used to control execution flow in the scripts. They are sequences of scripting code which help to control complex procedures. You can use control structures to define code which is only executed under certain conditions or repeated for a couple of times.\n\n***Note for advanced readers:** in the Virtual Reality scripting language control structures are normal scripting commands, with no special handling compared to other commands. This is different from most imperative programming languages (like C), where control statements are implemented in the core language grammar. The \"controlling\" done by them is implemented by accepting code as an argument. The complex control structures like \"while ... do ...\" are implemented using helper types, like While Type.*"},{"heading":"Requirements","level":3,"markdown":"To fully understand this article you should read the following articles:\n\n- Introduction to Arma Scripting\n- Variables\n- Operators"},{"heading":"Conditional Structures","level":3,"markdown":"**Conditional structures** help to define code which is only executed under certain circumstances. Often you will write code that depends on the game state, on other code or other conditions."},{"heading":"`if`-Statement","level":4,"markdown":"The `if`-statement defines code that is only executed **if** a certain condition is met. The syntax of it looks like that:\n\n if (CONDITION) then `// The round braces are optional`\n {\n \tSTATEMENT;\n \t...\n };\n\n- `CONDITION` is a Boolean statement or variable which returns either `true` or `false`. The code nested in the following block is only executed if the condition is `true`, else ignored.\n- `STATEMENT` is a custom sequence of statements. That may be commands, assignments, control structures etc.\n\n**Example:**\n\n```sqf\nif (_temperature < 0) then\n{\n    hint \"Snow!\";\n};\n```\n\nIn this example, first the value of `_temperature` is checked:\n- If the value is 0 or greater than 0, the nested code is ignored.\n- If the value is less than 0, the command `hint \"Snow!\";` is executed."},{"heading":"Alternative Code (else)","level":5,"markdown":"You can also define *alternative* code that is executed, when the condition is *not* `true`.\n\n if (CONDITION) then\n {\n \tSTATEMENT1;\n \t...\n }\n else\n {\n \tSTATEMENT2;\n \t...\n };\n\nAnother way of specifying an alternative code is done by feeding a 2-dimensional Array of Code into the then like this (but this alternative is CPU-heavier):\n\n if (CONDITION) then [{STATEMENT1; ...}, {STATEMENT2; ...}];\n\nIn fact the above syntax with the Array is the only possible syntax as else does nothing else than taking the code to its left and the one to its right and packs them both into an Array of Code which is then fed into the then operator. But using else is just as fine and in most cases better in case of readability of your code.\n\nHere you have a second sequence of statements executed when `CONDITION` is `false`."},{"heading":"Conditional assignments","level":5,"markdown":"`if..then` structures can also be used to assign conditional values to variables:\n\n```sqf\n_living = if (alive player) then { true } else { false };\n```"},{"heading":"SQS syntax (deprecated)","level":5,"markdown":"> [!WARNING]\n> SQS Syntax is deprecated; SQF Syntax should be used instead.\n\nWithin SQS Syntax the use of goto labels is a way to execute more than one statement within if...then structures.\n\n if (CONDITION) then { goto \"label\" }\n ... some other statements\n #label\n   statement1\n   statement2\n   statement3\n\n**Example 1: (without else)**\n\n```sqs\nif (_temperature < 0) then { goto \"Snow\" }\n; ... some other statements\n\n#Snow\n  hint \"Snow!\"\n  echo \"There is snow!\"\n  variable = text \"Hey. Snow outside.\"\n```\n\n**Example 2: (with else)**\n\n```sqs\nif (_temperature < 0) then { goto \"Snow\" } else { goto \"Sunshine\" }\n; ... some other statements\ngoto \"Continue\"\n#Snow\n  hint \"Snow!\"\n  echo \"There is snow!\"\n  variable = text \"Hey. Snow outside.\"\n  goto \"Continue\"\n\n#Sunshine\n  hint \"No Snow but sunshine!\"\n  echo \"There is no snow!\"\n  variable = text \"Hey. No snow outside.\"\n  goto \"Continue\"\n\n#Continue\n; ...\n```"},{"heading":"Nested `if`-Statements","level":5,"markdown":"Since the `if`-statement is itself a statement, you can also create **nested `if`-statements**.\n\n**Example:**\n\n```sqf\nif (alive player) then\n{\n    if (someAmmo player) then\n    {\n        hint \"The player is alive and has ammo!\";\n    }\n    else\n    {\n        hint \"The player is out of ammo!\";\n    };\n}\nelse\n{\n    hint \"The player is dead!\";\n};\n```"},{"heading":"`switch`-Statement (Armed Assault v1.00)","level":4,"markdown":"In some cases you may want to check a variable for several values and execute different code depending on the value.\nWith the above knowledge you could just write a sequence of `if`-statements.\n\n```sqf\nif (_color == \"blue\") then\n{\n    hint \"What a nice color\";\n}\nelse\n{\n    if (_color == \"red\") then\n    {\n        hint \"Don't you get aggressive?\";\n    }\n};\n```\n\nThe more values you want to compare, the longer gets this sequence. That is why the simplified `switch`-statement was introduced.\n\nThe `switch`-statement compares a variable against different values:\n\n switch (VARIABLE) do\n {\n \tcase VALUE1:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \tcase VALUE2:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \t...\n };\n\nThe structure compares `VARIABLE` against all given values (`VALUE1`, `VALUE2`, ...). If any of the values matches, the corresponding block of statements is executed.\n\n**Example:**\n\n```sqf\n[switch (_color) do\n{\n    case \"blue\":\n    {\n        hint \"What a nice color\";\n    };\n    case \"red\":\n    {\n        hint \"Don't you get aggressive?\";\n    };\n};\n```"},{"heading":"`default`-Block","level":5,"markdown":"In some cases you may want to define alternative code that is executed, when none of the values matches. You can write this code in a `default`-Block.\n\n switch (VARIABLE) do\n {\n \tcase VALUE1:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \tcase VALUE2:\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n \t...\n \tdefault `// No colon behind **default**`\n \t{\n \t\tSTATEMENT;\n \t\t...\n \t};\n };"},{"heading":"Variable Assignments","level":5,"markdown":"Switch can be used to assign different values to a variable:\n\n```sqf\nprivate _color = switch (side player) do\n{\n    case west: { \"ColorGreen\" };\n    case east: { \"ColorRed\" };\n};\n```"},{"heading":"Loops","level":3,"markdown":"**Loops** are used to execute the same code block for a specific or unspecific number of times."},{"heading":"`while`-Loop","level":4,"markdown":"This loop repeats the same code block as long as a given Boolean condition is `true`.\n\n while {CONDITION} do `// Note the curly braces`\n {\n \tSTATEMENT;\n \t...\n };\n\n**Description:**\n\n1. `CONDITION` is evaluated. If it is `true`, go on to 2., else skip the block and go on with the code following the loop.\n1. Execution of all nested statements. Go back to 1.\n\nIf `CONDITION` is `false` from the beginning on, the statements within the block of the loop will never be executed.\n\nBecause the test of the while expression takes place before each execution of the loop, a while loop executes zero or more times.\n\n**Example:**\n\n```sqf\nprivate _counter = 0;\n\nwhile { _counter < 10 } do\n{\n    _counter = _counter + 1;\n};\n```"},{"heading":"`for`-Loop (Armed Assault v1.00)","level":4,"markdown":"The `for`-loop repeats the same code block for a specific number of times.\n\n for [{BEGIN}, {CONDITION}, {STEP}] do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `BEGIN` is a number of statements executed *before* the loop starts\n- `CONDITION` is a Boolean condition evaluated *before* each loop\n- `STEP` is a number of statements executed *after* each loop\n\nThe loop processes as follows:\n\n1. `BEGIN` is executed\n1. `CONDITION` is evaluated. If it is `true`, go on to 3., else skip the block and go on with the code following the loop.\n1. The statements in the code block are executed\n1. `STEP` is executed, go on to 2.\n\nIf `CONDITION` is `false` from the beginning on, the code block will never be executed.\n\n**Example:**\n\n```sqf\nfor [{ _i = 0 }, { _i < 10 }, { _i = _i + 1 }] do // a loop repeating 10 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\nwill display \"0\" then \"1\" then \"2\" then \"3\" then \"4\" then \"5\" then \"6\" then \"7\" then \"8\" then \"9\".\n\n**Description:**\n1. The variable `_i` is set to 0\n1. The condition `_i < 10` is evaluated, which is `true` until `_i` surpasses 9.\n1. The code `player globalChat _i;` is executed\n1. The variable `_i` is incremented by 1, back to step 2."},{"heading":"`for`-`from`-`to`-Loop","level":5,"markdown":"There exists an alternate syntax of the `for`-loop, which simplifies the last example a bit.\n\n for \"VARNAME\" from STARTVALUE to ENDVALUE do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `VARNAME` is any name given to the variable used to count the loop\n- `STARTVALUE` is a Number value given to the counter variable before the loop starts\n- `ENDVALUE` is a Number value until which the counter is incremented\n\n> [!IMPORTANT]\n> Note: Unless using a custom step as seen below, ENDVALUE must be greater than STARTVALUE for the loop to execute\n\nThe loop processes as follows:\n\n1. A variable with the name `VARNAME` is initialized with `STARTVALUE`\n1. If `VARNAME` does not exceed `ENDVALUE`, the code block will be executed.\n1. The variable `VARNAME` is incremented by 1\n1. Go back to step 2\n\nThe following example is semantically equal to the last example.\n\n**Example:**\n\n```sqf\nfor \"_i\" from 0 to 9 do // a loop repeating 10 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\n**Description:**\n1. `_i` is set to 0\n1. `player globalChat 0` is executed\n1. `_i` is incremented by 1 => `_i` is now 1\n1. Back to step 2"},{"heading":"`for`-`from`-`to`-Loop with custom `step`","level":5,"markdown":"The default step to increment the variable in `for`-`from`-`to`-Loops is 1. You can set a custom step though using this syntax:\n\n for \"VARNAME\" from STARTVALUE to ENDVALUE step STEP do\n {\n \tSTATEMENT;\n \t...\n };\n\n- `STEP` is a Number which defines the step by which the variable is incremented every loop\n\n> [!IMPORTANT]\n> Note: Utilizing this method, you can perform loops where VARNAME decrements by using a negative step value combined with a STARTVALUE that is greater than ENDVALUE\n\nThe rest is equal to the above section.\n\n**Example:**\n\n```sqf\nfor \"_i\" from 0 to 9 step 2 do // a loop repeating 5 times\n{\n    player globalChat format [\"%1\", _i];\n};\n```\n\n**Description:**\n\n1. `_i` is set to 0\n1. `player globalChat 0` is executed\n1. `_i` is incremented by 2 => `_i` is now 2\n1. Back to step 2"},{"heading":"`forEach`-Loop","level":4,"markdown":"You will often use the `forEach`-loop to increment over arrays.\nIt repeats the same code block for every item in an array.\n\n {\n \tSTATEMENT;\n \t...\n } forEach ARRAY;\n\nThe code block is executed exactly `(count ARRAY)` times.\n\nYou may use the magic variable `_x` within the code block, which always references to the current item of the array.\nMagic variable `_foreachindex` contains current index of the _x element in ARRAY.\n\n**Example:**\n\n```sqf\nprivate _array = [unit1, unit2, unit3];\n\n{\n    _x setDamage 1;\n}\nforEach _array;\n```\n\n**Description:**\n1. In the first loop, the statement `unit1 setDamage 1;` is executed\n1. In the second loop, the statement `unit2 setDamage 1;` is executed\n1. In the third loop, the statement `unit3 setDamage 1;` is executed\n\n> [!WARNING]\n> Each iteration will be executed within one frame, even if it consists of multiple instructions. So be aware of large and/or complex code blocks!"},{"heading":"Return Values","level":3,"markdown":"Control structures always return the **last expression evaluated** within the structure.\n\n**Example:**\n\n```sqf\nif (myCondition) then { myValueA; } else { myValueB; }; // returns myValueA or myValueB\n```"},{"heading":"See Also","level":3,"markdown":"- Command Group: Program Flow\n- Statement\n- Expression"}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"Description.ext","title":"Description.ext","type":"topic","url":"https://community.bistudio.com/wiki/Description.ext","revid":378503,"updated":"2026-04-29T15:54:18Z","aliases":["Arma 3 CfgCommands","Arma 3: CfgCommands","CfgCommands","CfgSounds","EXT","desc.ext","description.ext","disableAI (description.ext)"],"markdown":"The Description.ext file is a missionConfigFile and is used to set the overall mission attributes or to define global properties that will be available for other scripts.\nIt is placed in the mission root folder and uses the same syntax as the config.cpp file, but supports only a limited number of config classes.\n\nAdditionally, many attributes can also be set via the Eden Editor, where changes are automatically refreshed upon scenario preview.\nIn the 2D Editor the mission has to be reloaded for changes to be applied.\n\n> [!NOTE]\n> This file is required in Operation Flashpoint: Elite for MP missions to work, otherwise a **-1 error** is shown.\n\n> [!NOTE]\n> This page is about the **Mission Description.ext**. For the campaign version, see Campaign Description.ext.\n\n> [!WARNING]\n> The keyword `class` for class definitions **must** be lowercase, otherwise a parsing error will occur.\n\n> [!IMPORTANT]\n> Accidentally creating this file with a wrong file extension is a frequent cause of issues.\n> If you are unfamiliar with script file creation, read Introduction to Arma Scripting#File Creation for a step-by-step tutorial.\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 v2.02, it is possible to import a class from main config and inherit from it in mission config:\n>\n> ```cpp\n> import RscText;\n> class MyText : RscText\n> {\n>     // ...\n> };\n> ```\n>\n> For more information, see the import (Config) page.\n\n### Mission Information\n\nThis section helps you find out how to customise Mission overall external appearance, from Mission Overview to Loading Screens.\n\n**Loading screen parameters**\n\n```cpp\nauthor            = \"Varanon\";\nonLoadName        = \"Point Insertion\";\nonLoadMission    = \"A group of NATO soldiers is tasked with sabotaging a coastal defense.\";\nloadScreen        = \"images\\loadScreen.paa\";\n\nclass Header\n{\n    gameType = \"Coop\";    // game type\n    minPlayers =  1;    // minimum number of players the mission supports\n    maxPlayers = 10;    // maximum number of players the mission supports\n};\n```\n\n> [!NOTE]\n> Header's `playerCountMultipleOf` entry is available in earlier titles (from Operation Flashpoint: Elite to Arma 3 1.30), allowing to setup the auto-assign team balancing factor: 1 for Coop, 2 for Versus.\n\n##### author (Arma 3 v0.50)\n\nMission author's name. The default loading screen shows this string below the #onLoadName in a smaller font prefixed by \"by \".\n\n##### onLoadName (Arma 3 v0.50)\n\nString (usually mission name) shown during mission loading. The string is shown in a slightly larger font above the loadScreen.\nThe #onLoadMission text is placed below the load screen and the header gameType determines the game type on top of the box.\n\n##### onLoadMission\n\nDisplays a message while the mission is loading. Note that a mission that takes very little time to load will only display the message for a short time.\nIn **OFP** this is the name you see when selecting a mission in MP and also the name that is presented to the Multiplayer browser.\n\n```cpp\nonLoadMission = \"YourMissionName\";\n```\n\n##### loadScreen (Arma 2: Operation Arrowhead v1.50)\n\nThe picture to be shown while the mission is loaded. The path is relative to the mission folder. Must be in PAA file format.\n2:1 aspect ratio (different aspect are rendered correctly as well, but won't cover the whole area).\nIdeally 1024x512 pixels.\n\n```cpp\nloadScreen = \"pictures\\intro.paa\";\n```\n\n##### header (Armed Assault v1.00)\n\nThis class defines mission type and other settings displayed in the multiplayer browser.\n\n```cpp\nclass Header\n{\n    gameType = \"CTF\";    // Game type\n    minPlayers =  1;    // minimum number of players the mission supports\n    maxPlayers = 10;    // maximum number of players the mission supports\n};\n```\n\nSee Multiplayer Game Types for more detailed information.\n\n##### onLoadIntro\n\nDisplays a message while the intro is loading.\n\n```cpp\nonLoadIntro = \"YourMessage\";\n```\n\n##### onLoadMissionTime\n\nDefine whether you will see the time and date displayed while the mission loads. Effect unkown in Arma 3.\n\n```cpp\nonLoadMissionTime = 1; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### onLoadIntroTime\n\nDefine whether you will see the time and date displayed while the intro loads.\n\n```cpp\nonLoadIntroTime = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### briefingName (Arma 3 v1.56)\n\nMission name displayed in the mission selection menu.\n\n```cpp\nbriefingName = \"TAG 1-5 CO My super mission\";\n```\n\n> [!IMPORTANT]\n> Please note that the same parameter can be defined in 3DEN in Attributes->General->Presentation->Title, but 'briefingName' from 'description.ext' has a priority. To use localized string either in 3DEN field or in 'description.ext', prefix stringtable ID with `@`.\n\n##### CfgLoadingTexts (Take On Helicopters v1.00)\n\nDefine mission specific loading texts.\n\n##### overviewPicture (Arma 3 v0.50)\n\nPath to image which will be displayed when the mission is highlighted on the mission selection screen. Image should be .paa format and in 2:1 aspect ratio – ideally 1024×512 (Arma 3).\n\n##### overviewText (Arma 3 v0.50)\n\nText to be displayed below the #overviewPicture on the mission selection screen when the mission is available to play.\n\n> [!IMPORTANT]\n> Please note that the same parameter can be defined in 3DEN in Attributes->General->Overview->Text, but 'overviewText' from 'description.ext' has a priority. To use localized string either in 3DEN field or in 'description.ext', prefix stringtable ID with `@`.\n\n> [!IMPORTANT]\n> The text that appears at the top of an MP mission is defined in **mod** mission definition and **not** through Description.ext:\n>\n> ```cpp\n> class Mission\n> {\n>     // ...\n>     class Intel\n>     {\n>         overviewText = \"This text here\";\n>         // ...\n>     };\n>     // ...\n> };\n> ```\n\n##### overviewTextLocked (Arma 3 v0.50)\n\nText to be displayed below the #overviewPicture on the mission selection screen when the mission is locked from play.\n\n> [!IMPORTANT]\n> Please note that to use localized string prefix stringtable ID with `@`.\n\n##### onBriefingGear\n\nDefines a sound (defined in #CfgSounds) that will play when accessing the gear part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingGear = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3.\n\n##### onBriefingGroup\n\nDefines a sound (defined in #CfgSounds) that will play when accessing the group part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingGroup = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3.\n\n##### onBriefingPlan\n\nDefines a sound (defined in #CfgSounds) that will play when accessing the plan part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingPlan = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3.\n\n##### CfgWorlds (Arma 3 v2.02)\n\nCould be used to override the following properties used on mission loading: author, description, pictureMap, pictureShot, loadingTexts[].\nIf a specific world name given as a subclass, override will happen only when this world is loading. If subclass with name Any is used, then aforementioned properties would be overridden for any world that is loading.\n\n```cpp\nclass CfgWorlds\n{\n    class Any // or specific world name\n    {\n        author = \"author\";\n        description = \"description\";\n        pictureMap = \"picturepath\";\n        pictureShot = \"picturepath\";\n        loadingTexts[] = { \"text1\", \"text2\", \"text3\" };\n    };\n};\n```\n\n### Respawn/Revive\n\nThis section talks about respawn and revive actions.\n- for Arma 2, see First Aid.\n- for Arma 3, see Arma 3: Respawn and Arma 3: Revive.\n\n|  |  |  |\n|---|---|---|\n| + Respawn types |  |  |\n| ID | Text version | Description |\n| **0** | **\"NONE\"** | No respawn |\n| **1** | **\"BIRD\"** | Respawn as a seagull |\n| **2** | **\"INSTANT\"** | Respawn just where you died. |\n| **3** | **\"BASE\"** | Respawn in base.<br>A respawn marker is needed. If no marker is defined, respawn behaviour will be the same as **\"INSTANT\"**.<br>Marker role names:<br>- Unit respawn: *respawn_**SIDE***<br>- Vehicle respawn: *respawn_vehicle_**SIDE***<br>Side can be one of *west*, *east*, *guerrila* (sic), *civilian*, e.g **respawn_west**.<br>Any suffix (eg: respawn_west**ABC**, respawn_west**_1**, etc) will allow multiple random respawn points. |\n| **4** | **\"GROUP\"** | Respawn in your group. If there is no remaining AI, you will become a seagull. |\n| **5** | **\"SIDE\"** | Armed Assault v1.08 Respawn into an AI unit on your side (if there's no AI left, you'll become a seagull).<br>With this respawn type, team switch is also available to any AI controlled playable units. |\n\n##### respawn\n\nSets soldiers and vehicles respawn type.\n\n```cpp\nrespawn = 0;        // Default: 0 for SP, 1 for MP\nrespawn = \"SIDE\";    // text version works too\n```\n\n##### respawnVehicle (Arma 3 v2.18)\n\nSets vehicles only respawn type. Vehicles can only have 2 (or \"INSTANT\") and 3 (or \"BASE\") respawn mode. All other modes are equal to disabled respawn. If 'respawnVehicle' is not defined, the 'respawn' value is used.\n\n```cpp\nrespawnVehicle = 3;            // number version\nrespawnVehicle = \"BASE\";    // text version works too\n```\n\n##### respawnButton\n\nEnable or disable the respawn button in the menu for INSTANT and BASE respawn types.\n\n```cpp\nrespawnButton = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### respawnDelay\n\nSet respawn delay in seconds.\n\n```cpp\nrespawnDelay = 42; // Default: ?\n```\n\n##### respawnVehicleDelay\n\nSet vehicle respawn delay in seconds.\n\n```cpp\nrespawnVehicleDelay = 12; // Default: ?\n```\n\n##### respawnDialog\n\nShow the scoreboard and respawn countdown timer for a player if he is killed with respawn type **3**.\n\n```cpp\nrespawnDialog = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### respawnOnStart\n\nRespawn player when he joins the game. Available only for INSTANT and BASE respawn types.\n\n```cpp\nrespawnOnStart = 1; // Default: 0\n```\n\n- -1 - Dont respawn on start. Don't run respawn script on start.\n-  0 - Dont respawn on start. Run respawn script on start.\n-  1 - Respawn on start. Run respawn script on start.\n\n##### respawnTemplates\n\nRespawn templates from CfgRespawnTemplates. You can combine any number of them together.\n\n```cpp\nrespawnTemplates[] = { \"Counter\", \"Wave\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn templates can be specified with *respawnTemplates***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> When such is undefined, general respawnTemplates are used instead.\n\n##### respawnWeapons (Armed Assault v1.00)\n\nSet weapons players will receive upon respawn. #respawnMagazines has to be defined as well.\n\n```cpp\nrespawnWeapons[] = { \"arifle_Katiba_GL_F\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn weapons can be specified with *respawnWeapons***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> Corresponding *respawnMagazines***SIDE***[]* has to be defined as well.\n\n##### respawnMagazines (Armed Assault v1.00)\n\nSet magazines players will receive upon respawn. #respawnWeapons has to be defined as well.\n\n```cpp\nrespawnMagazines[] = { \"30Rnd_65x39_caseless_green\", \"30Rnd_65x39_caseless_green\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn weapons can be specified with *respawnMagazines***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> Corresponding *respawnWeapons***SIDE***[]* has to be defined as well.\n\n##### reviveMode (Arma 3 v1.62)\n\nDefine if Revive mode is enabled.\n\n```cpp\nreviveMode = 1; // Default: 0\n```\n\n- 0 - disabled\n- 1 - enabled\n- 2 - controlled by player attributes\n\n##### reviveUnconsciousStateMode (Arma 3 v1.62)\n\nDefine revive mode.\n\n```cpp\nreviveUnconsciousStateMode = 0; // Default: 0\n```\n\n- 0 - basic mode\n- 1 - advanced mode\n- 2 - realistic\nSee damage model for more detailed information.\n\n##### reviveRequiredTrait (Arma 3 v1.62)\n\nDefine if only a medic (or unit with medic trait) can perform a revive.\n\n```cpp\nreviveRequiredTrait = 0; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### reviveRequiredItems (Arma 3 v1.62)\n\nDefine if a medical item (first aid kit or medkit) is required to begin a revive process.\n\n```cpp\nreviveRequiredItems = 2; // Default: ?\n```\n\n- 0 - none\n- 1 - medkit\n- 2 - medkit or first aid kit\n\n##### reviveRequiredItemsFakConsumed (Arma 3 v1.62)\n\nDefine if a first aid kit is consumed on reviving a teammate\n\n```cpp\nreviveRequiredItemsFakConsumed = 1; // 0: disabled - 1: enabled. Default: ?\n```\n\n##### reviveMedicSpeedMultiplier (Arma 3 v1.62)\n\nSpeed multiplier for revive performed by medic\n\n```cpp\nreviveMedicSpeedMultiplier = 2; // medic revive will be two times faster compared to another soldier\n```\n\n##### reviveDelay (Arma 3 v1.62)\n\nThe time in seconds it takes to revive an incapacitated unit. Having a Medikit will halve this time.\n\n```cpp\nreviveDelay = 10; // Default: 6\n```\n\n##### reviveForceRespawnDelay (Arma 3 v1.62)\n\nThe time in seconds it takes for an incapacitated unit to force their respawn.\n\n```cpp\nreviveForceRespawnDelay = 5; // Default: 3\n```\n\n##### reviveBleedOutDelay (Arma 3 v1.62)\n\nThe time in seconds it takes for a unit to bleed out.\n\n```cpp\nreviveBleedOutDelay = 300; // Default: 120\n```\n\n##### enablePlayerAddRespawn (Arma 3 v1.62)\n\nUsage unsure, may be related to respawn template **MenuPosition**.\n\n```cpp\nenablePlayerAddRespawn = 0; // Disable framework respawn\n```\n\n##### CfgRespawnInventory (Arma 3 v1.62)\n\nThis class defines a respawn inventory, used with **MenuInventory** respawn template.\nLoadouts with no assigned role are automatically assigned to the \"Default\" role.\n\nSee also BIS_fnc_addRespawnInventory, BIS_fnc_removeRespawnInventory\n\n```cpp\nclass CfgRespawnInventory\n{\n    class Blufor1\n    {\n        displayName = \"Light\";                                    // Name visible in the menu\n        icon = \"\\A3\\Ui_f\\data\\GUI\\Cfg\\Ranks\\sergeant_gs.paa\";    // Icon displayed next to the name\n        role = \"Assault\";                                        // Optional, see CfgRoles\n\n        // Loadout definition, uses same entries as CfgVehicles classes\n        weapons[] =\n        {\n            \"arifle_MXC_F\",\n            \"Binocular\"\n        };\n\n        magazines[] =\n        {\n            \"30Rnd_65x39_caseless_mag\",\n            \"30Rnd_65x39_caseless_mag\",\n            \"SmokeShell\"\n        };\n\n        items[] =\n        {\n            \"FirstAidKit\"\n        };\n\n        linkedItems[] =\n        {\n            \"V_Chestrig_khk\",\n            \"H_Watchcap_blk\",\n            \"optic_Aco\",\n            \"acc_flashlight\",\n            \"ItemMap\",\n            \"ItemCompass\",\n            \"ItemWatch\",\n            \"ItemRadio\"\n        };\n\n        uniformClass = \"U_B_CombatUniform_mcam_tshirt\";\n        backpack = \"B_AssaultPack_mcamo\";\n    };\n\n    class Blufor2\n    {\n        // Alternative configuration pointing to a CfgVehicles class. Loadout will be copied from it.\n        vehicle = \"B_soldier_AR_F\";\n    };\n};\n```\n\n##### CfgRespawnTemplates (Arma 3 v1.62)\n\nThis class defines new respawn templates to be used with respawn templates.\n\n```cpp\nclass CfgRespawnTemplates\n{\n    // class used in respawnTemplates entry\n    class myTag_beacon\n    {\n        // function or script executed upon death\n        // parameters passed into it are the same as are passed into onPlayerKilled.sqf file\n        onPlayerKilled = \"\\myAddon\\scripts\\respawnBeacon.sqf\";\n\n        // function or script executed upon respawn\n        // parameters passed into it are the same as are passed into onPlayerRespawn.sqf file\n        onPlayerRespawn = \"\\myAddon\\scripts\\respawnBeacon.sqf\";\n\n        // default respawn delay\n        // can be overwitten by description.ext attribute of the same name\n        respawnDelay = 20;\n\n        // see respawnOnStart for description and limitations\n        // can be overridden by description.ext attribute of the same name\n        respawnOnStart = 1;\n    };\n\n    class Spectator\n    {\n        onPlayerRespawn = \"BIS_fnc_respawnSpectator\"; // a function can be used instead of a script\n    };\n};\n```\n\n##### CfgRoles (Arma 3 v1.62)\n\nThis class defines Respawn roles. The main purpose of Roles is to make things clearer and simpler for player when selecting a loadout. All the loadouts available in a mission are now divided into various roles.\nMission designer can use roles already created in the game config, or custom roles can be defined in description.ext file. Loadouts with no role assigned are automatically assigned to the *Default* role.\n\n```cpp\n// all default roles with icons\nclass CfgRoles\n{\n    class Assault\n    {\n        displayName = \"$STR_A3_Role_Assault\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\assault_ca.paa\";\n    };\n\n    class Support\n    {\n        displayName = \"$STR_A3_Role_Support\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\support_ca.paa\";\n    };\n\n    class Recon\n    {\n        displayName = \"$STR_A3_Role_Recon\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\recon_ca.paa\";\n    };\n};\n```\n\n### Mission Keys\n\nMission keys are used to lock/unlock certain missions until you completed other ones. It can also be used in mission to know which missions you finished.\n\nActivated keys can be found in user profile (e.g documents\\*username.Arma3profile*) under *activeKeys* section.\n\nSee also commands activateKey, isKeyActive and deActivateKey for more detailed information.\n\n> [!IMPORTANT]\n> Please note that unlike other text items, stringtable translations ($STR_*) cannot be used.\n\n##### keys (Armed Assault v1.00)\n\nList of keys from which #keysLimit counts the *done* ones.\n\n```cpp\nkeys[] = { \"key1\", \"key2\", \"key3\" };\n```\n\n##### keysLimit (Armed Assault v1.00)\n\nNumber of keys from the #keys list needed *done* to unlock (and be able to play) this mission.\n\n```cpp\nkeysLimit = 2;\n```\n\n##### doneKeys (Armed Assault v1.00)\n\nName of keys marked *done* on mission completion.\n\n```cpp\ndoneKeys[] = { \"key4\" };\n```\n\n### Player's UI\n\nThis section explains HUD customisation possibilities.\n\nSee also commands:\n- showCompass, shownCompass, visibleCompass\n- showGPS, shownGPS, visibleGPS\n- showHUD, shownHUD\n- showWatch, shownWatch, visibleWatch\n- showUAVFeed, shownUAVFeed Arma 3 v1.16\n- showPad, shownPad Operation Flashpoint v1.00\n\n##### overrideFeedback (Arma 3 v1.98)\n\nSome of the feedback effects in Arma 3 are scripted and executed by `functions_f\\feedback\\fn_feedbackMain.fsm`. Those include being hit, pulsation, dirt from explosion, choking etc.\nAdding `overrideFeedback` with value > 0 will stop feedback FSM from executing, allowing mission/mod makers to script their own, custom effects. The param is first checked in the mission config and then mod config.\nIf mission config has this param set to 0, it will force default feedback handling without possibility to override it by mods. Do not set this param unless you are planning to enforce feedback one way or another.\n\n```cpp\noverrideFeedback = 1; // 0: force default handling, 1+: allow custom handling. Default: not set\n```\n\n##### showHUD\n\nEnables/Disables the following IGUI elements:\n- Vehicle and unit info\n- Radar and tactical display\n- Vehicle compass\n- Tank direction indicator\n- Commanding menu\n- Group info bar\n- HUD weapon cursors\n- Vehicle display panels\n- Kill messages\n- 3D Icons visibility\n\n```cpp\nshowHUD = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nThe effect of using the above **showHUD** param is different from the effects of showHUD scripting command, both methods are rather complementary to each other.\n\nSince Arma 3 v1.50 **showHUD** param can be an array to allow control over separate HUD elements, for example:\n\n```cpp\nshowHUD[] =\n{\n    1,    // Scripted HUD (same as showHUD command)\n    1,    // Vehicle and unit info\n    0,    // Vehicle radar [HIDDEN]\n    0,    // Vehicle compass [HIDDEN]\n    1,    // Tank direction indicator\n    1,    // Commanding menu\n    1,    // Group info bar\n    1,    // HUD weapon cursors\n    1,    // Vehicle display panels\n    1,    // \"x killed by y\" systemChat messages\n    1    // force show drawIcon3D icons\n};\n```\n\n> [!IMPORTANT]\n> Using the **showHUD[]** array parameter will disable the showHUD command entirely.\n\n##### showCompass\n\nDefines if the compass is visible.\n\n```cpp\nshowCompass = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showGPS\n\nEnables/Disables the GPS.\n\n```cpp\nshowGPS = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nIn Armed Assault *1.04* toggle this option to disable the mini map attached to the GPS.\n\n##### showGroupIndicator (Arma 3 v1.00)\n\nChanges default GPS mini map into a radar like display that indicates group members relative position to the player.\n\n```cpp\nshowGroupIndicator = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n> [!IMPORTANT]\n> Has no effect since custom panels were introduced in Arma 3. See BIS_fnc_groupIndicator.\n\n##### showMap\n\nDefines if the map is shown after the mission starts.\n\n```cpp\nshowMap = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showNotePad (Armed Assault v1.00)\n\nIn Armed Assault, defines if the NotePad is shown after the mission starts.\n\n```cpp\nshowNotePad = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showPad (Operation Flashpoint v1.00)\n\nDefines if the NotePad is shown after the mission starts. **Only in OFP:CWC**.\n\n```cpp\nshowPad = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showWatch\n\nDefines if the watch is visible.\n\n```cpp\nshowWatch = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showUAVFeed (Arma 3 v1.16)\n\nEnables/Disables the UAV Feed.\n\n```cpp\nshowUAVFeed = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### showSquadRadar (Arma 3 v1.60)\n\nDefines if the Squad Radar is visible.\n\n```cpp\nshowSquadRadar = 0; // 0: disabled - 1: enabled. Default: 0\n```\n\n> [!IMPORTANT]\n> Has no effect since custom panels were introduced in Arma 3.\n\n##### overrideHazeQuality (Arma 3 v2.16)\n\n0/1/2 - VeryLow/Low/Standard - Forces haze quality and in MP has priority over the server 'overrideHazeQuality' option. Standard(2) - mod config driven. Default(-1) - do not force.\n\n```cpp\noverrideHazeQuality = 1; // Low\n```\n\n### Starting Gear\n\nStarting gear points to briefing-available equipment. For respawn equipment, see #Respawn/Revive.\n\nSee also Weapon Pool Commands for more detailed information about weapon pool system.\n\n##### weapons\n\nSet weapons available to players during the briefing.\n\n```cpp\nclass Weapons\n{\n    class AK74        { count = 8; };\n    class RPG7V        { count = 2; };\n    class Binocular    { count = 2; };\n};\n```\n\n##### magazines\n\nSet magazines available to players during the briefing.\n\n```cpp\nclass Magazines\n{\n    class 30Rnd_545x39_AK    { count = 32; };\n    class PG7V                { count =  6; };\n    class HandGrenade        { count = 16; };\n};\n```\n\n##### backpacks (Arma 2: Operation Arrowhead v1.50)\n\nSet backpacks available to players during the briefing.\n\n```cpp\nclass Backpacks\n{\n    class US_Patrol_Pack_EP1    { count = 4; };\n    class US_Assault_Pack_EP1    { count = 4; };\n};\n```\n\n##### allowSubordinatesTakeWeapons (Arma 2: Operation Arrowhead v1.56)\n\nAllows subordinates (i.e., not leaders) to equip items defined in #weapons, #magazines and #backpacks.\n\n```cpp\nallowSubordinatesTakeWeapons = 1; // 0: disabled - 1: enabled. Default: ?\n```\n\n##### arsenalRestrictedItems (Arma 3 v1.98)\n\nUsed to blacklist undesired Arsenal equipment, which prevents user saved loadout from being loaded if it contains restricted items.\n\n```cpp\narsenalRestrictedItems[] = { \"U_B_Soldier_VR\" };\n```\n\n##### allowProfileGlasses (Arma 3 v2.04)\n\nWhen set to 0 will stop glasses set in player profile from being added to player's gear:\n\n```cpp\nallowProfileGlasses = 0;\n```\n\n### Corpse and Wreck Management\n\nThis section explains how to use game-included **garbage collector** (**GC**) for better performances.\n\nSee also addToRemainsCollector, isInRemainsCollector and removeFromRemainsCollector commands.\n\nThe Remains Collector, if enabled, runs at background on every client and clears mission of corpses and wrecks depending on set params and mode.\nIndividual objects can be added or removed from collector monitoring. Items in remains collector are sorted depending on how valuable they are.\nThe most valuable items are pushed to the end of remains array and will be deleted last if possible; for example, the flag carrier is never deleted while it has the flag.\n\n##### corpseManagerMode (Arma 3 v1.32)\n\nSets the mode for automatic corpse removal.\n\n```cpp\ncorpseManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the units are automatically managed by the manager\n- 1 = All - All units are automatically managed by the manager\n- 2 = None_But_Respawned - Only units that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All units are automatically managed by the manager with the exception of respawned ones (opposite to mode 2)\n\n##### corpseLimit (Arma 3 v0.50)\n\nIf the total number of monitored corpses is higher than **corpseLimit**, the corpses that have been dead for longer than #corpseRemovalMinTime will be considered for removal.\n\n```cpp\ncorpseLimit = 1; // Default: 15\n```\n\n##### corpseRemovalMinTime (Arma 3 v0.50)\n\nSee #corpseLimit above.\n\n```cpp\ncorpseRemovalMinTime = 60; // seconds. Default: 10\n```\n\n##### corpseRemovalMaxTime (Arma 3 v0.50)\n\nMonitored corpses that are dead for longer than **corpseRemovalMaxTime** will be considered for removal regardless of the #corpseLimit.\n\n```cpp\ncorpseRemovalMaxTime = 1200; // seconds. Default: 3600\n```\n\n##### disposalCheckPeriod (Arma 3 v2.18)\n\nHow often the remains collector checks monitored remains for removal. The value can be between 1 and 60.\n\n```cpp\ndisposalCheckPeriod = 30; // seconds. Default: 10\n```\n\n##### minPlayerDistance (Arma 3 v1.66)\n\nThis value applies for monitored corpses, wrecks and weaponholders. The minimum distance between remains and the nearest player before the remains are allowed to be removed by the remains collector.\nThe remains closer than minimum distance to nearest player will not be removed until distance increases. If 'minPlayerDistance' is set to 0, the distance check is not performed.\n\n```cpp\nminPlayerDistance = 50; // meters. Default: 0\n```\n\nArma 3 v2.18 The array variant allows setting individual minPlayerDistance for corpses, wrecks and weaponholders:\n\n```cpp\nminPlayerDistance[] = { 50, 60, 70 }; // metres. Default: { 0, 0, 0 }\n```\n\nArma 3 v2.20 The array supports override times now, format `{ corpsesMinDist, wrecksMinDist, weaponholdersMinDist, corpsesOverrideTime, wrecksOverrideTime, weaponholdersOverrideTime }`\nOverride times are \"force-remove after\" times. For example a corpse is scheduled for deletion but cannot be deleted because a player is nearby.\nIf override time is set, the corpse will be deleted regardless of player proximity.\nSo if for example #removalMaxTime is 3600 and override time is 300, the remains will be definitely deleted within 3600 + 300 = 3900 seconds even if a player is close by.\n\n```cpp\nminPlayerDistance[] = { // metres. Default: { 0, 0, 0, -1, -1, -1 }\n    50,        60,        70,        // corpsesMinDist,        wrecksMinDist,        weaponholdersMinDist\n    300,    120,    60        // corpsesOverrideTime,    wrecksOverrideTime,    weaponholdersOverrideTime\n};\n```\n\n##### weaponholderManagerMode (Arma 3 v2.18)\n\nSets the mode for automatic weapon holder removal.\n\n```cpp\nweaponholderManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the weapon holders are automatically managed by the manager\n- 1 = All - All weapon holders are automatically managed by the manager\n- 2 = None_But_Respawned - Only weapon holders from units that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All weapon holders are automatically managed by the manager with the exception of the ones from respawned units (opposite to mode 2)\n\n> [!NOTE]\n> WeaponHolderSimulated which is created after unit is dead and contains unit's weapon is not managed by the collector, but linked to the corpse and will be deleted when corpse is deleted. WeaponHolderSimulated that is created manually is managed by the collector just like GroundWeaponHolder\n\n##### weaponholderLimit (Arma 3 v2.18)\n\nIf the total number of monitored weapon holders is higher than **weaponholderLimit**, the weapon holders that exist for longer than #weaponholderRemovalMinTime will be considered for removal.\n\n```cpp\nweaponholderLimit = 1; // Default: 50\n```\n\n##### weaponholderRemovalMinTime (Arma 3 v2.18)\n\nSee #weaponholderLimit above.\n\n```cpp\nweaponholderRemovalMinTime = 60; // seconds. Default: 3600\n```\n\n##### weaponholderRemovalMaxTime (Arma 3 v2.18)\n\nMonitored weapon holders that exist for longer than **weaponholderRemovalMaxTime** will be considered for removal regardless of the #weaponholderLimit.\n\n```cpp\nweaponholderRemovalMaxTime = 1200; // seconds. Default: 36000\n```\n\n##### wreckManagerMode (Arma 3 v1.32)\n\nSets the mode for automatic wreck removal.\n\n```cpp\nwreckManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the vehicles are automatically managed by the manager\n- 1 = All - All vehicles are automatically managed by the manager\n- 2 = None_But_Respawned - Only vehicles that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All vehicles are automatically managed by the manager with exception of respawned (opposite to mode 2)\n\n##### wreckLimit (Arma 3 v0.50)\n\nIf the total number of monitored wrecks is higher than **wreckLimit**, the wrecks that existed for longer than #wreckRemovalMinTime will be considered for removal.\n\n```cpp\nwreckLimit = 1; // seconds. Default: 15\n```\n\n##### wreckRemovalMinTime (Arma 3 v0.50)\n\nSee #wreckLimit above.\n\n```cpp\nwreckRemovalMinTime = 60; // seconds. Default: 10\n```\n\n##### wreckRemovalMaxTime (Arma 3 v0.50)\n\nMonitored wrecks that existed for longer than **wreckRemovalMaxTime** will be considered for removal regardless of the #wreckLimit.\n\n```cpp\nwreckRemovalMaxTime = 1800; // seconds. Default: 36000 (10 hours)\n```\n\n### Mission Parameters\n\nMission parameters allow you to add settings to your creation. These settings are in-game accessible only in Multiplayer mode, but can also be accessed by commands for a scripted use in Singleplayer mode.\n\nSee Mission Parameters, along with BIS_fnc_getParamValue function (paramsArray usage is **not** recommended).\n\n##### param1/param2 (Operation Flashpoint v1.00)\n\n**param1** and **param2** are multiplayer options that can be seen in the multiplayer lobby.\nThey can be useful for setting time limits and score limits in such games as Capture the Flag and Death Matches.\nOther popular uses include time acceleration, setting the mission difficulty or switching the intro on/off.\n\nIn the mission, variables **param1** and **param2** have the corresponding values of the chosen options.\n\n> [!IMPORTANT]\n> - While **param1**/**param2** were introduced in **OFP** and can still be used in later titles, it is **highly recommended** to use config class #Params, available since Arma 2 v1.03.\n> - **param1**/**param2** variables can be overridden during the mission as they are **not** read-only.\n\n```cpp\ntitleParam1 = \"Time limit:\";\nvaluesParam1[] = { 0, 300, 600, 900 };\ndefValueParam1 = 900;\ntextsParam1[] = { \"Unlimited\", \"5 min\", \"10 min\", \"15 min\" };\n\ntitleParam2 = \"Score to win:\";\nvaluesParam2[] = { 10000, 5, 7, 10, 15, 20, 25, 30 };\ndefValueParam2 = 5;\ntextsParam2[] = { \"Unlimited\", 5, 7, 10, 15, 20, 25, 30 };\n```\n\nExample:\n\n```sqf\nhint format [\"param1 = %1\\nparam2 = %2\", param1, param2];\n```\n\n##### Params (Arma 2 v1.03)\n\nThese are Multiplayer parameters, available in the lobby by the server administrator.\nThey are intended as a replacement for #param1/param2.\n\n```cpp\nclass Params\n{\n    class ViewDistance\n    {\n        // Visible name in lobby settings list\n        title = \"View distance\";\n\n        // must be integers - commas e.g 1.5 are not allowed\n        values[] = { 500, 1000, 2000, 5000 };\n\n        // Description of each selectable item - must have the same number of items as 'values'\n        // If texts are missing, the values will be displayed instead\n        texts[] = { \"500m\", \"1000m\", \"2 km\", \"5 km\" };\n\n        // must be listed in 'values' array, otherwise 0 is used. If not integer, fallback value is 1\n        default = 1000;\n\n        // (optional) script file called when player joins, selected value is passed as an argument\n        file = \"setViewDistance.sqf\";\n    };\n};\n```\n\nSee Mission Parameters for more detailed information.\n\n### Mission Settings\n\nThese are non-editable, mission maker design settings.\nThey can be used for a smoother experience, briefing/debriefing behaviour, saving options, etc.\n\nSee also Debriefing for more detailed information.\n\n##### aiKills\n\nEnables AI units score to appear in score table.\n\n```cpp\naiKills = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### briefing\n\nSkip briefing screen for SP missions. If no briefing.html is present, it is skipped anyway.\n\n```cpp\nbriefing = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nBriefing will still be displayed until all clients are connected and done loading.\n\n##### debriefing\n\nDefines if the debriefing is shown or not at the end of the mission.\n\n```cpp\ndebriefing = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### CfgDebriefing (Arma 3 v0.50)\n\nDefine custom mission endings or override the default endings (found under CfgDebriefing in the game's config file).\n\n```cpp\nclass CfgDebriefing\n{\n    // Used when all players die in MP\n    class endDeath\n    {\n        title = \"Both teams have died.\";\n        description = \"Everyone was killed by the bomb.\";\n        picture = \"KIA\";\n    };\n};\n```\n\n**For a detailed description, see Arma 3: Debriefing.**\n\n##### CfgDebriefingSections (Arma 3 v0.50)\n\nDefine custom sections to be displayed on the debriefing screen. Useful for custom scoring systems or displaying player achievements.\n\n```cpp\nclass CfgDebriefingSections\n{\n    class bPoints\n    {\n        title = \"Blufor Points\";\n        variable = \"BLU_P\";\n    };\n\n    class oPoints\n    {\n        title = \"Opfor Points\";\n        variable = \"OPF_P\";\n    };\n};\n```\n\n##### DifficultyOverride (Arma 3 v2.16)\n\nAllow to override a difficulty setting for the mission only.\n\nAt the moment, only `tacticalPing` is supported.\n\n```cpp\nclass DifficultyOverride\n{\n    tacticalPing = 0; // disables tactical ping in this mission, even if selected difficulty preset has it enabled\n}\n```\n\n|  |  |  |  |\n|---|---|---|---|\n| + Channel ID number command correspondence |  |  |  |\n| Name | ID | Radio | Chat |\n| Global | 0 | globalRadio | globalChat |\n| Side | 1 | sideRadio | sideChat |\n| Command | 2 | commandRadio | commandChat |\n| Group | 3 | groupRadio | groupChat |\n| Vehicle | 4 | vehicleRadio | vehicleChat |\n| Direct | 5 | directSay | N/A |\n| System | 6 Arma 2: Operation Arrowhead v1.62<br>16 Arma 3 v0.50 | N/A | systemChat |\n\n##### disableChannels (Arma 2: Operation Arrowhead v1.62)\n\nDisable global, side, command or system chat. MOTD and admin say have exception and will show in global.\n\n> [!NOTE]\n> - This setting is not considered when hosting from Eden Editor.\n> - A mission using **disableChannels** will override any `disableChannels[]` value in server config.\n\n> [!NOTE]\n> **Arma 3:** See enableChannel.\n\nArma 2: Operation Arrowhead v1.62 **basic syntax**:\n\n```cpp\ndisableChannels[] = { 0, 3 }; // simple channel ID list\n```\n\nArma 3 v1.60 **advanced syntax**:\n\n```cpp\ndisableChannels[] =\n{\n    {\n        0,        // channel ID\n        false,    // text chat remains enabled\n        true,    // voice chat is disabled\n        false,    // allow placing map markers (Optional, default false - added in v2.20)\n        true    // disable drawing on map (Optional, default false - added in v2.20)\n    },\n    { 3, true, true }\n};\n```\n\n##### disabledAI\n\nMultiplayer setting that removes all playable units which do not have a human player.\n\nWhen AI is disabled, a player logging out will **not** have AI take control of his character.\n\n> [!IMPORTANT]\n> Disabling AI units will prevent JIP into playable units if **respawn** is disabled.\n\n```cpp\ndisabledAI = 1; // 0: AIs fill empty slots - 1: AIs are disabled, only players can spawn. Default: 0\n```\n\n##### disableRandomization (Arma 3 v1.42)\n\nDisables randomisation on certain objects, object types or object kinds in the mission. For more information visit: Arma 3: Vehicle Customisation\n\n```cpp\ndisableRandomization[] = { \"All\", \"AllVehicles\", \"B_G_Offroad_01_F\", \"myCar\", \"MyUnitName\", \"B_Soldier_F\" };\n```\n\nNote: This takes higher priority and will override the following:\n\n```sqf\n_vehicle setVariable [\"BIS_enableRandomization\", true]; // cannot enable for all or specific vehicles once disabled in description.ext\n```\n\n##### enableDebugConsole (Arma 3 v0.50)\n\nAllows access to the Debug Console in multiplayer scenarios outside of the editor. This has no effect for singleplayer scenarios.\n\nSince Arma 3 v2.18 also makes the console available in singleplayer scenarios.\n\n```cpp\nenableDebugConsole = 2; // dangerous in MP\n```\n\n- 0 - Default behavior, available only in editor\n- 1 - Available in SP and for hosts / logged in admins\n- 2 - Available for everyone\n\nAlternative since Arma 3 v1.72\n\n```cpp\nenableDebugConsole[] = { \"76561198XXXXXXXXX\", \"76561198YYYYYYYYY\", }; // admins and players with their UID in this list have access\n```\n\n##### enableItemsDropping (Arma 2: Operation Arrowhead v1.62)\n\nDisable dropping items while swimming. Introduced in Arma 2: Operation Arrowhead BETA 1.60.93965. Doesn't seem to have any effect in Arma 3.\n\n```cpp\nenableItemsDropping = 0; // 0: disabled - 1: enabled. Default: ?\n```\n\n##### enableTeamSwitch\n\nEnables or disables Team Switch functionality in MP when respawn type is 5 (SIDE).\n\n```cpp\nenableTeamSwitch = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### forceRotorLibSimulation (Arma 3 v1.34)\n\nForce enable or disable RotorLib flight model.\n\n```cpp\nforceRotorLibSimulation = 1; // Default: 0\n```\n\n- 0 - based on player's options\n- 1 - enabled (advanced mode)\n- 2 - disabled (default flight mode)\n\n##### hostDoesNotSkipLobby (Arma 3 v2.06)\n\nStops hosting player from skipping the lobby if  is used\n\n```cpp\nhostDoesNotSkipLobby = 1;\n```\n\n##### joinUnassigned (Arma 3 v0.50)\n\nBy default a new player is not auto assigned a free playable slot in the mission lobby in Multiplayer.\nDisable this setting to make him auto assigned to the side with least players.\n\n```cpp\njoinUnassigned = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### minScore, avgScore, maxScore\n\nSet minimum, average and maximum score for your mission.\nScore is related to the star display in the debriefing screen (OFP:CWC).\nThe score can be influenced during a missions progress by using the addRating command.\n\n```cpp\nminScore = 0;\navgScore = 1800;\nmaxScore = 75000;\n```\n\n> [!IMPORTANT]\n> Values have to follow this formula: **minScore < avgScore < maxScore**. Any other combinations can lead to game freeze upon mission end.\n\n##### missionGroup (Arma 3 v2.10)\n\nShared mission group name to override default missionName used with missionProfileNamespace, saveMissionProfileNamespace\n\n```cpp\nmissionGroup = \"SomeNameDescribingCommonMissions\";\n```\n\n##### onCheat (Arma 3 v1.00)\n\nExecutes custom statement when player enters the GETALLGEAR cheat (see: GETALLGEAR).\n\n```cpp\nonCheat = \"hint str _this\";\n```\n\n##### onPauseScript (Arma 2: Operation Arrowhead v1.62)\n\nExecutes a custom SQF script or function in scheduled environment (execVM) when player brings up Game Pause screen (presses 'Esc' button).\nDisplay parameter of the resulting dialog is available via `_this select 0` inside the script.\n\n```cpp\nonPauseScript    = \"myOnPauseScript.sqf\";                            // file path\nonPauseScript[]    = { \"myOnPauseFunction1\", \"myOnPauseFunction2\" };    // function name - since Arma 3\n```\n\n> [!IMPORTANT]\n> The script or function executes **in its own namespace**. In order to get/set external global variable you need to explicitly use mission namespace:\n> **Set:**\n>\n> ```sqf\n> // myVar2 = \"345\";                                    // will set the variable only in onPauseScript namespace\n> missionNamespace setVariable [\"myVar2\", \"345\"];        // will be available as a global variable\n> ```\n>\n> **Get:**\n>\n> ```sqf\n> // hint str myVar;                                    // will raise an undefined variable myVar error\n> hint str (missionNamespace getVariable \"myVar\");    // will access the global variable properly\n> ```\n\n##### saving (Armed Assault v1.00)\n\nToggle saving possibility.\n\n```cpp\nsaving = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\n##### scriptedPlayer (Take On Helicopters v1.00)\n\nWhen scripted player is enabled, game no longer shows \"No player select\" error message upon mission start when no player unit is present.\n\n```cpp\nscriptedPlayer = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### skipLobby (Arma 3 v1.60)\n\nWhen enabled, joining player will join the mission bypassing role selection screen.\nThe #joinUnassigned param will be set to 1 automatically, so that player receives first available role from mission template. When leaving such mission, player will go straight back to server browser.\n\n```cpp\nskipLobby = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n### Server Security\n\nThis section underlines mission security settings for server. They can secure or break your mission, so be sure to use them wisely.\n\n##### allowFunctionsLog (Arma 3 v0.50)\n\nAllows functions to log to the RPT file.\n\n```cpp\nallowFunctionsLog = 1; // 0: disabled - 1: enabled. Default: ?\n```\n\n##### allowFunctionsRecompile (Arma 3 v1.00)\n\nAs a security measure, functions are by default protected against rewriting during mission.\nThis restriction does not apply in missions previewed from the editor.\n\n```cpp\nallowFunctionsRecompile = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### zeusCompositionScriptLevel (Arma 3 v2.06)\n\n```cpp\nzeusCompositionScriptLevel = 0;    // 0: all scripts are forbidden\n                                // 1: only attributes are allowed (including custom attributes added by mods)\n                                // 2: all scripts are allowed including init scripts\n                                // Default: 1\n```\n\n##### CfgDisabledCommands (Arma 3 v1.66)\n\nDefine disabled script commands. See CfgDisabledCommands for more detailed explanations.\n\n##### CfgRemoteExec (Arma 3 v1.50)\n\nDefine remoteExec and remoteExecCall restrictions. See CfgRemoteExec for more detailed explanations and examples.\n\n### Tasks\n\nTasks are part of the mission. This section deals with the settings for them.\n\nSee also Arma 3: Task Framework#Task Overhaul\n\n##### taskManagement_markers2D (Arma 3 v1.42)\n\nUse new 2D markers.\n\n```cpp\ntaskManagement_markers2D = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### taskManagement_markers3D (Arma 3 v1.42)\n\nUse new 3D markers.\n\n```cpp\ntaskManagement_markers3D = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### taskManagement_propagate (Arma 3 v1.42)\n\nPropagate shared tasks to subordinates.\n\n```cpp\ntaskManagement_propagate = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n##### taskManagement_drawDist (Arma 3 v1.42)\n\n3D marker maximum draw distance in meters. within this range, unassigned tasks are drawn on screen.\n\n```cpp\ntaskManagement_drawDist = 2500; // in meters. Default: 2000\n```\n\n##### CfgTasks (Armed Assault v1.00)\n\nAgents task config\n\n```cpp\nclass CfgTasks\n{\n    class Default\n    {\n        name = \"\";\n        fsm = \"\";        // relative path to fsm file\n        condition = \"\";    // relative path to sqf file (compiled and stored for the duration of run time, executed frequently)\n        description = \"\";\n        destination = \"\";\n        resources[] = {};\n    };\n};\n```\n\n##### CfgTaskTypes (Arma 3 v1.54)\n\nDefine Task types and their icons.\n\n```cpp\nclass CfgTaskTypes\n{\n    class Attack\n    {\n        icon    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types\\Attack_ca.paa\";\n        icon3D    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types3D\\Attack_ca.paa\";\n    };\n\n    class Defend\n    {\n        icon    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types\\Defend_ca.paa\";\n        icon3D    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types3D\\Defend_ca.paa\";\n    };\n};\n```\n\n##### CfgTaskDescriptions (Arma 3 v1.12)\n\nDefine Task titles and descriptions.\n\n```cpp\nclass CfgTaskDescriptions\n{\n    class myTask1\n    {\n        title        = \"my task title\";\n        description    = \"my task description\";\n        marker        = \"my task destination marker\";\n    };\n\n    class myTask2\n    {\n        title        = \"STR_myTask2Title\";            // note the lack of $ sign here!\n        description    = \"STR_myTask2Description\";        // without $, it translates for each client\n        marker        = \"STR_myTask2Marker\";            // with $ everyone sees the server's language\n    };\n};\n```\n\n##### CfgTaskEnhancements (Arma 3 v1.42)\n\nDefines tasks enhancements directly in a class.\n\n```cpp\nclass CfgTaskEnhancements\n{\n    enable        = 1; // 0: disable new task features (default), 1: enable new task features and add new task markers and task widgets into the map\n    3d            = 1; // 0: do not use new 3D markers (default), 1: replace task waypoints with new 3D markers\n    3dDrawDist    = 0; // 3d marker draw distance (default: 2000)\n    share        = 1; // 0: do not count assigned players (default), 1: count how many players have the task assigned\n    propagate    = 1; // 0: do not propagate (default), 1: propagate shared tasks to subordinates\n};\n```\n\n### Custom Content Definition\n\nThe following class definitions allow for mission-defined content like sounds, music, or more advanced content like functions\n\n##### CfgCameraEffects\n\nConfigure custom cameraEffect.\n\n```cpp\nclass CfgCameraEffects\n{\n    class Array\n    {\n        class External\n        {\n            type = 0;\n            duration = 6;    // 3 seconds for some reason\n            file = \"\";        // some kind of custom .p3d file for camera\n        };\n\n        class AutoTerminate : External\n        {\n            type = 3;        // CamChained\n            chain[] = { \"External\", \"Terminate\" }; // Terminate will trigger after 3 seconds\n        };\n    };\n};\n```\n\nExample:\n\n```sqf\nshowCinemaBorder false;\nprivate _dur = getNumber (missionConfigFile >> \"CfgCameraEffects\" >> \"Array\" >> _this >> \"duration\");\nprivate _cam = \"camera\" camCreate (player modelToWorld [0, -100, 50]);\n_cam camSetTarget player;\n_cam camSetRelPos [0, -0.1, 1.8];\n_cam camCommit (_dur / 2);\n_cam cameraEffect [\"AutoTerminate\", \"Back\"];\nwaitUntil { camCommitted _cam };\ncamDestroy _cam;\n```\n\n##### CfgCommunicationMenu (Arma 3 v1.00)\n\nThis entry allows to add commanding menu option in the communication menu. See Arma 3: Communication Menu for more information.\n\n##### CfgCommands (Arma 3 v1.50)\n\nThis entry contains a list of configurations for certain scripting commands (currently only `allowedHTMLLoadURIs` for htmlLoad, ctrlSetURL and menuSetURL).\nThis entry can be defined in Config.cpp or in a campaign or mission Description.ext; the most local variant is used.\n\n```cpp\nclass CfgCommands\n{\n    // Note that in case of clients connected to dedicated server, restrictions defined in its config have priority.\n    allowedHTMLLoadURIs[] +=\n    {\n        \"*.mywebsite.com\",\n        \"*.mywebsite2.com/something/*\",\n        // ...\n        \"*.mywebsiteN.com\"\n    };\n};\n```\n\n###### `allowedHTMLLoadURIs`\n\nDefines a list of URIs that can be used with htmlLoad, ctrlSetURL and menuSetURL. Only URIs with the following protocols are supported:\n- HTTP (e.g. `http://example.com/`)\n- HTTPS (e.g. `https://example.com/`)\n- FTP (e.g. `ftp://ftp.example.com/`)\n- Gopher (e.g. `gopher://gopher.example.com/`)\n- Arma 3 v2.22 TeamSpeak 3 (e.g. `ts3server://ts3.example.com`)\n\nThe URIs support wildcards:\n- `-` matches any character zero or more times (e.g. `https://*.example.com/` matches `https://www.example.com/` and `https://files.example.com/`)\n- `?` matches any character exactly once (e.g. `https://example.com/?` matches `https://example.com/a` and `https://example.com/b`)\n\n> [!NOTE]\n> Some domains are automatically whitelisted, such as \"arma3.com\" or \"bistudio.com\".\n> This is a list of all patterns for whitelisted URLs in the engine:\n>\n> ```sqf\n> \"(ftp|http|https)://arma3\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.arma3\\\\.com/.*\"\n> \"(ftp|http|https)://bistudio\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.bistudio\\\\.com/.*\"\n> \"(ftp|http|https)://bohemia\\\\.net/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.bohemia\\\\.net/.*\"\n> \"(ftp|http|https)://armaplatform\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.armaplatform\\\\.com/.*\"\n> \"(ftp|http|https)://store\\\\.steampowered\\\\.com/.*\"\n> \"https://steamcommunity\\\\.com/workshop/.*\"\n> ```\n\n##### CfgFunctions (Arma 2 v1.00)\n\nDefine functions for your mission. For a detailed explanation, see:\n\n|  |  |\n|---|---|\n| - Arma 3 v1.00 | Arma 3: Functions Library |\n| - Arma 2 v1.00 Arma 2: Operation Arrowhead v1.00 | Arma 2: Functions Library |\n| - Take On Helicopters v1.00 | Take On Helicopters: Functions Library |\n\n##### CfgHints (Arma 3 v1.00)\n\nDefine Advanced Hints (similar to the Field Manual ones). See Advanced Hints for more information.\n\n##### CfgIdentities\n\nDefine the identities of individual units, you can specify the face, type of glasses worn, voice, tone of voice and name of an identity.\nYou then give a specific unit this identity by using the command setIdentity in the mission.\n\n> [!NOTE]\n> the `nameSound` entry is only valid since Arma 3. See setNameSound for possible values.\n\n```cpp\nclass CfgIdentities\n{\n    class MyLittleSoldier\n    {\n        name        = \"Givens\";\n        nameSound    = \"Givens\"; // Arma 3 only!\n        face        = \"whiteHead_06\";\n        glasses        = \"None\";\n        speaker        = \"Male05ENG\";\n        pitch        = 1.1;\n    };\n};\n```\n\nExample:\n\n```sqf\nplayer setIdentity \"MyLittleSoldier\";\n```\n\nSee CfgIdentities for more detailed information and valid options for face, glasses, speaker etc.\n\n##### CfgLeaflets (Arma 3 v1.76)\n\nDefine leaflets for your missions. See Arma 3: Leaflets for more information.\n\n##### CfgMusic\n\nDefines music you can play with playMusic.\n\n```cpp\nclass CfgMusic\n{\n    tracks[] = {};\n    class MyIntro\n    {\n        // display name\n        name    = \"My intro music\";\n\n        // filename, volume, pitch\n        sound[]    = { \"\\music\\filename.ogg\", db + 0, 1.0 };\n    };\n    class Ludwig9\n    {\n        name    = \"Ludwig Van Beethoven's Ninth Symphony\";\n        sound[]    = { \"\\music\\ludwig9.ogg\", db + 10, 1.0 };\n    };\n};\n```\n\nExample:\n\n```sqf\nplayMusic \"MyIntro\";\n```\n\n> [!IMPORTANT]\n> Setting volume (db) of music far from zero will disable fadeMusic command. Optimal values are from -10 to 10.\n\n##### CfgNotifications (Arma 3 v1.12)\n\nDefine custom notifications to be shown with BIS_fnc_showNotification. See Notification for more detailed information and examples.\n\n##### CfgPostprocessTemplates (Arma 3 v1.00)\n\nDefine custom post-process effects, to Post Process Effects format (only \"colorCorrection\" and \"filmGrain\" are supported for now).\n\nTo be used with BIS_fnc_setPPeffectTemplate.\n\n```cpp\nclass CfgPostprocessTemplates\n{\n    class MyPurplePP\n    {\n        colorCorrections[] = { 1, 1, 0, { 1, 1, 1, 0 }, { 1, 0.5, 1, 0 }, { 0.75, 0.25, 0, 1 } };\n        displayName = \"Purple-ish!\";\n        filmGrain[] = { 0.04, 1, 1, 0, 1 };\n    };\n};\n```\n\n##### CfgRadio\n\nDefines radio sentences you can play with these radio commands: customRadio, vehicleRadio, groupRadio, sideRadio, globalRadio.\n\n```cpp\nclass CfgRadio\n{\n    sounds[] = {};\n    class RadioMsg1\n    {\n        // display name\n        name    = \"\";\n\n        // filename, volume, pitch\n        sound[]    = { \"\\sound\\filename1.ogg\", db - 100, 1.0 };\n\n        // radio caption\n        title    = \"I am ready for your orders.\";\n    };\n\n    class RadioMsg2\n    {\n        name    = \"\";\n        sound[]    = { \"\\sound\\filename2\", db - 100, 1.0 }; // .wss implied\n        title    = \"$STR_RADIO_2\";\n    };\n};\n```\n\nExample:\n\n```sqf\nunit sideRadio \"RadioMsg2\";\n```\n\n##### CfgSentences\n\nSee Conversations for more information.\n\n##### CfgSFX\n\nSee CfgSFX for more information.\n\n##### CfgSounds\n\nGeneral sounds that can be used for dialog, voiceovers in the briefing etc.\n\nSee also commands playSound, say, say2D and say3D.\n\n```cpp\nclass CfgSounds\n{\n    sounds[] = {}; // OFP required it filled, now it can be empty or absent depending on the game's version\n\n    class wolf1\n    {\n        name = \"My wolf sound\";                        // display name\n        sound[] = { \"fx\\wolf1.ogg\", 1, 1, 100 };    // file, volume, pitch, maxDistance\n        titles[] = { 0, \"*wolf growls*\" };            // subtitles\n\n        titlesFont = \"LCD14\";        // OFP:R - titles font family\n        titlesSize = 0.1;            // OFP:R - titles font size\n\n        forceTitles = 1;            // Arma 3 - display titles even if global show titles option is off (1) or not (0)\n        titlesStructured = 1;        // Arma 3 - treat titles as Structured Text (1) or not (0)\n    };\n};\n```\n\n| Property | Description |\n|---|---|\n| sounds[] | *Was* required in previous titles, and needed to be filled with `CfgSounds` defined sounds at the beginning of Operation Flashpoint.<br>At least in Arma 3 the engine finds them without this value which can now be ignored entirely. |\n| name | (Optional) how the sound is referred to in the editor (e.g. name in trigger effects) this can be a translation (e.g `\"$STR_My_Translation\"`) |\n| sound[] | An array containing:<br>- file path: the relative path to the file<br>Since Arma 3 v1.50 the path can be prefixed with `@` in order to look directly into addon files, e.g `\"@a3\\Ui_F_Curator\\Data\\Sound\\CfgSound\\visionMode\"`<br>- volume: between 0 and 5, 1 being normal volume<br>> [!NOTE]<br>> Volume may at some point be found defined with **db** (e.g `db-40`). The formula for db-based volume is: `10^(*number* * (1/20))`.<br>- pitch: 1 is normal pitch, 2 = chipmunk, 0.5 = Darth Vader, etc<br>- max distance: (Optional, default `*volume* × 1000`) maximum distance at which the sound is heard, in metres |\n| titles[] | An array format `{ time1, text1, time2, text2 }` etc:<br>- time#: can be a number or an array:<br>  - number: sound time at which the text is displayed (2 = 2s after sound start)<br>  - array: format `{ displayTime, displayDurationFactor }`:<br>    - displayTime: sound time at which the text is displayed (2 = 2s after sound start)<br>    - displayDurationFactor: default value is 1 (for 10s subtitle display), 0.5 means half the time (5s), 2 means twice the time (20s) etc<br>- text#: the text to be displayed<br>> [!IMPORTANT]<br>> If a subtitle is timed for *after* the sound is done, the sound will repeat until the subtitle is played (then played until its end). |\n| Operation Flashpoint: Resistance v1.75 titlesFont | (Optional) titles font family |\n| Operation Flashpoint: Resistance v1.75 titlesSize | (Optional) titles font size |\n| Arma 3 v0.50 forceTitles | (Optional) if set to 1, will display titles even if global show titles option is off |\n| Arma 3 v0.50 titlesStructured | (Optional) if set to 1, treat titles as Structured Text (e.g `0, \"<t color=\"\"#ff0000\"\">Red text</t>\"`) |\n\nExample:\n\n```sqf\nplaySound \"wolf1\"; // class name as string\nplayer say [\"wolf1\", 100];\n```\n\n> [!NOTE]\n> See [OFP ToadLife's tutorial](http://ofp.toadlife.net/downloads/tutorials/tutorial_sound/tutorial_sound.html) for a sound advice.\n\n##### CfgUnitInsignia (Arma 3 v1.24)\n\nDefine custom unit insignia (shoulder patches). See Arma 3: Unit Insignia for more detailed information.\n\n```cpp\nclass CfgUnitInsignia\n{\n    class 111thID\n    {\n        displayName = \"111th Infantry Division\";    // name displayed in Arsenal\n        author = \"Bohemia Interactive\";                // author displayed in Arsenal\n        texture = \"\\a3\\UI_F_Bootcamp\\Data\\CfgUnitInsignia\\B_111thID_texture_ca.paa\"; // image path\n        textureVehicle = \"\";                        // does nothing, was reserved for future use\n    };\n};\n```\n\n##### CfgUnitTemplates (Arma 3 v1.50)\n\nThis class is used to create units templates. For now, this is only used with the function BIS_fnc_unitHeadgear.\n\n```cpp\nclass CfgUnitTemplates\n{\n    // Classic selectRandom\n    class MyFirstTemplate : Default\n    {\n        headgearList[] =\n        {\n            \"H_Cap_blk\",\n            \"H_Cap_grn\",\n            \"H_Cap_oli_hs\"\n        };\n\n        facewearList[] =\n        {\n            \"G_Bandanna_beast\",\n            \"G_Bandanna_blk\",\n            \"G_Bandanna_khk\"\n        };\n    };\n\n    // the probabilities will be considered, weighted random\n    class MySecondTemplate : Default\n    {\n        headgearList[] =\n        {\n            \"H_Cap_blk\",    0.9,\n            \"H_Cap_grn\",    0.6,\n            \"H_Cap_oli_hs\",    0.55\n        };\n\n        facewearList[] =\n        {\n            \"G_Bandanna_beast\",    0.5,\n            \"G_Bandanna_blk\",    0.5,\n            \"G_Bandanna_khk\",    0.5\n        };\n    };\n};\n```\n\nExample:\n\n```sqf\n[myUnit, \"MyFirstTemplate\"]        call BIS_fnc_unitHeadgear;\n[myUnit, \"MySecondTemplate\"]    call BIS_fnc_unitHeadgear;\n```\n\n##### CfgVehicles (Arma 3 v1.70)\n\nThis class can only be used to create sound sources.\n\nSee also #CfgSFX for more detailed information.\n\n```cpp\nclass CfgVehicles\n{\n    class MyOwlSound        // class name to be used with createSoundSource\n    {\n        sound = \"MyOwl\";    // reference to CfgSFX class\n    };\n};\n```\n\n##### CfgVehicleTemplates (Arma 3 v1.42)\n\nThis class is used to create vehicle templates used by the Vehicle Customisation system.\n\n```cpp\nclass CfgVehicleTemplates\n{\n    class BIS_Offroad_01_default\n    {\n        displayName = \"Default\";\n        author = \"Bohemia Interactive\";\n        textureList[] =\n        {\n            \"guerilla_01\", 0.5,\n            \"guerilla_02\", 1\n        };\n\n        animationList[] =\n        {\n            \"HideBumper1\", 1,\n            \"HideBumper2\", 1\n        };\n    };\n};\n```\n\n##### RscTitles\n\nThis class is used to define custom HUDs. See Arma: GUI Configuration for more information.","sections":[{"heading":null,"level":1,"markdown":"The Description.ext file is a missionConfigFile and is used to set the overall mission attributes or to define global properties that will be available for other scripts.\nIt is placed in the mission root folder and uses the same syntax as the config.cpp file, but supports only a limited number of config classes.\n\nAdditionally, many attributes can also be set via the Eden Editor, where changes are automatically refreshed upon scenario preview.\nIn the 2D Editor the mission has to be reloaded for changes to be applied.\n\n> [!NOTE]\n> This file is required in Operation Flashpoint: Elite for MP missions to work, otherwise a **-1 error** is shown.\n\n> [!NOTE]\n> This page is about the **Mission Description.ext**. For the campaign version, see Campaign Description.ext.\n\n> [!WARNING]\n> The keyword `class` for class definitions **must** be lowercase, otherwise a parsing error will occur.\n\n> [!IMPORTANT]\n> Accidentally creating this file with a wrong file extension is a frequent cause of issues.\n> If you are unfamiliar with script file creation, read Introduction to Arma Scripting#File Creation for a step-by-step tutorial.\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 v2.02, it is possible to import a class from main config and inherit from it in mission config:\n>\n> ```cpp\n> import RscText;\n> class MyText : RscText\n> {\n>     // ...\n> };\n> ```\n>\n> For more information, see the import (Config) page."},{"heading":"Mission Information","level":3,"markdown":"This section helps you find out how to customise Mission overall external appearance, from Mission Overview to Loading Screens.\n\n**Loading screen parameters**\n\n```cpp\nauthor            = \"Varanon\";\nonLoadName        = \"Point Insertion\";\nonLoadMission    = \"A group of NATO soldiers is tasked with sabotaging a coastal defense.\";\nloadScreen        = \"images\\loadScreen.paa\";\n\nclass Header\n{\n    gameType = \"Coop\";    // game type\n    minPlayers =  1;    // minimum number of players the mission supports\n    maxPlayers = 10;    // maximum number of players the mission supports\n};\n```\n\n> [!NOTE]\n> Header's `playerCountMultipleOf` entry is available in earlier titles (from Operation Flashpoint: Elite to Arma 3 1.30), allowing to setup the auto-assign team balancing factor: 1 for Coop, 2 for Versus."},{"heading":"author (Arma 3 v0.50)","level":5,"markdown":"Mission author's name. The default loading screen shows this string below the #onLoadName in a smaller font prefixed by \"by \"."},{"heading":"onLoadName (Arma 3 v0.50)","level":5,"markdown":"String (usually mission name) shown during mission loading. The string is shown in a slightly larger font above the loadScreen.\nThe #onLoadMission text is placed below the load screen and the header gameType determines the game type on top of the box."},{"heading":"onLoadMission","level":5,"markdown":"Displays a message while the mission is loading. Note that a mission that takes very little time to load will only display the message for a short time.\nIn **OFP** this is the name you see when selecting a mission in MP and also the name that is presented to the Multiplayer browser.\n\n```cpp\nonLoadMission = \"YourMissionName\";\n```"},{"heading":"loadScreen (Arma 2: Operation Arrowhead v1.50)","level":5,"markdown":"The picture to be shown while the mission is loaded. The path is relative to the mission folder. Must be in PAA file format.\n2:1 aspect ratio (different aspect are rendered correctly as well, but won't cover the whole area).\nIdeally 1024x512 pixels.\n\n```cpp\nloadScreen = \"pictures\\intro.paa\";\n```"},{"heading":"header (Armed Assault v1.00)","level":5,"markdown":"This class defines mission type and other settings displayed in the multiplayer browser.\n\n```cpp\nclass Header\n{\n    gameType = \"CTF\";    // Game type\n    minPlayers =  1;    // minimum number of players the mission supports\n    maxPlayers = 10;    // maximum number of players the mission supports\n};\n```\n\nSee Multiplayer Game Types for more detailed information."},{"heading":"onLoadIntro","level":5,"markdown":"Displays a message while the intro is loading.\n\n```cpp\nonLoadIntro = \"YourMessage\";\n```"},{"heading":"onLoadMissionTime","level":5,"markdown":"Define whether you will see the time and date displayed while the mission loads. Effect unkown in Arma 3.\n\n```cpp\nonLoadMissionTime = 1; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"onLoadIntroTime","level":5,"markdown":"Define whether you will see the time and date displayed while the intro loads.\n\n```cpp\nonLoadIntroTime = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"briefingName (Arma 3 v1.56)","level":5,"markdown":"Mission name displayed in the mission selection menu.\n\n```cpp\nbriefingName = \"TAG 1-5 CO My super mission\";\n```\n\n> [!IMPORTANT]\n> Please note that the same parameter can be defined in 3DEN in Attributes->General->Presentation->Title, but 'briefingName' from 'description.ext' has a priority. To use localized string either in 3DEN field or in 'description.ext', prefix stringtable ID with `@`."},{"heading":"CfgLoadingTexts (Take On Helicopters v1.00)","level":5,"markdown":"Define mission specific loading texts."},{"heading":"overviewPicture (Arma 3 v0.50)","level":5,"markdown":"Path to image which will be displayed when the mission is highlighted on the mission selection screen. Image should be .paa format and in 2:1 aspect ratio – ideally 1024×512 (Arma 3)."},{"heading":"overviewText (Arma 3 v0.50)","level":5,"markdown":"Text to be displayed below the #overviewPicture on the mission selection screen when the mission is available to play.\n\n> [!IMPORTANT]\n> Please note that the same parameter can be defined in 3DEN in Attributes->General->Overview->Text, but 'overviewText' from 'description.ext' has a priority. To use localized string either in 3DEN field or in 'description.ext', prefix stringtable ID with `@`.\n\n> [!IMPORTANT]\n> The text that appears at the top of an MP mission is defined in **mod** mission definition and **not** through Description.ext:\n>\n> ```cpp\n> class Mission\n> {\n>     // ...\n>     class Intel\n>     {\n>         overviewText = \"This text here\";\n>         // ...\n>     };\n>     // ...\n> };\n> ```"},{"heading":"overviewTextLocked (Arma 3 v0.50)","level":5,"markdown":"Text to be displayed below the #overviewPicture on the mission selection screen when the mission is locked from play.\n\n> [!IMPORTANT]\n> Please note that to use localized string prefix stringtable ID with `@`."},{"heading":"onBriefingGear","level":5,"markdown":"Defines a sound (defined in #CfgSounds) that will play when accessing the gear part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingGear = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3."},{"heading":"onBriefingGroup","level":5,"markdown":"Defines a sound (defined in #CfgSounds) that will play when accessing the group part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingGroup = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3."},{"heading":"onBriefingPlan","level":5,"markdown":"Defines a sound (defined in #CfgSounds) that will play when accessing the plan part of the briefing. See Briefing.html.\n\n```cpp\nonBriefingPlan = \"SoundName\";\n```\n\n> [!NOTE]\n> **Arma 3:** Has no effect in Arma 3."},{"heading":"CfgWorlds (Arma 3 v2.02)","level":5,"markdown":"Could be used to override the following properties used on mission loading: author, description, pictureMap, pictureShot, loadingTexts[].\nIf a specific world name given as a subclass, override will happen only when this world is loading. If subclass with name Any is used, then aforementioned properties would be overridden for any world that is loading.\n\n```cpp\nclass CfgWorlds\n{\n    class Any // or specific world name\n    {\n        author = \"author\";\n        description = \"description\";\n        pictureMap = \"picturepath\";\n        pictureShot = \"picturepath\";\n        loadingTexts[] = { \"text1\", \"text2\", \"text3\" };\n    };\n};\n```"},{"heading":"Respawn/Revive","level":3,"markdown":"This section talks about respawn and revive actions.\n- for Arma 2, see First Aid.\n- for Arma 3, see Arma 3: Respawn and Arma 3: Revive.\n\n|  |  |  |\n|---|---|---|\n| + Respawn types |  |  |\n| ID | Text version | Description |\n| **0** | **\"NONE\"** | No respawn |\n| **1** | **\"BIRD\"** | Respawn as a seagull |\n| **2** | **\"INSTANT\"** | Respawn just where you died. |\n| **3** | **\"BASE\"** | Respawn in base.<br>A respawn marker is needed. If no marker is defined, respawn behaviour will be the same as **\"INSTANT\"**.<br>Marker role names:<br>- Unit respawn: *respawn_**SIDE***<br>- Vehicle respawn: *respawn_vehicle_**SIDE***<br>Side can be one of *west*, *east*, *guerrila* (sic), *civilian*, e.g **respawn_west**.<br>Any suffix (eg: respawn_west**ABC**, respawn_west**_1**, etc) will allow multiple random respawn points. |\n| **4** | **\"GROUP\"** | Respawn in your group. If there is no remaining AI, you will become a seagull. |\n| **5** | **\"SIDE\"** | Armed Assault v1.08 Respawn into an AI unit on your side (if there's no AI left, you'll become a seagull).<br>With this respawn type, team switch is also available to any AI controlled playable units. |"},{"heading":"respawn","level":5,"markdown":"Sets soldiers and vehicles respawn type.\n\n```cpp\nrespawn = 0;        // Default: 0 for SP, 1 for MP\nrespawn = \"SIDE\";    // text version works too\n```"},{"heading":"respawnVehicle (Arma 3 v2.18)","level":5,"markdown":"Sets vehicles only respawn type. Vehicles can only have 2 (or \"INSTANT\") and 3 (or \"BASE\") respawn mode. All other modes are equal to disabled respawn. If 'respawnVehicle' is not defined, the 'respawn' value is used.\n\n```cpp\nrespawnVehicle = 3;            // number version\nrespawnVehicle = \"BASE\";    // text version works too\n```"},{"heading":"respawnButton","level":5,"markdown":"Enable or disable the respawn button in the menu for INSTANT and BASE respawn types.\n\n```cpp\nrespawnButton = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"respawnDelay","level":5,"markdown":"Set respawn delay in seconds.\n\n```cpp\nrespawnDelay = 42; // Default: ?\n```"},{"heading":"respawnVehicleDelay","level":5,"markdown":"Set vehicle respawn delay in seconds.\n\n```cpp\nrespawnVehicleDelay = 12; // Default: ?\n```"},{"heading":"respawnDialog","level":5,"markdown":"Show the scoreboard and respawn countdown timer for a player if he is killed with respawn type **3**.\n\n```cpp\nrespawnDialog = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"respawnOnStart","level":5,"markdown":"Respawn player when he joins the game. Available only for INSTANT and BASE respawn types.\n\n```cpp\nrespawnOnStart = 1; // Default: 0\n```\n\n- -1 - Dont respawn on start. Don't run respawn script on start.\n-  0 - Dont respawn on start. Run respawn script on start.\n-  1 - Respawn on start. Run respawn script on start."},{"heading":"respawnTemplates","level":5,"markdown":"Respawn templates from CfgRespawnTemplates. You can combine any number of them together.\n\n```cpp\nrespawnTemplates[] = { \"Counter\", \"Wave\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn templates can be specified with *respawnTemplates***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> When such is undefined, general respawnTemplates are used instead."},{"heading":"respawnWeapons (Armed Assault v1.00)","level":5,"markdown":"Set weapons players will receive upon respawn. #respawnMagazines has to be defined as well.\n\n```cpp\nrespawnWeapons[] = { \"arifle_Katiba_GL_F\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn weapons can be specified with *respawnWeapons***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> Corresponding *respawnMagazines***SIDE***[]* has to be defined as well."},{"heading":"respawnMagazines (Armed Assault v1.00)","level":5,"markdown":"Set magazines players will receive upon respawn. #respawnWeapons has to be defined as well.\n\n```cpp\nrespawnMagazines[] = { \"30Rnd_65x39_caseless_green\", \"30Rnd_65x39_caseless_green\" };\n```\n\n> [!IMPORTANT]\n> Side specific respawn weapons can be specified with *respawnMagazines***SIDE***[]* where **SIDE** can be any playable side (West, East, Guer, Civ).\n>\n> Corresponding *respawnWeapons***SIDE***[]* has to be defined as well."},{"heading":"reviveMode (Arma 3 v1.62)","level":5,"markdown":"Define if Revive mode is enabled.\n\n```cpp\nreviveMode = 1; // Default: 0\n```\n\n- 0 - disabled\n- 1 - enabled\n- 2 - controlled by player attributes"},{"heading":"reviveUnconsciousStateMode (Arma 3 v1.62)","level":5,"markdown":"Define revive mode.\n\n```cpp\nreviveUnconsciousStateMode = 0; // Default: 0\n```\n\n- 0 - basic mode\n- 1 - advanced mode\n- 2 - realistic\nSee damage model for more detailed information."},{"heading":"reviveRequiredTrait (Arma 3 v1.62)","level":5,"markdown":"Define if only a medic (or unit with medic trait) can perform a revive.\n\n```cpp\nreviveRequiredTrait = 0; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"reviveRequiredItems (Arma 3 v1.62)","level":5,"markdown":"Define if a medical item (first aid kit or medkit) is required to begin a revive process.\n\n```cpp\nreviveRequiredItems = 2; // Default: ?\n```\n\n- 0 - none\n- 1 - medkit\n- 2 - medkit or first aid kit"},{"heading":"reviveRequiredItemsFakConsumed (Arma 3 v1.62)","level":5,"markdown":"Define if a first aid kit is consumed on reviving a teammate\n\n```cpp\nreviveRequiredItemsFakConsumed = 1; // 0: disabled - 1: enabled. Default: ?\n```"},{"heading":"reviveMedicSpeedMultiplier (Arma 3 v1.62)","level":5,"markdown":"Speed multiplier for revive performed by medic\n\n```cpp\nreviveMedicSpeedMultiplier = 2; // medic revive will be two times faster compared to another soldier\n```"},{"heading":"reviveDelay (Arma 3 v1.62)","level":5,"markdown":"The time in seconds it takes to revive an incapacitated unit. Having a Medikit will halve this time.\n\n```cpp\nreviveDelay = 10; // Default: 6\n```"},{"heading":"reviveForceRespawnDelay (Arma 3 v1.62)","level":5,"markdown":"The time in seconds it takes for an incapacitated unit to force their respawn.\n\n```cpp\nreviveForceRespawnDelay = 5; // Default: 3\n```"},{"heading":"reviveBleedOutDelay (Arma 3 v1.62)","level":5,"markdown":"The time in seconds it takes for a unit to bleed out.\n\n```cpp\nreviveBleedOutDelay = 300; // Default: 120\n```"},{"heading":"enablePlayerAddRespawn (Arma 3 v1.62)","level":5,"markdown":"Usage unsure, may be related to respawn template **MenuPosition**.\n\n```cpp\nenablePlayerAddRespawn = 0; // Disable framework respawn\n```"},{"heading":"CfgRespawnInventory (Arma 3 v1.62)","level":5,"markdown":"This class defines a respawn inventory, used with **MenuInventory** respawn template.\nLoadouts with no assigned role are automatically assigned to the \"Default\" role.\n\nSee also BIS_fnc_addRespawnInventory, BIS_fnc_removeRespawnInventory\n\n```cpp\nclass CfgRespawnInventory\n{\n    class Blufor1\n    {\n        displayName = \"Light\";                                    // Name visible in the menu\n        icon = \"\\A3\\Ui_f\\data\\GUI\\Cfg\\Ranks\\sergeant_gs.paa\";    // Icon displayed next to the name\n        role = \"Assault\";                                        // Optional, see CfgRoles\n\n        // Loadout definition, uses same entries as CfgVehicles classes\n        weapons[] =\n        {\n            \"arifle_MXC_F\",\n            \"Binocular\"\n        };\n\n        magazines[] =\n        {\n            \"30Rnd_65x39_caseless_mag\",\n            \"30Rnd_65x39_caseless_mag\",\n            \"SmokeShell\"\n        };\n\n        items[] =\n        {\n            \"FirstAidKit\"\n        };\n\n        linkedItems[] =\n        {\n            \"V_Chestrig_khk\",\n            \"H_Watchcap_blk\",\n            \"optic_Aco\",\n            \"acc_flashlight\",\n            \"ItemMap\",\n            \"ItemCompass\",\n            \"ItemWatch\",\n            \"ItemRadio\"\n        };\n\n        uniformClass = \"U_B_CombatUniform_mcam_tshirt\";\n        backpack = \"B_AssaultPack_mcamo\";\n    };\n\n    class Blufor2\n    {\n        // Alternative configuration pointing to a CfgVehicles class. Loadout will be copied from it.\n        vehicle = \"B_soldier_AR_F\";\n    };\n};\n```"},{"heading":"CfgRespawnTemplates (Arma 3 v1.62)","level":5,"markdown":"This class defines new respawn templates to be used with respawn templates.\n\n```cpp\nclass CfgRespawnTemplates\n{\n    // class used in respawnTemplates entry\n    class myTag_beacon\n    {\n        // function or script executed upon death\n        // parameters passed into it are the same as are passed into onPlayerKilled.sqf file\n        onPlayerKilled = \"\\myAddon\\scripts\\respawnBeacon.sqf\";\n\n        // function or script executed upon respawn\n        // parameters passed into it are the same as are passed into onPlayerRespawn.sqf file\n        onPlayerRespawn = \"\\myAddon\\scripts\\respawnBeacon.sqf\";\n\n        // default respawn delay\n        // can be overwitten by description.ext attribute of the same name\n        respawnDelay = 20;\n\n        // see respawnOnStart for description and limitations\n        // can be overridden by description.ext attribute of the same name\n        respawnOnStart = 1;\n    };\n\n    class Spectator\n    {\n        onPlayerRespawn = \"BIS_fnc_respawnSpectator\"; // a function can be used instead of a script\n    };\n};\n```"},{"heading":"CfgRoles (Arma 3 v1.62)","level":5,"markdown":"This class defines Respawn roles. The main purpose of Roles is to make things clearer and simpler for player when selecting a loadout. All the loadouts available in a mission are now divided into various roles.\nMission designer can use roles already created in the game config, or custom roles can be defined in description.ext file. Loadouts with no role assigned are automatically assigned to the *Default* role.\n\n```cpp\n// all default roles with icons\nclass CfgRoles\n{\n    class Assault\n    {\n        displayName = \"$STR_A3_Role_Assault\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\assault_ca.paa\";\n    };\n\n    class Support\n    {\n        displayName = \"$STR_A3_Role_Support\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\support_ca.paa\";\n    };\n\n    class Recon\n    {\n        displayName = \"$STR_A3_Role_Recon\";\n        icon = \"a3\\Ui_f\\data\\GUI\\Cfg\\RespawnRoles\\recon_ca.paa\";\n    };\n};\n```"},{"heading":"Mission Keys","level":3,"markdown":"Mission keys are used to lock/unlock certain missions until you completed other ones. It can also be used in mission to know which missions you finished.\n\nActivated keys can be found in user profile (e.g documents\\*username.Arma3profile*) under *activeKeys* section.\n\nSee also commands activateKey, isKeyActive and deActivateKey for more detailed information.\n\n> [!IMPORTANT]\n> Please note that unlike other text items, stringtable translations ($STR_*) cannot be used."},{"heading":"keys (Armed Assault v1.00)","level":5,"markdown":"List of keys from which #keysLimit counts the *done* ones.\n\n```cpp\nkeys[] = { \"key1\", \"key2\", \"key3\" };\n```"},{"heading":"keysLimit (Armed Assault v1.00)","level":5,"markdown":"Number of keys from the #keys list needed *done* to unlock (and be able to play) this mission.\n\n```cpp\nkeysLimit = 2;\n```"},{"heading":"doneKeys (Armed Assault v1.00)","level":5,"markdown":"Name of keys marked *done* on mission completion.\n\n```cpp\ndoneKeys[] = { \"key4\" };\n```"},{"heading":"Player's UI","level":3,"markdown":"This section explains HUD customisation possibilities.\n\nSee also commands:\n- showCompass, shownCompass, visibleCompass\n- showGPS, shownGPS, visibleGPS\n- showHUD, shownHUD\n- showWatch, shownWatch, visibleWatch\n- showUAVFeed, shownUAVFeed Arma 3 v1.16\n- showPad, shownPad Operation Flashpoint v1.00"},{"heading":"overrideFeedback (Arma 3 v1.98)","level":5,"markdown":"Some of the feedback effects in Arma 3 are scripted and executed by `functions_f\\feedback\\fn_feedbackMain.fsm`. Those include being hit, pulsation, dirt from explosion, choking etc.\nAdding `overrideFeedback` with value > 0 will stop feedback FSM from executing, allowing mission/mod makers to script their own, custom effects. The param is first checked in the mission config and then mod config.\nIf mission config has this param set to 0, it will force default feedback handling without possibility to override it by mods. Do not set this param unless you are planning to enforce feedback one way or another.\n\n```cpp\noverrideFeedback = 1; // 0: force default handling, 1+: allow custom handling. Default: not set\n```"},{"heading":"showHUD","level":5,"markdown":"Enables/Disables the following IGUI elements:\n- Vehicle and unit info\n- Radar and tactical display\n- Vehicle compass\n- Tank direction indicator\n- Commanding menu\n- Group info bar\n- HUD weapon cursors\n- Vehicle display panels\n- Kill messages\n- 3D Icons visibility\n\n```cpp\nshowHUD = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nThe effect of using the above **showHUD** param is different from the effects of showHUD scripting command, both methods are rather complementary to each other.\n\nSince Arma 3 v1.50 **showHUD** param can be an array to allow control over separate HUD elements, for example:\n\n```cpp\nshowHUD[] =\n{\n    1,    // Scripted HUD (same as showHUD command)\n    1,    // Vehicle and unit info\n    0,    // Vehicle radar [HIDDEN]\n    0,    // Vehicle compass [HIDDEN]\n    1,    // Tank direction indicator\n    1,    // Commanding menu\n    1,    // Group info bar\n    1,    // HUD weapon cursors\n    1,    // Vehicle display panels\n    1,    // \"x killed by y\" systemChat messages\n    1    // force show drawIcon3D icons\n};\n```\n\n> [!IMPORTANT]\n> Using the **showHUD[]** array parameter will disable the showHUD command entirely."},{"heading":"showCompass","level":5,"markdown":"Defines if the compass is visible.\n\n```cpp\nshowCompass = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showGPS","level":5,"markdown":"Enables/Disables the GPS.\n\n```cpp\nshowGPS = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nIn Armed Assault *1.04* toggle this option to disable the mini map attached to the GPS."},{"heading":"showGroupIndicator (Arma 3 v1.00)","level":5,"markdown":"Changes default GPS mini map into a radar like display that indicates group members relative position to the player.\n\n```cpp\nshowGroupIndicator = 1; // 0: disabled - 1: enabled. Default: 0\n```\n\n> [!IMPORTANT]\n> Has no effect since custom panels were introduced in Arma 3. See BIS_fnc_groupIndicator."},{"heading":"showMap","level":5,"markdown":"Defines if the map is shown after the mission starts.\n\n```cpp\nshowMap = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showNotePad (Armed Assault v1.00)","level":5,"markdown":"In Armed Assault, defines if the NotePad is shown after the mission starts.\n\n```cpp\nshowNotePad = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showPad (Operation Flashpoint v1.00)","level":5,"markdown":"Defines if the NotePad is shown after the mission starts. **Only in OFP:CWC**.\n\n```cpp\nshowPad = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showWatch","level":5,"markdown":"Defines if the watch is visible.\n\n```cpp\nshowWatch = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showUAVFeed (Arma 3 v1.16)","level":5,"markdown":"Enables/Disables the UAV Feed.\n\n```cpp\nshowUAVFeed = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"showSquadRadar (Arma 3 v1.60)","level":5,"markdown":"Defines if the Squad Radar is visible.\n\n```cpp\nshowSquadRadar = 0; // 0: disabled - 1: enabled. Default: 0\n```\n\n> [!IMPORTANT]\n> Has no effect since custom panels were introduced in Arma 3."},{"heading":"overrideHazeQuality (Arma 3 v2.16)","level":5,"markdown":"0/1/2 - VeryLow/Low/Standard - Forces haze quality and in MP has priority over the server 'overrideHazeQuality' option. Standard(2) - mod config driven. Default(-1) - do not force.\n\n```cpp\noverrideHazeQuality = 1; // Low\n```"},{"heading":"Starting Gear","level":3,"markdown":"Starting gear points to briefing-available equipment. For respawn equipment, see #Respawn/Revive.\n\nSee also Weapon Pool Commands for more detailed information about weapon pool system."},{"heading":"weapons","level":5,"markdown":"Set weapons available to players during the briefing.\n\n```cpp\nclass Weapons\n{\n    class AK74        { count = 8; };\n    class RPG7V        { count = 2; };\n    class Binocular    { count = 2; };\n};\n```"},{"heading":"magazines","level":5,"markdown":"Set magazines available to players during the briefing.\n\n```cpp\nclass Magazines\n{\n    class 30Rnd_545x39_AK    { count = 32; };\n    class PG7V                { count =  6; };\n    class HandGrenade        { count = 16; };\n};\n```"},{"heading":"backpacks (Arma 2: Operation Arrowhead v1.50)","level":5,"markdown":"Set backpacks available to players during the briefing.\n\n```cpp\nclass Backpacks\n{\n    class US_Patrol_Pack_EP1    { count = 4; };\n    class US_Assault_Pack_EP1    { count = 4; };\n};\n```"},{"heading":"allowSubordinatesTakeWeapons (Arma 2: Operation Arrowhead v1.56)","level":5,"markdown":"Allows subordinates (i.e., not leaders) to equip items defined in #weapons, #magazines and #backpacks.\n\n```cpp\nallowSubordinatesTakeWeapons = 1; // 0: disabled - 1: enabled. Default: ?\n```"},{"heading":"arsenalRestrictedItems (Arma 3 v1.98)","level":5,"markdown":"Used to blacklist undesired Arsenal equipment, which prevents user saved loadout from being loaded if it contains restricted items.\n\n```cpp\narsenalRestrictedItems[] = { \"U_B_Soldier_VR\" };\n```"},{"heading":"allowProfileGlasses (Arma 3 v2.04)","level":5,"markdown":"When set to 0 will stop glasses set in player profile from being added to player's gear:\n\n```cpp\nallowProfileGlasses = 0;\n```"},{"heading":"Corpse and Wreck Management","level":3,"markdown":"This section explains how to use game-included **garbage collector** (**GC**) for better performances.\n\nSee also addToRemainsCollector, isInRemainsCollector and removeFromRemainsCollector commands.\n\nThe Remains Collector, if enabled, runs at background on every client and clears mission of corpses and wrecks depending on set params and mode.\nIndividual objects can be added or removed from collector monitoring. Items in remains collector are sorted depending on how valuable they are.\nThe most valuable items are pushed to the end of remains array and will be deleted last if possible; for example, the flag carrier is never deleted while it has the flag."},{"heading":"corpseManagerMode (Arma 3 v1.32)","level":5,"markdown":"Sets the mode for automatic corpse removal.\n\n```cpp\ncorpseManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the units are automatically managed by the manager\n- 1 = All - All units are automatically managed by the manager\n- 2 = None_But_Respawned - Only units that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All units are automatically managed by the manager with the exception of respawned ones (opposite to mode 2)"},{"heading":"corpseLimit (Arma 3 v0.50)","level":5,"markdown":"If the total number of monitored corpses is higher than **corpseLimit**, the corpses that have been dead for longer than #corpseRemovalMinTime will be considered for removal.\n\n```cpp\ncorpseLimit = 1; // Default: 15\n```"},{"heading":"corpseRemovalMinTime (Arma 3 v0.50)","level":5,"markdown":"See #corpseLimit above.\n\n```cpp\ncorpseRemovalMinTime = 60; // seconds. Default: 10\n```"},{"heading":"corpseRemovalMaxTime (Arma 3 v0.50)","level":5,"markdown":"Monitored corpses that are dead for longer than **corpseRemovalMaxTime** will be considered for removal regardless of the #corpseLimit.\n\n```cpp\ncorpseRemovalMaxTime = 1200; // seconds. Default: 3600\n```"},{"heading":"disposalCheckPeriod (Arma 3 v2.18)","level":5,"markdown":"How often the remains collector checks monitored remains for removal. The value can be between 1 and 60.\n\n```cpp\ndisposalCheckPeriod = 30; // seconds. Default: 10\n```"},{"heading":"minPlayerDistance (Arma 3 v1.66)","level":5,"markdown":"This value applies for monitored corpses, wrecks and weaponholders. The minimum distance between remains and the nearest player before the remains are allowed to be removed by the remains collector.\nThe remains closer than minimum distance to nearest player will not be removed until distance increases. If 'minPlayerDistance' is set to 0, the distance check is not performed.\n\n```cpp\nminPlayerDistance = 50; // meters. Default: 0\n```\n\nArma 3 v2.18 The array variant allows setting individual minPlayerDistance for corpses, wrecks and weaponholders:\n\n```cpp\nminPlayerDistance[] = { 50, 60, 70 }; // metres. Default: { 0, 0, 0 }\n```\n\nArma 3 v2.20 The array supports override times now, format `{ corpsesMinDist, wrecksMinDist, weaponholdersMinDist, corpsesOverrideTime, wrecksOverrideTime, weaponholdersOverrideTime }`\nOverride times are \"force-remove after\" times. For example a corpse is scheduled for deletion but cannot be deleted because a player is nearby.\nIf override time is set, the corpse will be deleted regardless of player proximity.\nSo if for example #removalMaxTime is 3600 and override time is 300, the remains will be definitely deleted within 3600 + 300 = 3900 seconds even if a player is close by.\n\n```cpp\nminPlayerDistance[] = { // metres. Default: { 0, 0, 0, -1, -1, -1 }\n    50,        60,        70,        // corpsesMinDist,        wrecksMinDist,        weaponholdersMinDist\n    300,    120,    60        // corpsesOverrideTime,    wrecksOverrideTime,    weaponholdersOverrideTime\n};\n```"},{"heading":"weaponholderManagerMode (Arma 3 v2.18)","level":5,"markdown":"Sets the mode for automatic weapon holder removal.\n\n```cpp\nweaponholderManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the weapon holders are automatically managed by the manager\n- 1 = All - All weapon holders are automatically managed by the manager\n- 2 = None_But_Respawned - Only weapon holders from units that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All weapon holders are automatically managed by the manager with the exception of the ones from respawned units (opposite to mode 2)\n\n> [!NOTE]\n> WeaponHolderSimulated which is created after unit is dead and contains unit's weapon is not managed by the collector, but linked to the corpse and will be deleted when corpse is deleted. WeaponHolderSimulated that is created manually is managed by the collector just like GroundWeaponHolder"},{"heading":"weaponholderLimit (Arma 3 v2.18)","level":5,"markdown":"If the total number of monitored weapon holders is higher than **weaponholderLimit**, the weapon holders that exist for longer than #weaponholderRemovalMinTime will be considered for removal.\n\n```cpp\nweaponholderLimit = 1; // Default: 50\n```"},{"heading":"weaponholderRemovalMinTime (Arma 3 v2.18)","level":5,"markdown":"See #weaponholderLimit above.\n\n```cpp\nweaponholderRemovalMinTime = 60; // seconds. Default: 3600\n```"},{"heading":"weaponholderRemovalMaxTime (Arma 3 v2.18)","level":5,"markdown":"Monitored weapon holders that exist for longer than **weaponholderRemovalMaxTime** will be considered for removal regardless of the #weaponholderLimit.\n\n```cpp\nweaponholderRemovalMaxTime = 1200; // seconds. Default: 36000\n```"},{"heading":"wreckManagerMode (Arma 3 v1.32)","level":5,"markdown":"Sets the mode for automatic wreck removal.\n\n```cpp\nwreckManagerMode = 0; // Default: 0\n```\n\n- 0 *(Default)* = None - None of the vehicles are automatically managed by the manager\n- 1 = All - All vehicles are automatically managed by the manager\n- 2 = None_But_Respawned - Only vehicles that can respawn are automatically managed by the manager\n- 3 = All_But_Respawned - All vehicles are automatically managed by the manager with exception of respawned (opposite to mode 2)"},{"heading":"wreckLimit (Arma 3 v0.50)","level":5,"markdown":"If the total number of monitored wrecks is higher than **wreckLimit**, the wrecks that existed for longer than #wreckRemovalMinTime will be considered for removal.\n\n```cpp\nwreckLimit = 1; // seconds. Default: 15\n```"},{"heading":"wreckRemovalMinTime (Arma 3 v0.50)","level":5,"markdown":"See #wreckLimit above.\n\n```cpp\nwreckRemovalMinTime = 60; // seconds. Default: 10\n```"},{"heading":"wreckRemovalMaxTime (Arma 3 v0.50)","level":5,"markdown":"Monitored wrecks that existed for longer than **wreckRemovalMaxTime** will be considered for removal regardless of the #wreckLimit.\n\n```cpp\nwreckRemovalMaxTime = 1800; // seconds. Default: 36000 (10 hours)\n```"},{"heading":"Mission Parameters","level":3,"markdown":"Mission parameters allow you to add settings to your creation. These settings are in-game accessible only in Multiplayer mode, but can also be accessed by commands for a scripted use in Singleplayer mode.\n\nSee Mission Parameters, along with BIS_fnc_getParamValue function (paramsArray usage is **not** recommended)."},{"heading":"param1/param2 (Operation Flashpoint v1.00)","level":5,"markdown":"**param1** and **param2** are multiplayer options that can be seen in the multiplayer lobby.\nThey can be useful for setting time limits and score limits in such games as Capture the Flag and Death Matches.\nOther popular uses include time acceleration, setting the mission difficulty or switching the intro on/off.\n\nIn the mission, variables **param1** and **param2** have the corresponding values of the chosen options.\n\n> [!IMPORTANT]\n> - While **param1**/**param2** were introduced in **OFP** and can still be used in later titles, it is **highly recommended** to use config class #Params, available since Arma 2 v1.03.\n> - **param1**/**param2** variables can be overridden during the mission as they are **not** read-only.\n\n```cpp\ntitleParam1 = \"Time limit:\";\nvaluesParam1[] = { 0, 300, 600, 900 };\ndefValueParam1 = 900;\ntextsParam1[] = { \"Unlimited\", \"5 min\", \"10 min\", \"15 min\" };\n\ntitleParam2 = \"Score to win:\";\nvaluesParam2[] = { 10000, 5, 7, 10, 15, 20, 25, 30 };\ndefValueParam2 = 5;\ntextsParam2[] = { \"Unlimited\", 5, 7, 10, 15, 20, 25, 30 };\n```\n\nExample:\n\n```sqf\nhint format [\"param1 = %1\\nparam2 = %2\", param1, param2];\n```"},{"heading":"Params (Arma 2 v1.03)","level":5,"markdown":"These are Multiplayer parameters, available in the lobby by the server administrator.\nThey are intended as a replacement for #param1/param2.\n\n```cpp\nclass Params\n{\n    class ViewDistance\n    {\n        // Visible name in lobby settings list\n        title = \"View distance\";\n\n        // must be integers - commas e.g 1.5 are not allowed\n        values[] = { 500, 1000, 2000, 5000 };\n\n        // Description of each selectable item - must have the same number of items as 'values'\n        // If texts are missing, the values will be displayed instead\n        texts[] = { \"500m\", \"1000m\", \"2 km\", \"5 km\" };\n\n        // must be listed in 'values' array, otherwise 0 is used. If not integer, fallback value is 1\n        default = 1000;\n\n        // (optional) script file called when player joins, selected value is passed as an argument\n        file = \"setViewDistance.sqf\";\n    };\n};\n```\n\nSee Mission Parameters for more detailed information."},{"heading":"Mission Settings","level":3,"markdown":"These are non-editable, mission maker design settings.\nThey can be used for a smoother experience, briefing/debriefing behaviour, saving options, etc.\n\nSee also Debriefing for more detailed information."},{"heading":"aiKills","level":5,"markdown":"Enables AI units score to appear in score table.\n\n```cpp\naiKills = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"briefing","level":5,"markdown":"Skip briefing screen for SP missions. If no briefing.html is present, it is skipped anyway.\n\n```cpp\nbriefing = 0; // 0: disabled - 1: enabled. Default: 1\n```\n\nBriefing will still be displayed until all clients are connected and done loading."},{"heading":"debriefing","level":5,"markdown":"Defines if the debriefing is shown or not at the end of the mission.\n\n```cpp\ndebriefing = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"CfgDebriefing (Arma 3 v0.50)","level":5,"markdown":"Define custom mission endings or override the default endings (found under CfgDebriefing in the game's config file).\n\n```cpp\nclass CfgDebriefing\n{\n    // Used when all players die in MP\n    class endDeath\n    {\n        title = \"Both teams have died.\";\n        description = \"Everyone was killed by the bomb.\";\n        picture = \"KIA\";\n    };\n};\n```\n\n**For a detailed description, see Arma 3: Debriefing.**"},{"heading":"CfgDebriefingSections (Arma 3 v0.50)","level":5,"markdown":"Define custom sections to be displayed on the debriefing screen. Useful for custom scoring systems or displaying player achievements.\n\n```cpp\nclass CfgDebriefingSections\n{\n    class bPoints\n    {\n        title = \"Blufor Points\";\n        variable = \"BLU_P\";\n    };\n\n    class oPoints\n    {\n        title = \"Opfor Points\";\n        variable = \"OPF_P\";\n    };\n};\n```"},{"heading":"DifficultyOverride (Arma 3 v2.16)","level":5,"markdown":"Allow to override a difficulty setting for the mission only.\n\nAt the moment, only `tacticalPing` is supported.\n\n```cpp\nclass DifficultyOverride\n{\n    tacticalPing = 0; // disables tactical ping in this mission, even if selected difficulty preset has it enabled\n}\n```\n\n|  |  |  |  |\n|---|---|---|---|\n| + Channel ID number command correspondence |  |  |  |\n| Name | ID | Radio | Chat |\n| Global | 0 | globalRadio | globalChat |\n| Side | 1 | sideRadio | sideChat |\n| Command | 2 | commandRadio | commandChat |\n| Group | 3 | groupRadio | groupChat |\n| Vehicle | 4 | vehicleRadio | vehicleChat |\n| Direct | 5 | directSay | N/A |\n| System | 6 Arma 2: Operation Arrowhead v1.62<br>16 Arma 3 v0.50 | N/A | systemChat |"},{"heading":"disableChannels (Arma 2: Operation Arrowhead v1.62)","level":5,"markdown":"Disable global, side, command or system chat. MOTD and admin say have exception and will show in global.\n\n> [!NOTE]\n> - This setting is not considered when hosting from Eden Editor.\n> - A mission using **disableChannels** will override any `disableChannels[]` value in server config.\n\n> [!NOTE]\n> **Arma 3:** See enableChannel.\n\nArma 2: Operation Arrowhead v1.62 **basic syntax**:\n\n```cpp\ndisableChannels[] = { 0, 3 }; // simple channel ID list\n```\n\nArma 3 v1.60 **advanced syntax**:\n\n```cpp\ndisableChannels[] =\n{\n    {\n        0,        // channel ID\n        false,    // text chat remains enabled\n        true,    // voice chat is disabled\n        false,    // allow placing map markers (Optional, default false - added in v2.20)\n        true    // disable drawing on map (Optional, default false - added in v2.20)\n    },\n    { 3, true, true }\n};\n```"},{"heading":"disabledAI","level":5,"markdown":"Multiplayer setting that removes all playable units which do not have a human player.\n\nWhen AI is disabled, a player logging out will **not** have AI take control of his character.\n\n> [!IMPORTANT]\n> Disabling AI units will prevent JIP into playable units if **respawn** is disabled.\n\n```cpp\ndisabledAI = 1; // 0: AIs fill empty slots - 1: AIs are disabled, only players can spawn. Default: 0\n```"},{"heading":"disableRandomization (Arma 3 v1.42)","level":5,"markdown":"Disables randomisation on certain objects, object types or object kinds in the mission. For more information visit: Arma 3: Vehicle Customisation\n\n```cpp\ndisableRandomization[] = { \"All\", \"AllVehicles\", \"B_G_Offroad_01_F\", \"myCar\", \"MyUnitName\", \"B_Soldier_F\" };\n```\n\nNote: This takes higher priority and will override the following:\n\n```sqf\n_vehicle setVariable [\"BIS_enableRandomization\", true]; // cannot enable for all or specific vehicles once disabled in description.ext\n```"},{"heading":"enableDebugConsole (Arma 3 v0.50)","level":5,"markdown":"Allows access to the Debug Console in multiplayer scenarios outside of the editor. This has no effect for singleplayer scenarios.\n\nSince Arma 3 v2.18 also makes the console available in singleplayer scenarios.\n\n```cpp\nenableDebugConsole = 2; // dangerous in MP\n```\n\n- 0 - Default behavior, available only in editor\n- 1 - Available in SP and for hosts / logged in admins\n- 2 - Available for everyone\n\nAlternative since Arma 3 v1.72\n\n```cpp\nenableDebugConsole[] = { \"76561198XXXXXXXXX\", \"76561198YYYYYYYYY\", }; // admins and players with their UID in this list have access\n```"},{"heading":"enableItemsDropping (Arma 2: Operation Arrowhead v1.62)","level":5,"markdown":"Disable dropping items while swimming. Introduced in Arma 2: Operation Arrowhead BETA 1.60.93965. Doesn't seem to have any effect in Arma 3.\n\n```cpp\nenableItemsDropping = 0; // 0: disabled - 1: enabled. Default: ?\n```"},{"heading":"enableTeamSwitch","level":5,"markdown":"Enables or disables Team Switch functionality in MP when respawn type is 5 (SIDE).\n\n```cpp\nenableTeamSwitch = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"forceRotorLibSimulation (Arma 3 v1.34)","level":5,"markdown":"Force enable or disable RotorLib flight model.\n\n```cpp\nforceRotorLibSimulation = 1; // Default: 0\n```\n\n- 0 - based on player's options\n- 1 - enabled (advanced mode)\n- 2 - disabled (default flight mode)"},{"heading":"hostDoesNotSkipLobby (Arma 3 v2.06)","level":5,"markdown":"Stops hosting player from skipping the lobby if  is used\n\n```cpp\nhostDoesNotSkipLobby = 1;\n```"},{"heading":"joinUnassigned (Arma 3 v0.50)","level":5,"markdown":"By default a new player is not auto assigned a free playable slot in the mission lobby in Multiplayer.\nDisable this setting to make him auto assigned to the side with least players.\n\n```cpp\njoinUnassigned = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"minScore, avgScore, maxScore","level":5,"markdown":"Set minimum, average and maximum score for your mission.\nScore is related to the star display in the debriefing screen (OFP:CWC).\nThe score can be influenced during a missions progress by using the addRating command.\n\n```cpp\nminScore = 0;\navgScore = 1800;\nmaxScore = 75000;\n```\n\n> [!IMPORTANT]\n> Values have to follow this formula: **minScore < avgScore < maxScore**. Any other combinations can lead to game freeze upon mission end."},{"heading":"missionGroup (Arma 3 v2.10)","level":5,"markdown":"Shared mission group name to override default missionName used with missionProfileNamespace, saveMissionProfileNamespace\n\n```cpp\nmissionGroup = \"SomeNameDescribingCommonMissions\";\n```"},{"heading":"onCheat (Arma 3 v1.00)","level":5,"markdown":"Executes custom statement when player enters the GETALLGEAR cheat (see: GETALLGEAR).\n\n```cpp\nonCheat = \"hint str _this\";\n```"},{"heading":"onPauseScript (Arma 2: Operation Arrowhead v1.62)","level":5,"markdown":"Executes a custom SQF script or function in scheduled environment (execVM) when player brings up Game Pause screen (presses 'Esc' button).\nDisplay parameter of the resulting dialog is available via `_this select 0` inside the script.\n\n```cpp\nonPauseScript    = \"myOnPauseScript.sqf\";                            // file path\nonPauseScript[]    = { \"myOnPauseFunction1\", \"myOnPauseFunction2\" };    // function name - since Arma 3\n```\n\n> [!IMPORTANT]\n> The script or function executes **in its own namespace**. In order to get/set external global variable you need to explicitly use mission namespace:\n> **Set:**\n>\n> ```sqf\n> // myVar2 = \"345\";                                    // will set the variable only in onPauseScript namespace\n> missionNamespace setVariable [\"myVar2\", \"345\"];        // will be available as a global variable\n> ```\n>\n> **Get:**\n>\n> ```sqf\n> // hint str myVar;                                    // will raise an undefined variable myVar error\n> hint str (missionNamespace getVariable \"myVar\");    // will access the global variable properly\n> ```"},{"heading":"saving (Armed Assault v1.00)","level":5,"markdown":"Toggle saving possibility.\n\n```cpp\nsaving = 0; // 0: disabled - 1: enabled. Default: 1\n```"},{"heading":"scriptedPlayer (Take On Helicopters v1.00)","level":5,"markdown":"When scripted player is enabled, game no longer shows \"No player select\" error message upon mission start when no player unit is present.\n\n```cpp\nscriptedPlayer = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"skipLobby (Arma 3 v1.60)","level":5,"markdown":"When enabled, joining player will join the mission bypassing role selection screen.\nThe #joinUnassigned param will be set to 1 automatically, so that player receives first available role from mission template. When leaving such mission, player will go straight back to server browser.\n\n```cpp\nskipLobby = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"Server Security","level":3,"markdown":"This section underlines mission security settings for server. They can secure or break your mission, so be sure to use them wisely."},{"heading":"allowFunctionsLog (Arma 3 v0.50)","level":5,"markdown":"Allows functions to log to the RPT file.\n\n```cpp\nallowFunctionsLog = 1; // 0: disabled - 1: enabled. Default: ?\n```"},{"heading":"allowFunctionsRecompile (Arma 3 v1.00)","level":5,"markdown":"As a security measure, functions are by default protected against rewriting during mission.\nThis restriction does not apply in missions previewed from the editor.\n\n```cpp\nallowFunctionsRecompile = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"zeusCompositionScriptLevel (Arma 3 v2.06)","level":5,"markdown":"```cpp\nzeusCompositionScriptLevel = 0;    // 0: all scripts are forbidden\n                                // 1: only attributes are allowed (including custom attributes added by mods)\n                                // 2: all scripts are allowed including init scripts\n                                // Default: 1\n```"},{"heading":"CfgDisabledCommands (Arma 3 v1.66)","level":5,"markdown":"Define disabled script commands. See CfgDisabledCommands for more detailed explanations."},{"heading":"CfgRemoteExec (Arma 3 v1.50)","level":5,"markdown":"Define remoteExec and remoteExecCall restrictions. See CfgRemoteExec for more detailed explanations and examples."},{"heading":"Tasks","level":3,"markdown":"Tasks are part of the mission. This section deals with the settings for them.\n\nSee also Arma 3: Task Framework#Task Overhaul"},{"heading":"taskManagement_markers2D (Arma 3 v1.42)","level":5,"markdown":"Use new 2D markers.\n\n```cpp\ntaskManagement_markers2D = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"taskManagement_markers3D (Arma 3 v1.42)","level":5,"markdown":"Use new 3D markers.\n\n```cpp\ntaskManagement_markers3D = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"taskManagement_propagate (Arma 3 v1.42)","level":5,"markdown":"Propagate shared tasks to subordinates.\n\n```cpp\ntaskManagement_propagate = 1; // 0: disabled - 1: enabled. Default: 0\n```"},{"heading":"taskManagement_drawDist (Arma 3 v1.42)","level":5,"markdown":"3D marker maximum draw distance in meters. within this range, unassigned tasks are drawn on screen.\n\n```cpp\ntaskManagement_drawDist = 2500; // in meters. Default: 2000\n```"},{"heading":"CfgTasks (Armed Assault v1.00)","level":5,"markdown":"Agents task config\n\n```cpp\nclass CfgTasks\n{\n    class Default\n    {\n        name = \"\";\n        fsm = \"\";        // relative path to fsm file\n        condition = \"\";    // relative path to sqf file (compiled and stored for the duration of run time, executed frequently)\n        description = \"\";\n        destination = \"\";\n        resources[] = {};\n    };\n};\n```"},{"heading":"CfgTaskTypes (Arma 3 v1.54)","level":5,"markdown":"Define Task types and their icons.\n\n```cpp\nclass CfgTaskTypes\n{\n    class Attack\n    {\n        icon    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types\\Attack_ca.paa\";\n        icon3D    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types3D\\Attack_ca.paa\";\n    };\n\n    class Defend\n    {\n        icon    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types\\Defend_ca.paa\";\n        icon3D    = \"\\A3\\UI_F_MP_Mark\\Data\\Tasks\\Types3D\\Defend_ca.paa\";\n    };\n};\n```"},{"heading":"CfgTaskDescriptions (Arma 3 v1.12)","level":5,"markdown":"Define Task titles and descriptions.\n\n```cpp\nclass CfgTaskDescriptions\n{\n    class myTask1\n    {\n        title        = \"my task title\";\n        description    = \"my task description\";\n        marker        = \"my task destination marker\";\n    };\n\n    class myTask2\n    {\n        title        = \"STR_myTask2Title\";            // note the lack of $ sign here!\n        description    = \"STR_myTask2Description\";        // without $, it translates for each client\n        marker        = \"STR_myTask2Marker\";            // with $ everyone sees the server's language\n    };\n};\n```"},{"heading":"CfgTaskEnhancements (Arma 3 v1.42)","level":5,"markdown":"Defines tasks enhancements directly in a class.\n\n```cpp\nclass CfgTaskEnhancements\n{\n    enable        = 1; // 0: disable new task features (default), 1: enable new task features and add new task markers and task widgets into the map\n    3d            = 1; // 0: do not use new 3D markers (default), 1: replace task waypoints with new 3D markers\n    3dDrawDist    = 0; // 3d marker draw distance (default: 2000)\n    share        = 1; // 0: do not count assigned players (default), 1: count how many players have the task assigned\n    propagate    = 1; // 0: do not propagate (default), 1: propagate shared tasks to subordinates\n};\n```"},{"heading":"Custom Content Definition","level":3,"markdown":"The following class definitions allow for mission-defined content like sounds, music, or more advanced content like functions"},{"heading":"CfgCameraEffects","level":5,"markdown":"Configure custom cameraEffect.\n\n```cpp\nclass CfgCameraEffects\n{\n    class Array\n    {\n        class External\n        {\n            type = 0;\n            duration = 6;    // 3 seconds for some reason\n            file = \"\";        // some kind of custom .p3d file for camera\n        };\n\n        class AutoTerminate : External\n        {\n            type = 3;        // CamChained\n            chain[] = { \"External\", \"Terminate\" }; // Terminate will trigger after 3 seconds\n        };\n    };\n};\n```\n\nExample:\n\n```sqf\nshowCinemaBorder false;\nprivate _dur = getNumber (missionConfigFile >> \"CfgCameraEffects\" >> \"Array\" >> _this >> \"duration\");\nprivate _cam = \"camera\" camCreate (player modelToWorld [0, -100, 50]);\n_cam camSetTarget player;\n_cam camSetRelPos [0, -0.1, 1.8];\n_cam camCommit (_dur / 2);\n_cam cameraEffect [\"AutoTerminate\", \"Back\"];\nwaitUntil { camCommitted _cam };\ncamDestroy _cam;\n```"},{"heading":"CfgCommunicationMenu (Arma 3 v1.00)","level":5,"markdown":"This entry allows to add commanding menu option in the communication menu. See Arma 3: Communication Menu for more information."},{"heading":"CfgCommands (Arma 3 v1.50)","level":5,"markdown":"This entry contains a list of configurations for certain scripting commands (currently only `allowedHTMLLoadURIs` for htmlLoad, ctrlSetURL and menuSetURL).\nThis entry can be defined in Config.cpp or in a campaign or mission Description.ext; the most local variant is used.\n\n```cpp\nclass CfgCommands\n{\n    // Note that in case of clients connected to dedicated server, restrictions defined in its config have priority.\n    allowedHTMLLoadURIs[] +=\n    {\n        \"*.mywebsite.com\",\n        \"*.mywebsite2.com/something/*\",\n        // ...\n        \"*.mywebsiteN.com\"\n    };\n};\n```"},{"heading":"`allowedHTMLLoadURIs`","level":6,"markdown":"Defines a list of URIs that can be used with htmlLoad, ctrlSetURL and menuSetURL. Only URIs with the following protocols are supported:\n- HTTP (e.g. `http://example.com/`)\n- HTTPS (e.g. `https://example.com/`)\n- FTP (e.g. `ftp://ftp.example.com/`)\n- Gopher (e.g. `gopher://gopher.example.com/`)\n- Arma 3 v2.22 TeamSpeak 3 (e.g. `ts3server://ts3.example.com`)\n\nThe URIs support wildcards:\n- `-` matches any character zero or more times (e.g. `https://*.example.com/` matches `https://www.example.com/` and `https://files.example.com/`)\n- `?` matches any character exactly once (e.g. `https://example.com/?` matches `https://example.com/a` and `https://example.com/b`)\n\n> [!NOTE]\n> Some domains are automatically whitelisted, such as \"arma3.com\" or \"bistudio.com\".\n> This is a list of all patterns for whitelisted URLs in the engine:\n>\n> ```sqf\n> \"(ftp|http|https)://arma3\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.arma3\\\\.com/.*\"\n> \"(ftp|http|https)://bistudio\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.bistudio\\\\.com/.*\"\n> \"(ftp|http|https)://bohemia\\\\.net/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.bohemia\\\\.net/.*\"\n> \"(ftp|http|https)://armaplatform\\\\.com/.*\"\n> \"(ftp|http|https)://[a-zA-Z0-9]+\\\\.armaplatform\\\\.com/.*\"\n> \"(ftp|http|https)://store\\\\.steampowered\\\\.com/.*\"\n> \"https://steamcommunity\\\\.com/workshop/.*\"\n> ```"},{"heading":"CfgFunctions (Arma 2 v1.00)","level":5,"markdown":"Define functions for your mission. For a detailed explanation, see:\n\n|  |  |\n|---|---|\n| - Arma 3 v1.00 | Arma 3: Functions Library |\n| - Arma 2 v1.00 Arma 2: Operation Arrowhead v1.00 | Arma 2: Functions Library |\n| - Take On Helicopters v1.00 | Take On Helicopters: Functions Library |"},{"heading":"CfgHints (Arma 3 v1.00)","level":5,"markdown":"Define Advanced Hints (similar to the Field Manual ones). See Advanced Hints for more information."},{"heading":"CfgIdentities","level":5,"markdown":"Define the identities of individual units, you can specify the face, type of glasses worn, voice, tone of voice and name of an identity.\nYou then give a specific unit this identity by using the command setIdentity in the mission.\n\n> [!NOTE]\n> the `nameSound` entry is only valid since Arma 3. See setNameSound for possible values.\n\n```cpp\nclass CfgIdentities\n{\n    class MyLittleSoldier\n    {\n        name        = \"Givens\";\n        nameSound    = \"Givens\"; // Arma 3 only!\n        face        = \"whiteHead_06\";\n        glasses        = \"None\";\n        speaker        = \"Male05ENG\";\n        pitch        = 1.1;\n    };\n};\n```\n\nExample:\n\n```sqf\nplayer setIdentity \"MyLittleSoldier\";\n```\n\nSee CfgIdentities for more detailed information and valid options for face, glasses, speaker etc."},{"heading":"CfgLeaflets (Arma 3 v1.76)","level":5,"markdown":"Define leaflets for your missions. See Arma 3: Leaflets for more information."},{"heading":"CfgMusic","level":5,"markdown":"Defines music you can play with playMusic.\n\n```cpp\nclass CfgMusic\n{\n    tracks[] = {};\n    class MyIntro\n    {\n        // display name\n        name    = \"My intro music\";\n\n        // filename, volume, pitch\n        sound[]    = { \"\\music\\filename.ogg\", db + 0, 1.0 };\n    };\n    class Ludwig9\n    {\n        name    = \"Ludwig Van Beethoven's Ninth Symphony\";\n        sound[]    = { \"\\music\\ludwig9.ogg\", db + 10, 1.0 };\n    };\n};\n```\n\nExample:\n\n```sqf\nplayMusic \"MyIntro\";\n```\n\n> [!IMPORTANT]\n> Setting volume (db) of music far from zero will disable fadeMusic command. Optimal values are from -10 to 10."},{"heading":"CfgNotifications (Arma 3 v1.12)","level":5,"markdown":"Define custom notifications to be shown with BIS_fnc_showNotification. See Notification for more detailed information and examples."},{"heading":"CfgPostprocessTemplates (Arma 3 v1.00)","level":5,"markdown":"Define custom post-process effects, to Post Process Effects format (only \"colorCorrection\" and \"filmGrain\" are supported for now).\n\nTo be used with BIS_fnc_setPPeffectTemplate.\n\n```cpp\nclass CfgPostprocessTemplates\n{\n    class MyPurplePP\n    {\n        colorCorrections[] = { 1, 1, 0, { 1, 1, 1, 0 }, { 1, 0.5, 1, 0 }, { 0.75, 0.25, 0, 1 } };\n        displayName = \"Purple-ish!\";\n        filmGrain[] = { 0.04, 1, 1, 0, 1 };\n    };\n};\n```"},{"heading":"CfgRadio","level":5,"markdown":"Defines radio sentences you can play with these radio commands: customRadio, vehicleRadio, groupRadio, sideRadio, globalRadio.\n\n```cpp\nclass CfgRadio\n{\n    sounds[] = {};\n    class RadioMsg1\n    {\n        // display name\n        name    = \"\";\n\n        // filename, volume, pitch\n        sound[]    = { \"\\sound\\filename1.ogg\", db - 100, 1.0 };\n\n        // radio caption\n        title    = \"I am ready for your orders.\";\n    };\n\n    class RadioMsg2\n    {\n        name    = \"\";\n        sound[]    = { \"\\sound\\filename2\", db - 100, 1.0 }; // .wss implied\n        title    = \"$STR_RADIO_2\";\n    };\n};\n```\n\nExample:\n\n```sqf\nunit sideRadio \"RadioMsg2\";\n```"},{"heading":"CfgSentences","level":5,"markdown":"See Conversations for more information."},{"heading":"CfgSFX","level":5,"markdown":"See CfgSFX for more information."},{"heading":"CfgSounds","level":5,"markdown":"General sounds that can be used for dialog, voiceovers in the briefing etc.\n\nSee also commands playSound, say, say2D and say3D.\n\n```cpp\nclass CfgSounds\n{\n    sounds[] = {}; // OFP required it filled, now it can be empty or absent depending on the game's version\n\n    class wolf1\n    {\n        name = \"My wolf sound\";                        // display name\n        sound[] = { \"fx\\wolf1.ogg\", 1, 1, 100 };    // file, volume, pitch, maxDistance\n        titles[] = { 0, \"*wolf growls*\" };            // subtitles\n\n        titlesFont = \"LCD14\";        // OFP:R - titles font family\n        titlesSize = 0.1;            // OFP:R - titles font size\n\n        forceTitles = 1;            // Arma 3 - display titles even if global show titles option is off (1) or not (0)\n        titlesStructured = 1;        // Arma 3 - treat titles as Structured Text (1) or not (0)\n    };\n};\n```\n\n| Property | Description |\n|---|---|\n| sounds[] | *Was* required in previous titles, and needed to be filled with `CfgSounds` defined sounds at the beginning of Operation Flashpoint.<br>At least in Arma 3 the engine finds them without this value which can now be ignored entirely. |\n| name | (Optional) how the sound is referred to in the editor (e.g. name in trigger effects) this can be a translation (e.g `\"$STR_My_Translation\"`) |\n| sound[] | An array containing:<br>- file path: the relative path to the file<br>Since Arma 3 v1.50 the path can be prefixed with `@` in order to look directly into addon files, e.g `\"@a3\\Ui_F_Curator\\Data\\Sound\\CfgSound\\visionMode\"`<br>- volume: between 0 and 5, 1 being normal volume<br>> [!NOTE]<br>> Volume may at some point be found defined with **db** (e.g `db-40`). The formula for db-based volume is: `10^(*number* * (1/20))`.<br>- pitch: 1 is normal pitch, 2 = chipmunk, 0.5 = Darth Vader, etc<br>- max distance: (Optional, default `*volume* × 1000`) maximum distance at which the sound is heard, in metres |\n| titles[] | An array format `{ time1, text1, time2, text2 }` etc:<br>- time#: can be a number or an array:<br>  - number: sound time at which the text is displayed (2 = 2s after sound start)<br>  - array: format `{ displayTime, displayDurationFactor }`:<br>    - displayTime: sound time at which the text is displayed (2 = 2s after sound start)<br>    - displayDurationFactor: default value is 1 (for 10s subtitle display), 0.5 means half the time (5s), 2 means twice the time (20s) etc<br>- text#: the text to be displayed<br>> [!IMPORTANT]<br>> If a subtitle is timed for *after* the sound is done, the sound will repeat until the subtitle is played (then played until its end). |\n| Operation Flashpoint: Resistance v1.75 titlesFont | (Optional) titles font family |\n| Operation Flashpoint: Resistance v1.75 titlesSize | (Optional) titles font size |\n| Arma 3 v0.50 forceTitles | (Optional) if set to 1, will display titles even if global show titles option is off |\n| Arma 3 v0.50 titlesStructured | (Optional) if set to 1, treat titles as Structured Text (e.g `0, \"<t color=\"\"#ff0000\"\">Red text</t>\"`) |\n\nExample:\n\n```sqf\nplaySound \"wolf1\"; // class name as string\nplayer say [\"wolf1\", 100];\n```\n\n> [!NOTE]\n> See [OFP ToadLife's tutorial](http://ofp.toadlife.net/downloads/tutorials/tutorial_sound/tutorial_sound.html) for a sound advice."},{"heading":"CfgUnitInsignia (Arma 3 v1.24)","level":5,"markdown":"Define custom unit insignia (shoulder patches). See Arma 3: Unit Insignia for more detailed information.\n\n```cpp\nclass CfgUnitInsignia\n{\n    class 111thID\n    {\n        displayName = \"111th Infantry Division\";    // name displayed in Arsenal\n        author = \"Bohemia Interactive\";                // author displayed in Arsenal\n        texture = \"\\a3\\UI_F_Bootcamp\\Data\\CfgUnitInsignia\\B_111thID_texture_ca.paa\"; // image path\n        textureVehicle = \"\";                        // does nothing, was reserved for future use\n    };\n};\n```"},{"heading":"CfgUnitTemplates (Arma 3 v1.50)","level":5,"markdown":"This class is used to create units templates. For now, this is only used with the function BIS_fnc_unitHeadgear.\n\n```cpp\nclass CfgUnitTemplates\n{\n    // Classic selectRandom\n    class MyFirstTemplate : Default\n    {\n        headgearList[] =\n        {\n            \"H_Cap_blk\",\n            \"H_Cap_grn\",\n            \"H_Cap_oli_hs\"\n        };\n\n        facewearList[] =\n        {\n            \"G_Bandanna_beast\",\n            \"G_Bandanna_blk\",\n            \"G_Bandanna_khk\"\n        };\n    };\n\n    // the probabilities will be considered, weighted random\n    class MySecondTemplate : Default\n    {\n        headgearList[] =\n        {\n            \"H_Cap_blk\",    0.9,\n            \"H_Cap_grn\",    0.6,\n            \"H_Cap_oli_hs\",    0.55\n        };\n\n        facewearList[] =\n        {\n            \"G_Bandanna_beast\",    0.5,\n            \"G_Bandanna_blk\",    0.5,\n            \"G_Bandanna_khk\",    0.5\n        };\n    };\n};\n```\n\nExample:\n\n```sqf\n[myUnit, \"MyFirstTemplate\"]        call BIS_fnc_unitHeadgear;\n[myUnit, \"MySecondTemplate\"]    call BIS_fnc_unitHeadgear;\n```"},{"heading":"CfgVehicles (Arma 3 v1.70)","level":5,"markdown":"This class can only be used to create sound sources.\n\nSee also #CfgSFX for more detailed information.\n\n```cpp\nclass CfgVehicles\n{\n    class MyOwlSound        // class name to be used with createSoundSource\n    {\n        sound = \"MyOwl\";    // reference to CfgSFX class\n    };\n};\n```"},{"heading":"CfgVehicleTemplates (Arma 3 v1.42)","level":5,"markdown":"This class is used to create vehicle templates used by the Vehicle Customisation system.\n\n```cpp\nclass CfgVehicleTemplates\n{\n    class BIS_Offroad_01_default\n    {\n        displayName = \"Default\";\n        author = \"Bohemia Interactive\";\n        textureList[] =\n        {\n            \"guerilla_01\", 0.5,\n            \"guerilla_02\", 1\n        };\n\n        animationList[] =\n        {\n            \"HideBumper1\", 1,\n            \"HideBumper2\", 1\n        };\n    };\n};\n```"},{"heading":"RscTitles","level":5,"markdown":"This class is used to define custom HUDs. See Arma: GUI Configuration for more information."}],"categories":["Mission Editing"],"groups":["Scripting"]},{"name":"Diary Record","title":"Diary Record","type":"topic","url":"https://community.bistudio.com/wiki/Diary_Record","revid":340880,"updated":"2023-05-13T21:43:01Z","aliases":[],"markdown":"**Description:**\nA Diary Record is created by createDiaryRecord - introduced in Arma 2.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nA Diary Record is created by createDiaryRecord - introduced in Arma 2."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Display","title":"Display","type":"topic","url":"https://community.bistudio.com/wiki/Display","revid":149025,"updated":"2020-03-10T21:07:04Z","aliases":[],"markdown":"**Display** is a UI object that holds Dialogs and Controls. Similar to how controls are identified by IDCs, displays and dialogs are identified by IDDs. If the IDD is available, displays (and dialogs) can be accessed with findDisplay. The existence of a distinction between displays and dialogs becomes apparent at time of creation and closing. A display uses the functions createDisplay and closeDisplay, whereas a dialog uses createDialog and closeDialog.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance.","sections":[{"heading":null,"level":1,"markdown":"**Display** is a UI object that holds Dialogs and Controls. Similar to how controls are identified by IDCs, displays and dialogs are identified by IDDs. If the IDD is available, displays (and dialogs) can be accessed with findDisplay. The existence of a distinction between displays and dialogs becomes apparent at time of creation and closing. A display uses the functions createDisplay and closeDisplay, whereas a dialog uses createDialog and closeDialog.\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Editor Object","title":"Editor Object","type":"topic","url":"https://community.bistudio.com/wiki/Editor_Object","revid":295451,"updated":"2021-11-15T22:55:04Z","aliases":[],"markdown":"## Editor Object Type\n\n**Description:**\n\nEditor objects are used in *Offline Mission Editor* (VBS2) and *Real Time Editor* for an abstract representation of what is on the map.\n\nAn editor object is a String build this way: `\"_type_x\"`, with type being the editor object's type, e.g. \"unit\", and x being the reference number. For example `\"_unit_1\"`, `\"_artillery_23\"`, `\"_marker_4\"`.\n\nIntroduced with Virtual Battlespace 2, does not refer to Operation Flashpoint, Operation Flashpoint: Resistance or Armed Assault.","sections":[{"heading":"Editor Object Type","level":2,"markdown":"**Description:**\n\nEditor objects are used in *Offline Mission Editor* (VBS2) and *Real Time Editor* for an abstract representation of what is on the map.\n\nAn editor object is a String build this way: `\"_type_x\"`, with type being the editor object's type, e.g. \"unit\", and x being the reference number. For example `\"_unit_1\"`, `\"_artillery_23\"`, `\"_marker_4\"`.\n\nIntroduced with Virtual Battlespace 2, does not refer to Operation Flashpoint, Operation Flashpoint: Resistance or Armed Assault."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Event Scripts","title":"Event Scripts","type":"topic","url":"https://community.bistudio.com/wiki/Event_Scripts","revid":377939,"updated":"2026-01-11T17:03:24Z","aliases":["Event based scripts","Init.sqs","Initintro.sqs","init.sqf","init.sqs","onPlayerRespawn.sqf"],"markdown":"__NOTOC____NOEDITSECTION__\n\n|  |  |  |\n|---|---|---|\n| + Default Scripts Location | Game | Path |\n| Operation Flashpoint v1.00 | `DTA/scripts.pbo` |  |\n| Armed Assault v1.00 | `Ca.pbo/data/scripts` |  |\n| Arma 2 v1.00 |  |  |\n| Arma 2: Operation Arrowhead v1.50 |  |  |\n| Arma 3 v1.00 | `functions_f.pbo/scripts` |  |\n| Take On Helicopters v1.00 | `data_h.pbo/data/scripts` |  |\n\nEvent Scripts are scripts that are executed upon specific events. Not all event scripts are executed directly by the engine.\n\nTo use an Event Script, create a file of the given name in the mission directory.\n\n| init* scripts | (on)Player* scripts | Other Scripts |\n|---|---|---|\n| - #init.sqf<br>- #init.sqs<br>- #init3DEN.sqf<br>- #initIntro.sqf<br>- #initIntro.sqs<br>- #initJIPcompatible.sqf<br>- #initPlayerLocal.sqf<br>- #initPlayerServer.sqf<br>- #initServer.sqf | - #onPlayerKilled.sqf<br>- #onPlayerKilled.sqs<br>- #onPlayerRespawn.sqf<br>- #onPlayerRespawn.sqs<br>- #onPlayerRespawnAsSeagull.sqs<br>- #onPlayerRespawnOtherUnit.sqs<br>- #onPlayerResurrect.sqs<br>- #playerKilledScript.sqs<br>- #playerRespawnScript.sqs<br>- #playerRespawnSeagullScript.sqs<br>- #playerRespawnOtherUnit.sqs<br>- #playerResurrectScript.sqs | - #exit.sqf<br>- #exit.sqs<br>- #missionFlow.fsm<br>- #onFlare.sqs<br>- #pauseOnLoad.sqf<br>- #teamSwitchScript.sqs |\n\n> [!NOTE]\n> - See Initialisation Order to learn when initialisation scripts are executed.\n> - Additional initialisation scripts can be executed using functions with preInit or postInit attribute.\n\n### Available Scripts\n\n| File | Present in | Details |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|\n| Operation Flashpoint v1.00 | Operation Flashpoint: Resistance v1.75 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Arma 3 v1.00 | Take On Helicopters v1.00 | Can suspend |  |\n| #### exit.sqf<br>Executed when mission is finished (before debriefing screen).<br>In Arma 3, see also \"Ended\" and \"MPEnded\" Mission Event Handlers.<br>```sqf<br>params [\"_endType\"];<br>```<br>- endType: String |  |  |  | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### exit.sqs<br>Executed when mission is finished (before debriefing screen).<br>In Arma 3, see also \"Ended\" and \"MPEnded\" Mission Event Handlers.<br>```sqf<br>params [\"_endType\"];<br>```<br>- endType: String |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### init.sqf<br>Executed when mission is started (before briefing screen). |  |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### init.sqs<br>Executed when mission is started (before briefing screen). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### init3DEN.sqf<br>Executed when loading a scenario in Eden Editor if the file is present. Useful for executing scenario-specific editor functionality. |  |  |  |  |  | ✓ |  | ✗ |\n| #### initIntro.sqf<br>Executed when intro, outro win or outro lose is started.<br>> [!NOTE]<br>> **Arma 3:** Functional in Arma 3 only for intro. |  |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### initIntro.sqs<br>Executed when intro, outro win or outro lose is started.<br>> [!NOTE]<br>> **Arma 3:** Functional in Arma 3 only for intro. |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### initJIPcompatible.sqf<br>Executed locally by Arma 2: Multiplayer Framework when a player joins mission (includes both mission start and JIP). Also executed locally on server at mission start. |  |  |  | ✓ | ✓ |  |  |  |\n| #### initPlayerLocal.sqf<br>Executed locally when player joins mission (includes both mission start and JIP). See Initialisation Order for details about when exactly the script is executed.<br>```sqf<br>params [\"_player\", \"_didJIP\"];<br>```<br>- player: Object<br>- didJIP: Boolean |  |  |  |  |  | ✓ |  | ✓ |\n| #### initPlayerServer.sqf<br>Executed only on server when a player joins mission (includes both mission start and JIP). See Initialisation Order for details about when exactly the script is executed.<br>This script relies on BIS_fnc_execVM and remoteExec. If CfgRemoteExec's `class Functions` is set to mode = 0 or 1, the script will never be executed.<br>Therefore, `initPlayerServer.sqf` should be avoided - use [this method](https://www.reddit.com/r/armadev/comments/8fkitd/initplayerserversqf_therefore_initplayerserversqf/dy5k5pf/) instead.<br>```sqf<br>params [\"_playerUnit\", \"_didJIP\"];<br>```<br>- playerUnit: Object<br>- didJIP: Boolean |  |  |  |  |  | ✓ |  | ✓ |\n| #### initServer.sqf<br>Executed only on server when mission is started. See Initialisation Order for details about when exactly the script is executed. |  |  |  |  |  | ✓ |  | ✓ |\n| #### missionFlow.fsm<br>Executed on post-init when mission is started. See BIS_fnc_missionFlow. |  |  |  |  |  | ✓ |  |  |\n| #### onFlare.sqs<br>Executed when a flare is lit after being fired from grenade launcher.<br>```sqf<br>params [\"_colorRGB\", \"_shooter\", \"_projectile\", \"_instigator\"];<br>```<br>- colorRGB: Color (RGBA)<br>- shooter: Object<br>- Arma 3 v2.10 projectile: Object - the flare itself<br>- Arma 3 v2.18 instigator: Object - shot instigator |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### onPlayerKilled.sqf<br>Executed when player is killed in singleplayer or in multiplayer mission.<br>```sqf<br>params [\"_oldUnit\", \"_killer\", \"_respawn\", \"_respawnDelay\"];<br>```<br>- oldUnit: Object<br>- killer: Object<br>- respawnType: Number<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  | ✓ |\n| #### onPlayerKilled.sqs<br>Executed when player is killed in singleplayer or in multiplayer mission with \"NONE\" respawn type.<br>```sqf<br>params [\"_player\", \"_killer\"];<br>```<br>- player: Object<br>- killer: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerRespawn.sqf<br>Executed locally when player respawns in a multiplayer mission.<br>This event script will also fire at the beginning of a mission if respawnOnStart is 0 or 1, oldUnit will be objNull in this instance.<br>This script will not fire at mission start if respawnOnStart equals -1.<br>```sqf<br>params [\"_newUnit\", \"_oldUnit\", \"_respawn\", \"_respawnDelay\"];<br>```<br>- newUnit: Object<br>- oldUnit: Object<br>- respawnType: Number<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  | ✓ |\n| #### onPlayerRespawn.sqs<br>Executed when player is killed in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if *dta\\scripts\\onPlayerRespawn.sqs* does not exist.<br>```sqf<br>params [\"_player\", \"_killer\", \"_respawnDelay\"];<br>```<br>- player: Object<br>- killer: Object<br>- respawnDelay: Number |  | ✓ |  |  |  |  |  |  |\n| #### onPlayerRespawnAsSeagull.sqs<br>Executed when player is killed in multiplayer mission with \"SEAGULL\" respawn type, or when the type is \"GROUP\" or \"SIDE\", but no remaining respawn slots are left.<br>This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerRespawnAsSeagull.sqs` was renamed to `1. playerRespawnSeagullScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_seagull\"];<br>```<br>- player: Object<br>- killer: Object<br>- seagull: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerRespawnOtherUnit.sqs<br>Executed when player is killed in multiplayer mission with \"GROUP\" or \"SIDE\" respawn type. This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerRespawnOtherUnit.sqs` was renamed to `1. playerRespawnOtherUnit.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_newUnit\"];<br>```<br>- player: Object<br>- killer: Object<br>- newUnit: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerResurrect.sqs<br>Executed when player is respawned in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if `dta\\scripts\\onPlayerResurrect.sqs` does not exist.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerResurrect.sqs` was renamed to `1. playerResurrectScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\"];<br>```<br>- player: Object |  | ✓ |  |  |  | ✗ |  |  |\n| #### pauseOnLoad.sqf<br>Executed when pause menu is activated.<br>To make it work in MP or Arma 3, use `onPauseScript = \"pauseOnLoad.sqf\";` in Description.ext.<br>```sqf<br>params [\"_pauseMenuDisplay\"];<br>```<br>- pauseMenuDisplay: Display |  |  |  | ✓ | ✓ |  | ✓ | ✓ |\n| #### playerKilledScript.sqs<br>Executed locally when player is killed in singleplayer or in multiplayer mission with \"NONE\" respawn type.<br>Overrides default behavior of mission death screen in single player. Game may become unplayable if not scripted correctly. Avoid use if not experienced with this script.<br>```sqf<br>params [\"_player\", \"_killer\"];<br>```<br>- player: Object<br>- killer: Object |  |  |  |  |  | ✓ |  |  |\n| #### playerRespawnScript.sqs<br>Executed locally and immediately when player is killed in multiplayer mission with \"BASE\" or \"INSTANT\" respawn type.<br>Overrides default behavior of multiplayer respawn. Game may become unplayable if not scripted correctly. Avoid use if not experienced with this script.<br>```sqf<br>params [\"_player\", \"_killer\", \"_respawnDelay\"];<br>```<br>- player: Object<br>- killer: Object<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  |  |\n| #### playerRespawnSeagullScript.sqs<br>Executed when player is killed in multiplayer mission with \"SEAGULL\" respawn type, or when the type is \"GROUP\" or \"SIDE\", but no remaining respawn slots are left.<br>This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerRespawnAsSeagull.sqs` was renamed to `playerRespawnSeagullScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_seagull\"];<br>```<br>- player: Object<br>- killer: Object<br>- seagull: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### playerRespawnOtherUnit.sqs<br>Executed when player is killed in multiplayer mission with \"GROUP\" or \"SIDE\" respawn type. This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerRespawnOtherUnit.sqs` was renamed to `playerRespawnOtherUnit.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_newUnit\"];<br>```<br>- player: Object<br>- killer: Object<br>- newUnit: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### playerResurrectScript.sqs<br>Executed when player is respawned in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if `dta\\scripts\\onPlayerResurrect.sqs` does not exist.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerResurrect.sqs` was renamed to `playerResurrectScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\"];<br>```<br>- player: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### teamSwitchScript.sqs<br>Executed *after* a Team Switch is done. **Not** triggered by selectPlayer.<br>```sqf<br>params [\"_oldUnit\", \"_newUnit\"];<br>```<br>- oldUnit: Object<br>- newUnit: Object | ✗ |  |  |  |  | ✓ |  |  |","sections":[{"heading":null,"level":1,"markdown":"__NOTOC____NOEDITSECTION__\n\n|  |  |  |\n|---|---|---|\n| + Default Scripts Location | Game | Path |\n| Operation Flashpoint v1.00 | `DTA/scripts.pbo` |  |\n| Armed Assault v1.00 | `Ca.pbo/data/scripts` |  |\n| Arma 2 v1.00 |  |  |\n| Arma 2: Operation Arrowhead v1.50 |  |  |\n| Arma 3 v1.00 | `functions_f.pbo/scripts` |  |\n| Take On Helicopters v1.00 | `data_h.pbo/data/scripts` |  |\n\nEvent Scripts are scripts that are executed upon specific events. Not all event scripts are executed directly by the engine.\n\nTo use an Event Script, create a file of the given name in the mission directory.\n\n| init* scripts | (on)Player* scripts | Other Scripts |\n|---|---|---|\n| - #init.sqf<br>- #init.sqs<br>- #init3DEN.sqf<br>- #initIntro.sqf<br>- #initIntro.sqs<br>- #initJIPcompatible.sqf<br>- #initPlayerLocal.sqf<br>- #initPlayerServer.sqf<br>- #initServer.sqf | - #onPlayerKilled.sqf<br>- #onPlayerKilled.sqs<br>- #onPlayerRespawn.sqf<br>- #onPlayerRespawn.sqs<br>- #onPlayerRespawnAsSeagull.sqs<br>- #onPlayerRespawnOtherUnit.sqs<br>- #onPlayerResurrect.sqs<br>- #playerKilledScript.sqs<br>- #playerRespawnScript.sqs<br>- #playerRespawnSeagullScript.sqs<br>- #playerRespawnOtherUnit.sqs<br>- #playerResurrectScript.sqs | - #exit.sqf<br>- #exit.sqs<br>- #missionFlow.fsm<br>- #onFlare.sqs<br>- #pauseOnLoad.sqf<br>- #teamSwitchScript.sqs |\n\n> [!NOTE]\n> - See Initialisation Order to learn when initialisation scripts are executed.\n> - Additional initialisation scripts can be executed using functions with preInit or postInit attribute."},{"heading":"Available Scripts","level":3,"markdown":"| File | Present in | Details |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|\n| Operation Flashpoint v1.00 | Operation Flashpoint: Resistance v1.75 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Arma 3 v1.00 | Take On Helicopters v1.00 | Can suspend |  |\n| #### exit.sqf<br>Executed when mission is finished (before debriefing screen).<br>In Arma 3, see also \"Ended\" and \"MPEnded\" Mission Event Handlers.<br>```sqf<br>params [\"_endType\"];<br>```<br>- endType: String |  |  |  | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### exit.sqs<br>Executed when mission is finished (before debriefing screen).<br>In Arma 3, see also \"Ended\" and \"MPEnded\" Mission Event Handlers.<br>```sqf<br>params [\"_endType\"];<br>```<br>- endType: String |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### init.sqf<br>Executed when mission is started (before briefing screen). |  |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### init.sqs<br>Executed when mission is started (before briefing screen). | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### init3DEN.sqf<br>Executed when loading a scenario in Eden Editor if the file is present. Useful for executing scenario-specific editor functionality. |  |  |  |  |  | ✓ |  | ✗ |\n| #### initIntro.sqf<br>Executed when intro, outro win or outro lose is started.<br>> [!NOTE]<br>> **Arma 3:** Functional in Arma 3 only for intro. |  |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| #### initIntro.sqs<br>Executed when intro, outro win or outro lose is started.<br>> [!NOTE]<br>> **Arma 3:** Functional in Arma 3 only for intro. |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### initJIPcompatible.sqf<br>Executed locally by Arma 2: Multiplayer Framework when a player joins mission (includes both mission start and JIP). Also executed locally on server at mission start. |  |  |  | ✓ | ✓ |  |  |  |\n| #### initPlayerLocal.sqf<br>Executed locally when player joins mission (includes both mission start and JIP). See Initialisation Order for details about when exactly the script is executed.<br>```sqf<br>params [\"_player\", \"_didJIP\"];<br>```<br>- player: Object<br>- didJIP: Boolean |  |  |  |  |  | ✓ |  | ✓ |\n| #### initPlayerServer.sqf<br>Executed only on server when a player joins mission (includes both mission start and JIP). See Initialisation Order for details about when exactly the script is executed.<br>This script relies on BIS_fnc_execVM and remoteExec. If CfgRemoteExec's `class Functions` is set to mode = 0 or 1, the script will never be executed.<br>Therefore, `initPlayerServer.sqf` should be avoided - use [this method](https://www.reddit.com/r/armadev/comments/8fkitd/initplayerserversqf_therefore_initplayerserversqf/dy5k5pf/) instead.<br>```sqf<br>params [\"_playerUnit\", \"_didJIP\"];<br>```<br>- playerUnit: Object<br>- didJIP: Boolean |  |  |  |  |  | ✓ |  | ✓ |\n| #### initServer.sqf<br>Executed only on server when mission is started. See Initialisation Order for details about when exactly the script is executed. |  |  |  |  |  | ✓ |  | ✓ |\n| #### missionFlow.fsm<br>Executed on post-init when mission is started. See BIS_fnc_missionFlow. |  |  |  |  |  | ✓ |  |  |\n| #### onFlare.sqs<br>Executed when a flare is lit after being fired from grenade launcher.<br>```sqf<br>params [\"_colorRGB\", \"_shooter\", \"_projectile\", \"_instigator\"];<br>```<br>- colorRGB: Color (RGBA)<br>- shooter: Object<br>- Arma 3 v2.10 projectile: Object - the flare itself<br>- Arma 3 v2.18 instigator: Object - shot instigator |  | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |  |\n| #### onPlayerKilled.sqf<br>Executed when player is killed in singleplayer or in multiplayer mission.<br>```sqf<br>params [\"_oldUnit\", \"_killer\", \"_respawn\", \"_respawnDelay\"];<br>```<br>- oldUnit: Object<br>- killer: Object<br>- respawnType: Number<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  | ✓ |\n| #### onPlayerKilled.sqs<br>Executed when player is killed in singleplayer or in multiplayer mission with \"NONE\" respawn type.<br>```sqf<br>params [\"_player\", \"_killer\"];<br>```<br>- player: Object<br>- killer: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerRespawn.sqf<br>Executed locally when player respawns in a multiplayer mission.<br>This event script will also fire at the beginning of a mission if respawnOnStart is 0 or 1, oldUnit will be objNull in this instance.<br>This script will not fire at mission start if respawnOnStart equals -1.<br>```sqf<br>params [\"_newUnit\", \"_oldUnit\", \"_respawn\", \"_respawnDelay\"];<br>```<br>- newUnit: Object<br>- oldUnit: Object<br>- respawnType: Number<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  | ✓ |\n| #### onPlayerRespawn.sqs<br>Executed when player is killed in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if *dta\\scripts\\onPlayerRespawn.sqs* does not exist.<br>```sqf<br>params [\"_player\", \"_killer\", \"_respawnDelay\"];<br>```<br>- player: Object<br>- killer: Object<br>- respawnDelay: Number |  | ✓ |  |  |  |  |  |  |\n| #### onPlayerRespawnAsSeagull.sqs<br>Executed when player is killed in multiplayer mission with \"SEAGULL\" respawn type, or when the type is \"GROUP\" or \"SIDE\", but no remaining respawn slots are left.<br>This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerRespawnAsSeagull.sqs` was renamed to `1. playerRespawnSeagullScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_seagull\"];<br>```<br>- player: Object<br>- killer: Object<br>- seagull: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerRespawnOtherUnit.sqs<br>Executed when player is killed in multiplayer mission with \"GROUP\" or \"SIDE\" respawn type. This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerRespawnOtherUnit.sqs` was renamed to `1. playerRespawnOtherUnit.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_newUnit\"];<br>```<br>- player: Object<br>- killer: Object<br>- newUnit: Object | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ |  |\n| #### onPlayerResurrect.sqs<br>Executed when player is respawned in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if `dta\\scripts\\onPlayerResurrect.sqs` does not exist.<br>> [!NOTE]<br>> **Arma 3:** `onPlayerResurrect.sqs` was renamed to `1. playerResurrectScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\"];<br>```<br>- player: Object |  | ✓ |  |  |  | ✗ |  |  |\n| #### pauseOnLoad.sqf<br>Executed when pause menu is activated.<br>To make it work in MP or Arma 3, use `onPauseScript = \"pauseOnLoad.sqf\";` in Description.ext.<br>```sqf<br>params [\"_pauseMenuDisplay\"];<br>```<br>- pauseMenuDisplay: Display |  |  |  | ✓ | ✓ |  | ✓ | ✓ |\n| #### playerKilledScript.sqs<br>Executed locally when player is killed in singleplayer or in multiplayer mission with \"NONE\" respawn type.<br>Overrides default behavior of mission death screen in single player. Game may become unplayable if not scripted correctly. Avoid use if not experienced with this script.<br>```sqf<br>params [\"_player\", \"_killer\"];<br>```<br>- player: Object<br>- killer: Object |  |  |  |  |  | ✓ |  |  |\n| #### playerRespawnScript.sqs<br>Executed locally and immediately when player is killed in multiplayer mission with \"BASE\" or \"INSTANT\" respawn type.<br>Overrides default behavior of multiplayer respawn. Game may become unplayable if not scripted correctly. Avoid use if not experienced with this script.<br>```sqf<br>params [\"_player\", \"_killer\", \"_respawnDelay\"];<br>```<br>- player: Object<br>- killer: Object<br>- respawnDelay: Number |  |  |  |  |  | ✓ |  |  |\n| #### playerRespawnSeagullScript.sqs<br>Executed when player is killed in multiplayer mission with \"SEAGULL\" respawn type, or when the type is \"GROUP\" or \"SIDE\", but no remaining respawn slots are left.<br>This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerRespawnAsSeagull.sqs` was renamed to `playerRespawnSeagullScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_seagull\"];<br>```<br>- player: Object<br>- killer: Object<br>- seagull: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### playerRespawnOtherUnit.sqs<br>Executed when player is killed in multiplayer mission with \"GROUP\" or \"SIDE\" respawn type. This script will replace the default respawn sequence.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerRespawnOtherUnit.sqs` was renamed to `playerRespawnOtherUnit.sqs` in Arma 3.<br>```sqf<br>params [\"_player\", \"_killer\", \"_newUnit\"];<br>```<br>- player: Object<br>- killer: Object<br>- newUnit: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### playerResurrectScript.sqs<br>Executed when player is respawned in multiplayer mission with \"INSTANT\" or \"BASE\" respawn type. It will not work if `dta\\scripts\\onPlayerResurrect.sqs` does not exist.<br>> [!NOTE]<br>> **Arma 3:** `1. onPlayerResurrect.sqs` was renamed to `playerResurrectScript.sqs` in Arma 3.<br>```sqf<br>params [\"_player\"];<br>```<br>- player: Object | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |  |\n| #### teamSwitchScript.sqs<br>Executed *after* a Team Switch is done. **Not** triggered by selectPlayer.<br>```sqf<br>params [\"_oldUnit\", \"_newUnit\"];<br>```<br>- oldUnit: Object<br>- newUnit: Object | ✗ |  |  |  |  | ✓ |  |  |"}],"categories":["Event Handlers","Mission Editing","Scripting Topics"],"groups":["Scripting"]},{"name":"Expression","title":"Expression","type":"topic","url":"https://community.bistudio.com/wiki/Expression","revid":337051,"updated":"2023-01-10T14:32:59Z","aliases":["expression"],"markdown":"An **expression** is a piece of code that returns a value.\n\n### Expression Types\n\nAn expression can be:\n\n- variable\n- operation\n- scripting command\n- control structure\n\n#### Variable\n\nAn expression can be a simple variable (identifier):\n\n**Examples:**\n\n```sqs\n_myVariable\nglobalVariable\n```\n\n#### Operation\n\nAn expression can be an operation including its operands.\n\n**Examples:**\n\n```sqs\n5 * 6\na % 2\nb * c\n```\n\n#### Scripting Command\n\nAn expression can be a scripting command returning a value including its arguments.\n\n**Examples:**\n\n```sqs\ncount myArray\nposition unit1\n```\n\n#### Control Structure\n\nAn expression can be a control structure returning a value.\n\n**Examples:**\n\n```sqs\n; returns myValueA or myValueB\nif (myCondition) then { myValueA } else { myValueB }\n```","sections":[{"heading":null,"level":1,"markdown":"An **expression** is a piece of code that returns a value."},{"heading":"Expression Types","level":3,"markdown":"An expression can be:\n\n- variable\n- operation\n- scripting command\n- control structure"},{"heading":"Variable","level":4,"markdown":"An expression can be a simple variable (identifier):\n\n**Examples:**\n\n```sqs\n_myVariable\nglobalVariable\n```"},{"heading":"Operation","level":4,"markdown":"An expression can be an operation including its operands.\n\n**Examples:**\n\n```sqs\n5 * 6\na % 2\nb * c\n```"},{"heading":"Scripting Command","level":4,"markdown":"An expression can be a scripting command returning a value including its arguments.\n\n**Examples:**\n\n```sqs\ncount myArray\nposition unit1\n```"},{"heading":"Control Structure","level":4,"markdown":"An expression can be a control structure returning a value.\n\n**Examples:**\n\n```sqs\n; returns myValueA or myValueB\nif (myCondition) then { myValueA } else { myValueB }\n```"}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"For Type","title":"For Type","type":"topic","url":"https://community.bistudio.com/wiki/For_Type","revid":245328,"updated":"2021-02-10T23:45:38Z","aliases":[],"markdown":"**Description:**\nThis type handles 'For' cycles.\n\n**Usage of this type:**\n\nfor \"_var\" from :expr: to :expr: [step <expr>] do {..code..};\n\n**Second usage:**\n\nfor [\":initPhase:\",\":condition:\",\":updatePhase:\"] do {...code...};\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance.\n\n### See Also\n\nfor, Control Structures","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nThis type handles 'For' cycles.\n\n**Usage of this type:**\n\nfor \"_var\" from :expr: to :expr: [step <expr>] do {..code..};\n\n**Second usage:**\n\nfor [\":initPhase:\",\":condition:\",\":updatePhase:\"] do {...code...};\n\nIntroduced with Armed Assault, does not refer to Cold War Crisis or Resistance."},{"heading":"See Also","level":3,"markdown":"for, Control Structures"}],"categories":["Syntactical Helper Types"],"groups":["Data Types"]},{"name":"Group","title":"Group","type":"topic","url":"https://community.bistudio.com/wiki/Group","revid":330390,"updated":"2022-09-05T21:46:56Z","aliases":[],"markdown":"A group is its own data type in the scripting language. All units belong to a group. If units are linked together in the editor, they are all part of the same group. If a unit is not linked to anyone else, then it belongs to its own group.\n\n- The AI makes many decisions as an entire group, instead of on an individual unit level. For example, behavior, combat mode, and waypoints are decided on a group, not an individual level.\n- Note that empty objects do not belong to a group. Nor do empty vehicles.\n- To get the group that a unit belongs to, use the group command.\n- To get the unit that currently leads a group, use the leader command.\n- To get an array of units that are in a group, use the units command.\n\n|  |  |  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|\n| Game | Operation Flashpoint v1.00 | Operation Flashpoint: Elite v1.00 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Take On Helicopters v1.00 | Arma 3 v1.00 | Arma 3 v1.68 |\n| Max. No. of Groups per Side | 63 | 144 | 288 |  |  |  |  |  |\n| Max. No. of Units per Group | 12 | ? | 10000+ |  |  |  |  |  |","sections":[{"heading":null,"level":1,"markdown":"A group is its own data type in the scripting language. All units belong to a group. If units are linked together in the editor, they are all part of the same group. If a unit is not linked to anyone else, then it belongs to its own group.\n\n- The AI makes many decisions as an entire group, instead of on an individual unit level. For example, behavior, combat mode, and waypoints are decided on a group, not an individual level.\n- Note that empty objects do not belong to a group. Nor do empty vehicles.\n- To get the group that a unit belongs to, use the group command.\n- To get the unit that currently leads a group, use the leader command.\n- To get an array of units that are in a group, use the units command.\n\n|  |  |  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|\n| Game | Operation Flashpoint v1.00 | Operation Flashpoint: Elite v1.00 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Take On Helicopters v1.00 | Arma 3 v1.00 | Arma 3 v1.68 |\n| Max. No. of Groups per Side | 63 | 144 | 288 |  |  |  |  |  |\n| Max. No. of Units per Group | 12 | ? | 10000+ |  |  |  |  |  |"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"HashMap","title":"HashMap","type":"topic","url":"https://community.bistudio.com/wiki/HashMap","revid":339000,"updated":"2023-04-24T16:22:14Z","aliases":[],"markdown":"Arma 3 v2.02\n\nA **HashMap** is a specialized data structure that contains key-value pairs.\n\nHashMaps provide (near) constant-time lookup for keys, making them highly efficient at finding the value associated with a specific key - even if there is a very large amount of keys.\n\nSee [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) to learn more about the underlying technology.\n\nWhile HashMaps and Arrays share many traits (and SQF command names), there are important differences and HashMaps must not be considered as some sort of new or improved replacement for the Array.\n\n### HashMap Basics\n\nThis section introduces the HashMap and its features and is intended to help create a basic understanding of what HashMaps are and what they can be used for.\n\n#### Comparison with Arrays\n\nThe HashMap and the Array are both data structures that are used to store multiple elements. Arrays are simple and only store single elements, one after the other, while HashMaps store key-value pairs, where each key uniquely identifies a single value.\n\nUnlike Arrays, HashMaps have no order, i.e. there is no such thing as a first, second, third or last element in a HashMap. As such, the # and select commands can not be used with HashMaps. This also means that the order in which the forEach-loop processes a HashMap's key-value pairs is not deterministic.\n\nIterating over all elements in a HashMap is less efficient than doing the same in an Array.\n\n#### Constant-time Key Lookup\n\nHashMaps are specifically designed for (near) constant-time lookup of keys.\n\nConsider the following example to understand what that means: Let's say we have an Array that looks like this:\n\n```sqf\nprivate _playerDataArray = [[\"Player_A_UID\", \"Data A-1\", \"Data A-2\" /*, ... */], [\"Player_B_UID\", \"Data B-1\", \"Data B-2\" /*, ... */], [\"Player_C_UID\", \"Data C-1\", \"Data C-2\" /*, ... */] /*, ... */];\n```\n\nWe want to find a specific UID so that we can retrieve the corresponding data. We can easily achieve that using the findIf command:\n\n```sqf\n_index = _playerDataArray findIf {_x # 0 isEqualTo \"Wanted_UID\"};\n_data = _playerDataArray # _index;\n```\n\nBut what findIf actually does for us is something like this:\n\n```sqf\n{\n    if (_x # 0 isEqualTo \"Wanted_UID\") then\n    {\n        breakWith _forEachIndex;\n    };\n} forEach _playerDataArray;\n```\n\nNow consider how many isEqualTo comparisons this forEach-loop has to perform: If the element identified by \"Wanted_UID\" is stored at or near the end of `_playerDataArray`, then our code has to go through (almost) the entire Array to find it - and the same is the case if the element we are looking for does not exist in our Array.\n\nEvery single one of these comparisons takes some time - not much, but it will add up eventually. This is no problem as long as our Array is relatively small, but it becomes a serious issue when the Array starts growing: If there are 10,000 elements in the Array that means up to 10,000 comparisons might be necessary just to find a single element, if there are 100,000 elements that means up to 100,000 comparisons and so on - the amount of steps and time needed to find an element grows linearly with the Array size.\n\nAnd this is where HashMaps come in. Simply put: When a key-value pair is inserted into a HashMap, a hash function is applied to the key to determine the position at which the key-value pair is going to be stored. Then, when we want to retrieve the value associated with a specific key, the same hash function (Arma 3 uses [FNV-1a 64-bit](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function)) is applied to that key and the resulting position tells the HashMap exactly where to find the key-value pair that we are looking for.\n\n```sqf\nprivate _data = _playerDataHashMap get \"Wanted_UID\";\n```\n\nSince the process to find a given key-value pair is always the same (apply hash function, look at the resulting position, return the value that is stored there), it also always takes (more or less) the same amount of time - regardless of the size of the HashMap.\n\nThat is what constant-time lookup for keys means. And it comes with very useful benefits: The procedures to search for, retrieve, modify or remove a specific element can all be completed in constant time; whether the HashMap contains 10, 10,000 or 1,000,000 elements does not matter.\n\n### Working with HashMaps\n\n#### Supported Key Types\n\nBecause of the requirement for the keys to be hashable (and constant), not all Data Types can be used as keys.\n\nSupported types are limited to:\n- Array\n- Boolean\n- Code\n- Config\n- Namespace\n- NaN\n- Number\n- Side\n- String\n\n> [!IMPORTANT]\n> - For some unsupported key types, such as Objects, a workaround can be used. See Unsupported Key Types.\n> - Array keys can only contain supported types.\n> - Array keys are deep-copied on insertion and cannot be modified when retrieved via keys or inside forEach.\n> - The virtual type HashMapKey is a combination of all the supported types.\n\n#### Creating a HashMap\n\n```sqf\n// example of an empty HashMap:\nprivate _myMap = createHashMap;\ncount _myMap; // returns 0\n\n// example of a prefilled HashMap:\nprivate _myFilledMap = createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\", 3]];\ncount _myFilledMap; // returns 3\n```\n\n#### Setting an element\n\n```sqf\nprivate _myMap = createHashMap;\n_myMap set [1, \"hello there\"]; // _myMap is [[1, \"hello there\"]]\n```\n\nInserting an element with a key that already exists inside the HashMap will overwrite the existing key.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _overwritten = _myMap set [\"a\", 1337]; // _myMap is now [[\"a\",1337], [\"b\",2]] and _overwritten is true\n```\n\n#### Getting an element\n\nValues are retrieved by their key:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n_myMap get \"a\"; // returns 1\n_myMap get \"z\"; // returns Nothing\n_myMap getOrDefault [\"z\", \"NotFound\"]; // returns \"NotFound\"\n// alternatively\n_myMap getOrDefaultCall [\"z\", { systemChat \"key 'z' does not exist, creating it\"; \"26\"; }, true];\n```\n\n#### Removing an element\n\nElements can be removed (deleted) from the HashMap using deleteAt with the element's key:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n_myMap deleteAt \"b\"; // _myMap is \"a\",1\n```\n\n#### Checking if an element exists\n\nIt is possible to check if a key is present in the HashMap using the in command:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n\"a\" in _myMap; // returns true\n\"z\" in _myMap; // returns false\n```\n\n#### Counting elements\n\nThe count command can be used to return the number of key-value pairs stored in the HashMap:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\ncount _myMap ; // returns 2\n```\n\n#### Retrieving keys\n\nRetrieving an Array of all keys in the HashMap using the keys command:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nkeys _myMap; // returns [\"a\", \"b\"]\n```\n\n#### HashMap variables\n\nA HashMap variable is a reference to the HashMap (see [Wikipedia](https://en.wikipedia.org/wiki/Reference_(computer_science))); this means that if the HashMap is edited, all scripts and functions using this HashMap will see the changes.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\",3]];\nprivate _myNewMap = _myMap;\n_myMap set [\"z\", 4];\n_myNewMap get \"z\"; // returns 4\n```\n\nA HashMap set through setVariable does not need to be assigned again:\n\n```sqf\nplayer setVariable [\"myMap\", createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\",3]]];\nprivate _myMap = player getVariable \"myMap\";\n_myMap set [\"z\", 4];\nplayer getVariable \"myMap\"; // returns [[\"a\",1], [\"b\",2], [\"c\",3], [\"z\",4]]\n```\n\n#### Copying a HashMap\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _myNewMap = _myMap;\n_myMap set [\"a\", 1337];\n_myNewMap get \"a\"; // returns 1337\n```\n\nIn order to avoid this behaviour, **copy** the HashMap with + (plus):\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _myNewMap = +_myMap;\n_myMap set [\"a\", 1337];\n_myNewMap get \"a\"; // still 1\n```\n\nArrays stored as key or value in the HashMap will also be deep-copied.\n\n### Advanced Usage\n\n#### Iterating through a HashMap\n\nIn general, HashMaps have to be considered unordered. While iterating through them is possible with forEach, it is less efficient than looping through Arrays.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\", 1], [\"b\", 2]];\n{ systemChat str [_x, _y] } forEach _myMap;\n```\n\nWhen iterating through a HashMap with forEach, `_x` contains the key of the current element and `_y` contains the corresponding value.\n\n#### Merging two HashMaps\n\nTwo HashMaps can be merged together using merge.\n\n```sqf\n_hashMap1 merge _hashMap2;\n```\n\n#### Unsupported Key Types\n\nFor some unsupported data types, such as Objects, the following workaround can be used, as long as they're supported by the hashValue command:\n\n```sqf\nTAG_fnc_set = {\n    params [\"_hashmap\", \"_key\", \"_value\"];\n    isNil {\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]], true]; // uses an array to resolve any potential hash collision\n        \n        private _keyIndex = _keyVals#0 find _key;\n        if (_keyIndex < 0) then {\n            _keyVals#0 pushBack _key;\n            _keyVals#1 pushBack _value;\n        } else {\n            _keyVals#1 set [_keyIndex, _value];\n        };\n    };\n};\nTAG_fnc_get = {\n    params [\"_hashmap\", \"_key\", \"_defaultValue\"];\n    private \"_return\";\n    isNil { // force unscheduled check\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]]];\n        _return = _keyVals#1 param [_keyVals#0 find _key, _defaultValue];\n    };\n    _return;\n};\nTAG_fnc_remove = {\n    params [\"_hashmap\", \"_key\"];\n    isNil { // force unscheduled check\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]]];\n        private _keyIndex = _keyVals#0 find _key;\n        if (_keyIndex >= 0) then {\n            _keyVals#0 deleteAt _keyIndex;\n            _keyVals#1 deleteAt _keyIndex;\n        };\n    };\n};\n\n// Example: Add the player object to hashmap (assuming player is not null)\nprivate _tempHashmap = createHashMap;\n[_tempHashmap, player, 1] call TAG_fnc_set; // add the player object as key, and 1 as its value\nprivate _value1 = [_tempHashmap, player, 2] call TAG_fnc_get; // will return 1\nprivate _value2 = [_tempHashmap, objNull, 2] call TAG_fnc_get; // will return 2, the default value\n```\n\nThe above example can be extended to add support for iterations, etc. as well.\n\n#### Automagic assignation\n\nKeys can be prefixed by an underscore so that the HashMap can be converted to private variables on-the-fly using params. This can be useful if a HashMap is kept alive for a long time and its values need to be accessed often, or to further simplify passing data between computers. Here's an example with a simple vehicle respawn system:\n\n```sqf\nprivate _vehicleHashMaps = nearestObjects [player, [\"LandVehicle\"], 50] apply\n{\n    createHashMapFromArray\n    [\n        [\"_vehicle\", _x],\n        [\"_class\", typeOf _x],\n        [\"_startPos\", getPosATL _x],\n        [\"_respawnTimeout\", 10*60],\n        [\"_lastSeenAlive\", diag_tickTime]\n    ]\n};\n\n_vehicleHashMaps spawn\n{\n    while {true} do\n    {\n        {\n            _settings = _x;\n            (values _settings) params (keys _settings); // automagic assignation of each value to a private variable of its key name\n\n            if (alive _vehicle) then\n            {\n                _settings set [\"_lastSeenAlive\", diag_tickTime];\n            }\n            else\n            {\n                if (diag_tickTime - _lastSeenAlive >= _respawnTimeout) then\n                {\n                    deleteVehicle _vehicle;\n                    _vehicle = createVehicle [_class, _startPos, [], 0, \"NONE\"];\n                    _settings set [\"_vehicle\", _vehicle];\n                    _settings set [\"_lastSeenAlive\", diag_tickTime];\n                };\n            };\n\n            sleep 1;\n        } forEach _this;\n\n        sleep 60;\n    };\n};\n```\n\n### Common Errors\n\n#### Scalar Key Precision\n\nNumbers in Arma 3 are floating point numbers, and because there are gaps between floating point numbers, rounding is necessary - see also [Wikipedia](https://en.wikipedia.org/wiki/Single-precision_floating-point_format). For example, 87654316, 87654317, 87654318, 87654319, 87654320, 87654321, 87654322, 87654323 and 87654324 will all be rounded to and treated as the same value by the game engine (because the actual value of each of these numbers can not be represented as an Arma 3 floating point number). Similar problems occur with fractional numbers:\n\n```sqf\n// this will return false:\n(0.3 + 0.4 == 0.7)\n```\n\nThis means that using very large numbers or fractional numbers as HashMap keys has to be done cautiously to avoid accidentally overwriting existing keys.\n\n### See Also\n\n- All HashMap commands","sections":[{"heading":null,"level":1,"markdown":"Arma 3 v2.02\n\nA **HashMap** is a specialized data structure that contains key-value pairs.\n\nHashMaps provide (near) constant-time lookup for keys, making them highly efficient at finding the value associated with a specific key - even if there is a very large amount of keys.\n\nSee [Wikipedia](https://en.wikipedia.org/wiki/Hash_table) to learn more about the underlying technology.\n\nWhile HashMaps and Arrays share many traits (and SQF command names), there are important differences and HashMaps must not be considered as some sort of new or improved replacement for the Array."},{"heading":"HashMap Basics","level":3,"markdown":"This section introduces the HashMap and its features and is intended to help create a basic understanding of what HashMaps are and what they can be used for."},{"heading":"Comparison with Arrays","level":4,"markdown":"The HashMap and the Array are both data structures that are used to store multiple elements. Arrays are simple and only store single elements, one after the other, while HashMaps store key-value pairs, where each key uniquely identifies a single value.\n\nUnlike Arrays, HashMaps have no order, i.e. there is no such thing as a first, second, third or last element in a HashMap. As such, the # and select commands can not be used with HashMaps. This also means that the order in which the forEach-loop processes a HashMap's key-value pairs is not deterministic.\n\nIterating over all elements in a HashMap is less efficient than doing the same in an Array."},{"heading":"Constant-time Key Lookup","level":4,"markdown":"HashMaps are specifically designed for (near) constant-time lookup of keys.\n\nConsider the following example to understand what that means: Let's say we have an Array that looks like this:\n\n```sqf\nprivate _playerDataArray = [[\"Player_A_UID\", \"Data A-1\", \"Data A-2\" /*, ... */], [\"Player_B_UID\", \"Data B-1\", \"Data B-2\" /*, ... */], [\"Player_C_UID\", \"Data C-1\", \"Data C-2\" /*, ... */] /*, ... */];\n```\n\nWe want to find a specific UID so that we can retrieve the corresponding data. We can easily achieve that using the findIf command:\n\n```sqf\n_index = _playerDataArray findIf {_x # 0 isEqualTo \"Wanted_UID\"};\n_data = _playerDataArray # _index;\n```\n\nBut what findIf actually does for us is something like this:\n\n```sqf\n{\n    if (_x # 0 isEqualTo \"Wanted_UID\") then\n    {\n        breakWith _forEachIndex;\n    };\n} forEach _playerDataArray;\n```\n\nNow consider how many isEqualTo comparisons this forEach-loop has to perform: If the element identified by \"Wanted_UID\" is stored at or near the end of `_playerDataArray`, then our code has to go through (almost) the entire Array to find it - and the same is the case if the element we are looking for does not exist in our Array.\n\nEvery single one of these comparisons takes some time - not much, but it will add up eventually. This is no problem as long as our Array is relatively small, but it becomes a serious issue when the Array starts growing: If there are 10,000 elements in the Array that means up to 10,000 comparisons might be necessary just to find a single element, if there are 100,000 elements that means up to 100,000 comparisons and so on - the amount of steps and time needed to find an element grows linearly with the Array size.\n\nAnd this is where HashMaps come in. Simply put: When a key-value pair is inserted into a HashMap, a hash function is applied to the key to determine the position at which the key-value pair is going to be stored. Then, when we want to retrieve the value associated with a specific key, the same hash function (Arma 3 uses [FNV-1a 64-bit](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function)) is applied to that key and the resulting position tells the HashMap exactly where to find the key-value pair that we are looking for.\n\n```sqf\nprivate _data = _playerDataHashMap get \"Wanted_UID\";\n```\n\nSince the process to find a given key-value pair is always the same (apply hash function, look at the resulting position, return the value that is stored there), it also always takes (more or less) the same amount of time - regardless of the size of the HashMap.\n\nThat is what constant-time lookup for keys means. And it comes with very useful benefits: The procedures to search for, retrieve, modify or remove a specific element can all be completed in constant time; whether the HashMap contains 10, 10,000 or 1,000,000 elements does not matter."},{"heading":"Working with HashMaps","level":3,"markdown":""},{"heading":"Supported Key Types","level":4,"markdown":"Because of the requirement for the keys to be hashable (and constant), not all Data Types can be used as keys.\n\nSupported types are limited to:\n- Array\n- Boolean\n- Code\n- Config\n- Namespace\n- NaN\n- Number\n- Side\n- String\n\n> [!IMPORTANT]\n> - For some unsupported key types, such as Objects, a workaround can be used. See Unsupported Key Types.\n> - Array keys can only contain supported types.\n> - Array keys are deep-copied on insertion and cannot be modified when retrieved via keys or inside forEach.\n> - The virtual type HashMapKey is a combination of all the supported types."},{"heading":"Creating a HashMap","level":4,"markdown":"```sqf\n// example of an empty HashMap:\nprivate _myMap = createHashMap;\ncount _myMap; // returns 0\n\n// example of a prefilled HashMap:\nprivate _myFilledMap = createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\", 3]];\ncount _myFilledMap; // returns 3\n```"},{"heading":"Setting an element","level":4,"markdown":"```sqf\nprivate _myMap = createHashMap;\n_myMap set [1, \"hello there\"]; // _myMap is [[1, \"hello there\"]]\n```\n\nInserting an element with a key that already exists inside the HashMap will overwrite the existing key.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _overwritten = _myMap set [\"a\", 1337]; // _myMap is now [[\"a\",1337], [\"b\",2]] and _overwritten is true\n```"},{"heading":"Getting an element","level":4,"markdown":"Values are retrieved by their key:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n_myMap get \"a\"; // returns 1\n_myMap get \"z\"; // returns Nothing\n_myMap getOrDefault [\"z\", \"NotFound\"]; // returns \"NotFound\"\n// alternatively\n_myMap getOrDefaultCall [\"z\", { systemChat \"key 'z' does not exist, creating it\"; \"26\"; }, true];\n```"},{"heading":"Removing an element","level":4,"markdown":"Elements can be removed (deleted) from the HashMap using deleteAt with the element's key:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n_myMap deleteAt \"b\"; // _myMap is \"a\",1\n```"},{"heading":"Checking if an element exists","level":4,"markdown":"It is possible to check if a key is present in the HashMap using the in command:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\n\"a\" in _myMap; // returns true\n\"z\" in _myMap; // returns false\n```"},{"heading":"Counting elements","level":4,"markdown":"The count command can be used to return the number of key-value pairs stored in the HashMap:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\ncount _myMap ; // returns 2\n```"},{"heading":"Retrieving keys","level":4,"markdown":"Retrieving an Array of all keys in the HashMap using the keys command:\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nkeys _myMap; // returns [\"a\", \"b\"]\n```"},{"heading":"HashMap variables","level":4,"markdown":"A HashMap variable is a reference to the HashMap (see [Wikipedia](https://en.wikipedia.org/wiki/Reference_(computer_science))); this means that if the HashMap is edited, all scripts and functions using this HashMap will see the changes.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\",3]];\nprivate _myNewMap = _myMap;\n_myMap set [\"z\", 4];\n_myNewMap get \"z\"; // returns 4\n```\n\nA HashMap set through setVariable does not need to be assigned again:\n\n```sqf\nplayer setVariable [\"myMap\", createHashMapFromArray [[\"a\",1], [\"b\",2], [\"c\",3]]];\nprivate _myMap = player getVariable \"myMap\";\n_myMap set [\"z\", 4];\nplayer getVariable \"myMap\"; // returns [[\"a\",1], [\"b\",2], [\"c\",3], [\"z\",4]]\n```"},{"heading":"Copying a HashMap","level":4,"markdown":"```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _myNewMap = _myMap;\n_myMap set [\"a\", 1337];\n_myNewMap get \"a\"; // returns 1337\n```\n\nIn order to avoid this behaviour, **copy** the HashMap with + (plus):\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\",1], [\"b\",2]];\nprivate _myNewMap = +_myMap;\n_myMap set [\"a\", 1337];\n_myNewMap get \"a\"; // still 1\n```\n\nArrays stored as key or value in the HashMap will also be deep-copied."},{"heading":"Advanced Usage","level":3,"markdown":""},{"heading":"Iterating through a HashMap","level":4,"markdown":"In general, HashMaps have to be considered unordered. While iterating through them is possible with forEach, it is less efficient than looping through Arrays.\n\n```sqf\nprivate _myMap = createHashMapFromArray [[\"a\", 1], [\"b\", 2]];\n{ systemChat str [_x, _y] } forEach _myMap;\n```\n\nWhen iterating through a HashMap with forEach, `_x` contains the key of the current element and `_y` contains the corresponding value."},{"heading":"Merging two HashMaps","level":4,"markdown":"Two HashMaps can be merged together using merge.\n\n```sqf\n_hashMap1 merge _hashMap2;\n```"},{"heading":"Unsupported Key Types","level":4,"markdown":"For some unsupported data types, such as Objects, the following workaround can be used, as long as they're supported by the hashValue command:\n\n```sqf\nTAG_fnc_set = {\n    params [\"_hashmap\", \"_key\", \"_value\"];\n    isNil {\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]], true]; // uses an array to resolve any potential hash collision\n        \n        private _keyIndex = _keyVals#0 find _key;\n        if (_keyIndex < 0) then {\n            _keyVals#0 pushBack _key;\n            _keyVals#1 pushBack _value;\n        } else {\n            _keyVals#1 set [_keyIndex, _value];\n        };\n    };\n};\nTAG_fnc_get = {\n    params [\"_hashmap\", \"_key\", \"_defaultValue\"];\n    private \"_return\";\n    isNil { // force unscheduled check\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]]];\n        _return = _keyVals#1 param [_keyVals#0 find _key, _defaultValue];\n    };\n    _return;\n};\nTAG_fnc_remove = {\n    params [\"_hashmap\", \"_key\"];\n    isNil { // force unscheduled check\n        private _hash = hashValue _key;\n        private _keyVals = _hashmap getOrDefault [_hash, [[],[]]];\n        private _keyIndex = _keyVals#0 find _key;\n        if (_keyIndex >= 0) then {\n            _keyVals#0 deleteAt _keyIndex;\n            _keyVals#1 deleteAt _keyIndex;\n        };\n    };\n};\n\n// Example: Add the player object to hashmap (assuming player is not null)\nprivate _tempHashmap = createHashMap;\n[_tempHashmap, player, 1] call TAG_fnc_set; // add the player object as key, and 1 as its value\nprivate _value1 = [_tempHashmap, player, 2] call TAG_fnc_get; // will return 1\nprivate _value2 = [_tempHashmap, objNull, 2] call TAG_fnc_get; // will return 2, the default value\n```\n\nThe above example can be extended to add support for iterations, etc. as well."},{"heading":"Automagic assignation","level":4,"markdown":"Keys can be prefixed by an underscore so that the HashMap can be converted to private variables on-the-fly using params. This can be useful if a HashMap is kept alive for a long time and its values need to be accessed often, or to further simplify passing data between computers. Here's an example with a simple vehicle respawn system:\n\n```sqf\nprivate _vehicleHashMaps = nearestObjects [player, [\"LandVehicle\"], 50] apply\n{\n    createHashMapFromArray\n    [\n        [\"_vehicle\", _x],\n        [\"_class\", typeOf _x],\n        [\"_startPos\", getPosATL _x],\n        [\"_respawnTimeout\", 10*60],\n        [\"_lastSeenAlive\", diag_tickTime]\n    ]\n};\n\n_vehicleHashMaps spawn\n{\n    while {true} do\n    {\n        {\n            _settings = _x;\n            (values _settings) params (keys _settings); // automagic assignation of each value to a private variable of its key name\n\n            if (alive _vehicle) then\n            {\n                _settings set [\"_lastSeenAlive\", diag_tickTime];\n            }\n            else\n            {\n                if (diag_tickTime - _lastSeenAlive >= _respawnTimeout) then\n                {\n                    deleteVehicle _vehicle;\n                    _vehicle = createVehicle [_class, _startPos, [], 0, \"NONE\"];\n                    _settings set [\"_vehicle\", _vehicle];\n                    _settings set [\"_lastSeenAlive\", diag_tickTime];\n                };\n            };\n\n            sleep 1;\n        } forEach _this;\n\n        sleep 60;\n    };\n};\n```"},{"heading":"Common Errors","level":3,"markdown":""},{"heading":"Scalar Key Precision","level":4,"markdown":"Numbers in Arma 3 are floating point numbers, and because there are gaps between floating point numbers, rounding is necessary - see also [Wikipedia](https://en.wikipedia.org/wiki/Single-precision_floating-point_format). For example, 87654316, 87654317, 87654318, 87654319, 87654320, 87654321, 87654322, 87654323 and 87654324 will all be rounded to and treated as the same value by the game engine (because the actual value of each of these numbers can not be represented as an Arma 3 floating point number). Similar problems occur with fractional numbers:\n\n```sqf\n// this will return false:\n(0.3 + 0.4 == 0.7)\n```\n\nThis means that using very large numbers or fractional numbers as HashMap keys has to be done cautiously to avoid accidentally overwriting existing keys."},{"heading":"See Also","level":3,"markdown":"- All HashMap commands"}],"categories":["Data Types","Introduced with Arma 3 version 2.02"],"groups":["Data Types"]},{"name":"HashMapKey","title":"HashMapKey","type":"topic","url":"https://community.bistudio.com/wiki/HashMapKey","revid":330441,"updated":"2022-09-15T21:04:29Z","aliases":[],"markdown":"HashMapKey is a virtual compound type containing all the possible types that can be used as keys in a HashMap.\n\nThe types are:\n- Number\n- Boolean\n- String\n- Code\n- Side\n- Config\n- Namespace\n- NaN\n- Array","sections":[{"heading":null,"level":1,"markdown":"HashMapKey is a virtual compound type containing all the possible types that can be used as keys in a HashMap.\n\nThe types are:\n- Number\n- Boolean\n- String\n- Code\n- Side\n- Config\n- Namespace\n- NaN\n- Array"}],"categories":["Magic Types"],"groups":["Data Types"]},{"name":"Identifier","title":"Identifier","type":"topic","url":"https://community.bistudio.com/wiki/Identifier","revid":377927,"updated":"2026-01-11T16:19:20Z","aliases":["identifier"],"markdown":"__NOTOC__\nAn Identifier is the name given to a variable that the scripter can choose: It is the name that *identifies* the variable.\n\n### Rules\n\n|  |  |  |\n|---|---|---|\n| + Regex: `[a-zA-Z_][a-zA-Z0-9_]*` | Valid | Invalid |\n| - variable1<br>- _my_local_variable<br>- _1variable<br>- _player | - 1variable<br>- _my#localVar<br>- _guy1&2var<br>- player (player) |  |\n\nBinding rules for identifiers:\n- Identifiers may consist of any ASCII text characters (a-z, A-Z), numbers (0-9) and underscores (_).\n- Identifiers **must not** start with a number (e.g \"9myVariable\" is invalid).\n- Identifiers of local variables **must** start with an underscore.\n- Identifiers are **case-insensitive**.\n- Identifiers **cannot be the same as reserved words** (e.g commands and functions).\n\n### Recommendations\n\nIt is recommended to write **local variable identifiers** in [camel case](https://en.wikipedia.org/wiki/Camel_case) syntax. This makes identifiers more readable:\n\n```sqf\nprivate _myVariableName = 5;\n```\n\n> [!IMPORTANT]\n> <https://en.wikipedia.org/wiki/Snake_case> is sometimes encountered but is not recommended and should be avoided:\n>\n> ```sqf\n> _my_variable_name = 5;\n> ```\n\nIt is also recommended to prefix **global variable identifiers** with **your** tag in order to avoid any potential conflict between addons, scripts and missions:\n `// **Tag**_identifier`\n UNIQUETAG_player = player;\n\n### See also\n\n- Variables","sections":[{"heading":null,"level":1,"markdown":"__NOTOC__\nAn Identifier is the name given to a variable that the scripter can choose: It is the name that *identifies* the variable."},{"heading":"Rules","level":3,"markdown":"|  |  |  |\n|---|---|---|\n| + Regex: `[a-zA-Z_][a-zA-Z0-9_]*` | Valid | Invalid |\n| - variable1<br>- _my_local_variable<br>- _1variable<br>- _player | - 1variable<br>- _my#localVar<br>- _guy1&2var<br>- player (player) |  |\n\nBinding rules for identifiers:\n- Identifiers may consist of any ASCII text characters (a-z, A-Z), numbers (0-9) and underscores (_).\n- Identifiers **must not** start with a number (e.g \"9myVariable\" is invalid).\n- Identifiers of local variables **must** start with an underscore.\n- Identifiers are **case-insensitive**.\n- Identifiers **cannot be the same as reserved words** (e.g commands and functions)."},{"heading":"Recommendations","level":3,"markdown":"It is recommended to write **local variable identifiers** in [camel case](https://en.wikipedia.org/wiki/Camel_case) syntax. This makes identifiers more readable:\n\n```sqf\nprivate _myVariableName = 5;\n```\n\n> [!IMPORTANT]\n> <https://en.wikipedia.org/wiki/Snake_case> is sometimes encountered but is not recommended and should be avoided:\n>\n> ```sqf\n> _my_variable_name = 5;\n> ```\n\nIt is also recommended to prefix **global variable identifiers** with **your** tag in order to avoid any potential conflict between addons, scripts and missions:\n `// **Tag**_identifier`\n UNIQUETAG_player = player;"},{"heading":"See also","level":3,"markdown":"- Variables"}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"If Type","title":"If Type","type":"topic","url":"https://community.bistudio.com/wiki/If_Type","revid":245280,"updated":"2021-02-10T14:24:06Z","aliases":[],"markdown":"**Description:**\nHelper type used in if...then construct.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nHelper type used in if...then construct."}],"categories":["Syntactical Helper Types"],"groups":["Data Types"]},{"name":"Initialisation Order","title":"Initialisation Order","type":"topic","url":"https://community.bistudio.com/wiki/Initialisation_Order","revid":373629,"updated":"2025-05-29T15:41:33Z","aliases":["Initialization Order"],"markdown":"Whenever a mission is launched (or joined in Multiplayer) certain tasks are performed to ensure the mission's various components are initialised correctly and that everyone is synced in multiplayer games (particularly JIP players).\nInitialisation order refers to the order in which those tasks are executed and it is important to take into account when setting up the start of a mission.\n\nEvent Scripts are a key part of a mission's initialisation order and will be utilised often when working with SQF.\n\n|  |  |  |\n|---|---|---|\n| + Key | Item | Meaning |\n|  | Single Player Only |  |\n|  | Multiplayer Only |  |\n|  | Order is not guaranteed |  |\n\nTake note that the order of initialisation is different in single player and multiplayer environments. If an entry is unmarked then it applies to both.\n\n> [!NOTE]\n> In multiplayer the following is relevant to every machine including the server and headless clients.\n> If the server is non-dedicated then it should be considered both a server and client.\n\n### Arma 3\n\n|  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|\n| + Order of Initialisation (From First to Last) | Task | Applies To | JIP | Related To | Exec Environment | Notes |\n| Functions with *recompile* attribute are recompiled | All | ✓ | Arma 3: Functions Library |  |  |  |\n| Functions with *preInit* attribute are called | All | ✓ | Arma 3: Functions Library | Unscheduled |  |  |\n| Object Init Event Handlers are called | All | ✗ |  | Unscheduled |  |  |\n| Expressions of Eden Editor entity attributes are called | Server | ✗ | Eden Editor: Configuring Attributes | Unscheduled | `isPlayer _entity` does not return true immediately. Once the entity has become a player, it is transfered to the client. |  |\n| Object initialisation fields are called | All | ✓ |  | Unscheduled |  |  |\n| init.sqs is executed | Singleplayer | N/A | Event Scripts |  |  |  |\n| init.sqf is executed | Singleplayer | N/A | Event Scripts | Scheduled (ref: Note **in single player** that while the environment is Scheduled (canSuspend returns true), the engine seems to wait until the script is done executing, essentially behaving similarly to an Unscheduled environment - infinite loops will freeze the game, uiSleep may pause the game for up to ~20s (postInit), waitUntil can cause catastrophic issues, etc.) |  |  |\n| Expressions of Eden Editor scenario attributes are called | All | ✓ | Eden Editor: Configuring Attributes | Unscheduled | player is not available immediately. |  |\n| Persistent functions are called | Client | ✓ | Arma 3: Remote Execution, BIS_fnc_MP |  |  |  |\n| Modules are initialised | All | ✗ |  |  | Modules with `isTriggerActivated = 0` execute their functions in scheduled environment |  |\n| initServer.sqf is executed | Server | N/A | Event Scripts | Scheduled |  |  |\n| initPlayerLocal.sqf is executed | Client | ✓ | Event Scripts | Scheduled |  |  |\n| initPlayerServer.sqf is executed on the server | Client | ✓ | Event Scripts | Scheduled |  |  |\n| Functions with *postInit* attribute are called | All | ✓ | Arma 3: Functions Library | Scheduled |  |  |\n| \"BIS_fnc_init\" variable is set to true | All | ✓ | Arma 2: Functions Library |  |  |  |\n| init.sqs is executed | Multiplayer | ✓ | Event Scripts | Scheduled |  |  |\n| init.sqf is executed | Multiplayer | ✓ | Event Scripts | Scheduled |  |  |","sections":[{"heading":null,"level":1,"markdown":"Whenever a mission is launched (or joined in Multiplayer) certain tasks are performed to ensure the mission's various components are initialised correctly and that everyone is synced in multiplayer games (particularly JIP players).\nInitialisation order refers to the order in which those tasks are executed and it is important to take into account when setting up the start of a mission.\n\nEvent Scripts are a key part of a mission's initialisation order and will be utilised often when working with SQF.\n\n|  |  |  |\n|---|---|---|\n| + Key | Item | Meaning |\n|  | Single Player Only |  |\n|  | Multiplayer Only |  |\n|  | Order is not guaranteed |  |\n\nTake note that the order of initialisation is different in single player and multiplayer environments. If an entry is unmarked then it applies to both.\n\n> [!NOTE]\n> In multiplayer the following is relevant to every machine including the server and headless clients.\n> If the server is non-dedicated then it should be considered both a server and client."},{"heading":"Arma 3","level":3,"markdown":"|  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|\n| + Order of Initialisation (From First to Last) | Task | Applies To | JIP | Related To | Exec Environment | Notes |\n| Functions with *recompile* attribute are recompiled | All | ✓ | Arma 3: Functions Library |  |  |  |\n| Functions with *preInit* attribute are called | All | ✓ | Arma 3: Functions Library | Unscheduled |  |  |\n| Object Init Event Handlers are called | All | ✗ |  | Unscheduled |  |  |\n| Expressions of Eden Editor entity attributes are called | Server | ✗ | Eden Editor: Configuring Attributes | Unscheduled | `isPlayer _entity` does not return true immediately. Once the entity has become a player, it is transfered to the client. |  |\n| Object initialisation fields are called | All | ✓ |  | Unscheduled |  |  |\n| init.sqs is executed | Singleplayer | N/A | Event Scripts |  |  |  |\n| init.sqf is executed | Singleplayer | N/A | Event Scripts | Scheduled (ref: Note **in single player** that while the environment is Scheduled (canSuspend returns true), the engine seems to wait until the script is done executing, essentially behaving similarly to an Unscheduled environment - infinite loops will freeze the game, uiSleep may pause the game for up to ~20s (postInit), waitUntil can cause catastrophic issues, etc.) |  |  |\n| Expressions of Eden Editor scenario attributes are called | All | ✓ | Eden Editor: Configuring Attributes | Unscheduled | player is not available immediately. |  |\n| Persistent functions are called | Client | ✓ | Arma 3: Remote Execution, BIS_fnc_MP |  |  |  |\n| Modules are initialised | All | ✗ |  |  | Modules with `isTriggerActivated = 0` execute their functions in scheduled environment |  |\n| initServer.sqf is executed | Server | N/A | Event Scripts | Scheduled |  |  |\n| initPlayerLocal.sqf is executed | Client | ✓ | Event Scripts | Scheduled |  |  |\n| initPlayerServer.sqf is executed on the server | Client | ✓ | Event Scripts | Scheduled |  |  |\n| Functions with *postInit* attribute are called | All | ✓ | Arma 3: Functions Library | Scheduled |  |  |\n| \"BIS_fnc_init\" variable is set to true | All | ✓ | Arma 2: Functions Library |  |  |  |\n| init.sqs is executed | Multiplayer | ✓ | Event Scripts | Scheduled |  |  |\n| init.sqf is executed | Multiplayer | ✓ | Event Scripts | Scheduled |  |  |"}],"categories":["Mission Editing","Scripting Topics"],"groups":["Scripting"]},{"name":"Location","title":"Location","type":"topic","url":"https://community.bistudio.com/wiki/Location","revid":378131,"updated":"2026-02-22T20:29:35Z","aliases":["Arma 2: CfgLocationTypes","location"],"markdown":"A location is an extended type of marker. For example city names displayed on the map are locations; their information can be accessed and modified with Location commands.\n\nLocation notion was introduced in Armed Assault v1.08.\n\n### Specifics\n\nLocations:\n- are defined in `bin\\Config.bin\\CfgLocationTypes` / `configFile >> \"CfgLocationTypes\"`\n- have a name, a side, a 3D position, a 2D area, and an orientation\n- have a non-scaling map representation (icon and/or text, depending on their class)\n- can be attached to objects, with all of the location's relevant properties inherited from the object\n- are local, their properties are not synchronised over the network\n\nTerrain built-in locations:\n- provide a way to find nearby high points, towns, etc.\n- are defined in an island's `.pew` file. When the island is exported to `.wrp` its `.hpp` file is also produced, containing the location names used in the `.pew` file. This `.hpp` file is then incorporated into the config for the island using an #include statement.\nThis section included in the island config ensures any locations set in the `.pew` file are included in the island during packing.\n\n| Modification | Terrain Location | Scripted Terrain Location<br>using createLocation#Syntax 2 | Scripted Location |\n|---|---|---|---|\n| Side | ✓ | ✓ | ✓ |\n| Size | ✗ | ✓ | ✓ |\n| Direction | ✗ | ✓ | ✓ |\n| setVariable/getVariable | ✗ | ✓ | ✓ |\n| 3D Position | ✗ | ✗ | ✓ |\n| Attach to an object | ✗ | ✗ | ✓ |\n| Deletion | ✗ | ✗ | ✓ |\n\n### Location Types\n\n#### Armed Assault\n\nPossible location types are:\n- Mount\n- Name\n- NameMarine\n- NameCityCapital\n- NameCity\n- NameVillage\n- NameLocal\n- Hill\n- ViewPoint\n- RockArea\n- BorderCrossing\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard\n\n#### Arma 2\n\n- Name\n- Strategic\n- StrongpointArea\n- FlatArea\n- FlatAreaCity\n- FlatAreaCitySmall\n- CityCenter\n- Airport\n- NameMarine\n- NameCityCapital\n- NameCity\n- NameVillage\n- NameLocal\n- Hill\n- ViewPoint\n- RockArea\n- BorderCrossing\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard\n\n#### Arma 3\n\n- Airport (on Tanoa only. Tanoan airports have their own location type. On Altis and Stratis, airports are **NameLocal**)\n- Area\n- BorderCrossing\n- CityCenter\n- CivilDefense\n- CulturalProperty\n- DangerousForces\n- Flag\n- FlatArea\n- FlatAreaCity\n- FlatAreaCitySmall\n- Hill\n- HistoricalSite\n- Invisible\n- Mount\n- Name\n- NameCity\n- NameCityCapital\n- NameLocal (will return names like Airport)\n- NameMarine\n- NameVillage\n- RockArea\n- SafetyZone\n- Strategic\n- StrongpointArea\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard\n- ViewPoint\n- b_air\n- b_antiair\n- b_armor\n- b_art\n- b_hq\n- b_inf\n- b_installation\n- b_maint\n- b_mech_inf\n- b_med\n- b_mortar\n- b_motor_inf\n- b_naval\n- b_plane\n- b_recon\n- b_service\n- b_support\n- b_uav\n- b_unknown\n- c_air\n- c_car\n- c_plane\n- c_ship\n- c_unknown\n- fakeTown\n- group_0\n- group_1\n- group_10\n- group_11\n- group_2\n- group_3\n- group_4\n- group_5\n- group_6\n- group_7\n- group_8\n- group_9\n- n_air\n- n_antiair\n- n_armor\n- n_art\n- n_hq\n- n_inf\n- n_installation\n- n_maint\n- n_mech_inf\n- n_med\n- n_mortar\n- n_motor_inf\n- n_naval\n- n_plane\n- n_recon\n- n_service\n- n_support\n- n_uav\n- n_unknown\n- o_air\n- o_antiair\n- o_armor\n- o_art\n- o_hq\n- o_inf\n- o_installation\n- o_maint\n- o_mech_inf\n- o_med\n- o_mortar\n- o_motor_inf\n- o_naval\n- o_plane\n- o_recon\n- o_service\n- o_support\n- o_uav\n- o_unknown\n- respawn_air\n- respawn_armor\n- respawn_inf\n- respawn_motor\n- respawn_naval\n- respawn_para\n- respawn_plane\n- respawn_unknown\n- u_installation","sections":[{"heading":null,"level":1,"markdown":"A location is an extended type of marker. For example city names displayed on the map are locations; their information can be accessed and modified with Location commands.\n\nLocation notion was introduced in Armed Assault v1.08."},{"heading":"Specifics","level":3,"markdown":"Locations:\n- are defined in `bin\\Config.bin\\CfgLocationTypes` / `configFile >> \"CfgLocationTypes\"`\n- have a name, a side, a 3D position, a 2D area, and an orientation\n- have a non-scaling map representation (icon and/or text, depending on their class)\n- can be attached to objects, with all of the location's relevant properties inherited from the object\n- are local, their properties are not synchronised over the network\n\nTerrain built-in locations:\n- provide a way to find nearby high points, towns, etc.\n- are defined in an island's `.pew` file. When the island is exported to `.wrp` its `.hpp` file is also produced, containing the location names used in the `.pew` file. This `.hpp` file is then incorporated into the config for the island using an #include statement.\nThis section included in the island config ensures any locations set in the `.pew` file are included in the island during packing.\n\n| Modification | Terrain Location | Scripted Terrain Location<br>using createLocation#Syntax 2 | Scripted Location |\n|---|---|---|---|\n| Side | ✓ | ✓ | ✓ |\n| Size | ✗ | ✓ | ✓ |\n| Direction | ✗ | ✓ | ✓ |\n| setVariable/getVariable | ✗ | ✓ | ✓ |\n| 3D Position | ✗ | ✗ | ✓ |\n| Attach to an object | ✗ | ✗ | ✓ |\n| Deletion | ✗ | ✗ | ✓ |"},{"heading":"Location Types","level":3,"markdown":""},{"heading":"Armed Assault","level":4,"markdown":"Possible location types are:\n- Mount\n- Name\n- NameMarine\n- NameCityCapital\n- NameCity\n- NameVillage\n- NameLocal\n- Hill\n- ViewPoint\n- RockArea\n- BorderCrossing\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard"},{"heading":"Arma 2","level":4,"markdown":"- Name\n- Strategic\n- StrongpointArea\n- FlatArea\n- FlatAreaCity\n- FlatAreaCitySmall\n- CityCenter\n- Airport\n- NameMarine\n- NameCityCapital\n- NameCity\n- NameVillage\n- NameLocal\n- Hill\n- ViewPoint\n- RockArea\n- BorderCrossing\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard"},{"heading":"Arma 3","level":4,"markdown":"- Airport (on Tanoa only. Tanoan airports have their own location type. On Altis and Stratis, airports are **NameLocal**)\n- Area\n- BorderCrossing\n- CityCenter\n- CivilDefense\n- CulturalProperty\n- DangerousForces\n- Flag\n- FlatArea\n- FlatAreaCity\n- FlatAreaCitySmall\n- Hill\n- HistoricalSite\n- Invisible\n- Mount\n- Name\n- NameCity\n- NameCityCapital\n- NameLocal (will return names like Airport)\n- NameMarine\n- NameVillage\n- RockArea\n- SafetyZone\n- Strategic\n- StrongpointArea\n- VegetationBroadleaf\n- VegetationFir\n- VegetationPalm\n- VegetationVineyard\n- ViewPoint\n- b_air\n- b_antiair\n- b_armor\n- b_art\n- b_hq\n- b_inf\n- b_installation\n- b_maint\n- b_mech_inf\n- b_med\n- b_mortar\n- b_motor_inf\n- b_naval\n- b_plane\n- b_recon\n- b_service\n- b_support\n- b_uav\n- b_unknown\n- c_air\n- c_car\n- c_plane\n- c_ship\n- c_unknown\n- fakeTown\n- group_0\n- group_1\n- group_10\n- group_11\n- group_2\n- group_3\n- group_4\n- group_5\n- group_6\n- group_7\n- group_8\n- group_9\n- n_air\n- n_antiair\n- n_armor\n- n_art\n- n_hq\n- n_inf\n- n_installation\n- n_maint\n- n_mech_inf\n- n_med\n- n_mortar\n- n_motor_inf\n- n_naval\n- n_plane\n- n_recon\n- n_service\n- n_support\n- n_uav\n- n_unknown\n- o_air\n- o_antiair\n- o_armor\n- o_art\n- o_hq\n- o_inf\n- o_installation\n- o_maint\n- o_mech_inf\n- o_med\n- o_mortar\n- o_motor_inf\n- o_naval\n- o_plane\n- o_recon\n- o_service\n- o_support\n- o_uav\n- o_unknown\n- respawn_air\n- respawn_armor\n- respawn_inf\n- respawn_motor\n- respawn_naval\n- respawn_para\n- respawn_plane\n- respawn_unknown\n- u_installation"}],"categories":["Data Types","Introduced with Armed Assault version 1.08"],"groups":["Data Types"]},{"name":"Magic Variables","title":"Magic Variables","type":"topic","url":"https://community.bistudio.com/wiki/Magic_Variables","revid":378809,"updated":"2026-06-30T19:25:43Z","aliases":["fnc scriptName","forEachIndex","this","thisActivator","thisArgs","thisList","thisScript","thisTrigger","thisargs","x","y"],"markdown":"__NOEDITSECTION__\nMagic variables are engine-maintained variables that serve a specific purpose within a given scope and are often used by the engine to provide data to a script or code fragment.\n\nThey are usually no longer present after leaving the scope (e.g. after code execution or after a forEach-statement).\n\n#### _this\n\nUsed to make the arguments of a script call (call, exec, execVM, spawn) visible and accessible to the script. Also used by Event Handlers to provide parameters.\n\n#### _x\n\nRepresents the current element during iteration with apply, count, configClasses, configProperties, findIf, forEach and select.\n\n#### _y (Arma 3 v2.02)\n\nIterating over a HashMap with forEach will return the key as _x and the value as _y.\n\n#### _exception (Armed Assault v1.00)\n\nException handling using a try-catch-statement declares this variable which contains details about the thrown exception in the try-block.\n\n#### _fnc_scriptName (Arma 3 v1.00)\n\n> [!NOTE]\n> Not engine-maintained, but added by `functions_f/initFunctions.sqf` – see scriptName.\n\nWithin a Function, the `TAG_fnc_functionName` function name (e.g. `\"myTag_fnc_myFunction\"`).\n\n#### _fnc_scriptNameParent (Arma 3 v1.00)\n\n> [!NOTE]\n> Not engine-maintained, but added by `functions_f/initFunctions.sqf` – see scriptName.\n\nWithin a Function, the name of the function that called the current function (same as _fnc_scriptName if the function was not called by another function).\n\n#### _forEachIndex (Arma 2: Operation Arrowhead v1.55)\n\nRepresents the (zero-based) index of a forEach- / forEachReversed-loop.\n\n#### _self (Arma 3 v2.14)\n\nAvailable in HashMapObject methods. Contains the HashMapObject instance that the method was invoked on (see createHashMapObject).\n\n#### _thisArgs (Arma 3 v2.04)\n\nAdditional Event Handler arguments available with addMissionEventHandler.\n\n#### _thisEvent (Arma 3 v2.06)\n\nThe name of the Event added with addEventHandler, addMPEventHandler, addMissionEventHandler,addUserActionEventHandler, ctrlAddEventHandler and displayAddEventHandler, as well as for config types EHs.\n\n#### _thisEventHandler (Arma 3 v1.64)\n\nThe index for Event Handlers added with addEventHandler, addMPEventHandler, addMissionEventHandler, addUserActionEventHandler, ctrlAddEventHandler and displayAddEventHandler.\n\n#### _thisFSM (Arma 3 v1.54)\n\nThe FSM ID for FSMs executed with execFSM.\n\n#### _thisScript (Arma 3 v1.54)\n\nThe Script Handle of a script started with execVM, call or spawn.\n\n#### _thisScriptedEventHandler (Arma 3 v1.68)\n\nThe index for Scripted Event Handlers added with BIS_fnc_addScriptedEventHandler.\n\n#### _time\n\n> [!WARNING]\n> SQS only.\n\nThe time elapsed since the script started running.\n\n#### this\n\n- **Addon Config Files** (e.g. UserActions, onInit, etc.)**:** The object to which the entry belongs.\n- **Dialogs:** The player unit that activated control (e.g. via mouseEnter). false if non-activated.\n- **Object Init Fields:** The object to which the init field belongs.\n- **Triggers:**\n  - *Condition*: The Boolean return value of the Trigger's condition (e.g. \"East Not Present\").\n  - *On Activation* and *On Deactivation*: Seems to always return false.\n- **Waypoints:**\n  - *Condition*, *On Activation* and *On Deactivation*: The group leader that completed the waypoint (or the driver, if the waypoint is assigned to a vehicle).\n\n#### thisList\n\n- **Triggers:**\n  - Accessible in the *Condition*, *On Activation* and *On Deactivation* code.\n  - Defines an array of objects that have been detected by the trigger (same as what is returned by the list command).\n  - Seems to be undefined in the *On Deactivation* expression and should not be used. It will either be an empty array, or possibly the contents of a different trigger.\n- **Waypoints:**\n  - Accessible within the *Condition* or *On Activation* code.\n  - Defines an array containing all group members that completed the waypoint.\n\n#### thisTrigger\n\nRefers to the trigger object itself - accessible within the *Condition*, *On Activation* and *On Deactivation* code.\n\n#### thisActivator (Arma 3 v2.22)\n\nRefers to an Object, which activated this trigger. Default: the trigger Object itself.","sections":[{"heading":null,"level":1,"markdown":"__NOEDITSECTION__\nMagic variables are engine-maintained variables that serve a specific purpose within a given scope and are often used by the engine to provide data to a script or code fragment.\n\nThey are usually no longer present after leaving the scope (e.g. after code execution or after a forEach-statement)."},{"heading":"_this","level":4,"markdown":"Used to make the arguments of a script call (call, exec, execVM, spawn) visible and accessible to the script. Also used by Event Handlers to provide parameters."},{"heading":"_x","level":4,"markdown":"Represents the current element during iteration with apply, count, configClasses, configProperties, findIf, forEach and select."},{"heading":"_y (Arma 3 v2.02)","level":4,"markdown":"Iterating over a HashMap with forEach will return the key as _x and the value as _y."},{"heading":"_exception (Armed Assault v1.00)","level":4,"markdown":"Exception handling using a try-catch-statement declares this variable which contains details about the thrown exception in the try-block."},{"heading":"_fnc_scriptName (Arma 3 v1.00)","level":4,"markdown":"> [!NOTE]\n> Not engine-maintained, but added by `functions_f/initFunctions.sqf` – see scriptName.\n\nWithin a Function, the `TAG_fnc_functionName` function name (e.g. `\"myTag_fnc_myFunction\"`)."},{"heading":"_fnc_scriptNameParent (Arma 3 v1.00)","level":4,"markdown":"> [!NOTE]\n> Not engine-maintained, but added by `functions_f/initFunctions.sqf` – see scriptName.\n\nWithin a Function, the name of the function that called the current function (same as _fnc_scriptName if the function was not called by another function)."},{"heading":"_forEachIndex (Arma 2: Operation Arrowhead v1.55)","level":4,"markdown":"Represents the (zero-based) index of a forEach- / forEachReversed-loop."},{"heading":"_self (Arma 3 v2.14)","level":4,"markdown":"Available in HashMapObject methods. Contains the HashMapObject instance that the method was invoked on (see createHashMapObject)."},{"heading":"_thisArgs (Arma 3 v2.04)","level":4,"markdown":"Additional Event Handler arguments available with addMissionEventHandler."},{"heading":"_thisEvent (Arma 3 v2.06)","level":4,"markdown":"The name of the Event added with addEventHandler, addMPEventHandler, addMissionEventHandler,addUserActionEventHandler, ctrlAddEventHandler and displayAddEventHandler, as well as for config types EHs."},{"heading":"_thisEventHandler (Arma 3 v1.64)","level":4,"markdown":"The index for Event Handlers added with addEventHandler, addMPEventHandler, addMissionEventHandler, addUserActionEventHandler, ctrlAddEventHandler and displayAddEventHandler."},{"heading":"_thisFSM (Arma 3 v1.54)","level":4,"markdown":"The FSM ID for FSMs executed with execFSM."},{"heading":"_thisScript (Arma 3 v1.54)","level":4,"markdown":"The Script Handle of a script started with execVM, call or spawn."},{"heading":"_thisScriptedEventHandler (Arma 3 v1.68)","level":4,"markdown":"The index for Scripted Event Handlers added with BIS_fnc_addScriptedEventHandler."},{"heading":"_time","level":4,"markdown":"> [!WARNING]\n> SQS only.\n\nThe time elapsed since the script started running."},{"heading":"this","level":4,"markdown":"- **Addon Config Files** (e.g. UserActions, onInit, etc.)**:** The object to which the entry belongs.\n- **Dialogs:** The player unit that activated control (e.g. via mouseEnter). false if non-activated.\n- **Object Init Fields:** The object to which the init field belongs.\n- **Triggers:**\n  - *Condition*: The Boolean return value of the Trigger's condition (e.g. \"East Not Present\").\n  - *On Activation* and *On Deactivation*: Seems to always return false.\n- **Waypoints:**\n  - *Condition*, *On Activation* and *On Deactivation*: The group leader that completed the waypoint (or the driver, if the waypoint is assigned to a vehicle)."},{"heading":"thisList","level":4,"markdown":"- **Triggers:**\n  - Accessible in the *Condition*, *On Activation* and *On Deactivation* code.\n  - Defines an array of objects that have been detected by the trigger (same as what is returned by the list command).\n  - Seems to be undefined in the *On Deactivation* expression and should not be used. It will either be an empty array, or possibly the contents of a different trigger.\n- **Waypoints:**\n  - Accessible within the *Condition* or *On Activation* code.\n  - Defines an array containing all group members that completed the waypoint."},{"heading":"thisTrigger","level":4,"markdown":"Refers to the trigger object itself - accessible within the *Condition*, *On Activation* and *On Deactivation* code."},{"heading":"thisActivator (Arma 3 v2.22)","level":4,"markdown":"Refers to an Object, which activated this trigger. Default: the trigger Object itself."}],"categories":["Scripting Topics"],"groups":["Scripting"]},{"name":"Multiplayer Scripting","title":"Multiplayer Scripting","type":"topic","url":"https://community.bistudio.com/wiki/Multiplayer_Scripting","revid":376938,"updated":"2025-12-31T22:33:57Z","aliases":["JIP","Join In Progress","Locality in Multiplayer","Multiplayer scripting"],"markdown":"This page aims to explain notions and specificities of Multiplayer Scripting and its differences with Singleplayer Scripting.\n\nIt features three parts:\n1. #Notions and general knowledge\n1. #Structuring Multiplayer code\n1. Testing locally\n\n## Notions and general knowledge\n\n### The basics\n\n- In Multiplayer, players are connected to a **server**.\n  - The server is a machine that distributes information among clients, such as unit positions, vehicle speeds, etc.\n  - The server can be either a dedicated machine, or hosted by a player; in the latter it means the server can have a player unit.\n- A machine connected to a server is called a **client**.\n  - Clients can join a mission *after* it started: they are considered \"JIP\" and scripting should be adapted to them. See the #Join In Progress chapter for more information.\n\n> [!NOTE]\n> In Singleplayer, the game acts as a player-hosted server (isServer returns true).\n\n> [!WARNING]\n> Some Multiplayer commands do **not** work in Singleplayer, such as netId!\n>\n> The other way around, some Singleplayer commands do not work in Multiplayer (e.g  setAccTime).\n\n### Locality\n\n#### Definitions\n\n- **LOCAL** is an attribute for the machine where the command/script/function is executed or the AI calculated.\n  - to check if an argument is local, use the local command\n- **REMOTE** means **non local** - on another machine. All player-controlled soldiers are remote units to a dedicated server, for example.\n  - to check if an argument is remote, simply use `not local _myObject`\n- commands arguments and effects can be either **local** or **global**:\n\n|  |  |\n|---|---|\n| Local Argument | a **local** argument means an argument that is processed on the machine where the command is executed |\n| Global Argument | a **global** argument means any argument, even a remote one |\n| Local Effect | a **local** effect means that the effect will only happen on the machine where the command is executed |\n| Global Effect | a **global** effect means that all the computers will receive it |\n| Server Execution | **server exec** means that the command or function has to be executed on the server machine, either mission host or dedicated server |\n\n> [!NOTE]\n> See also:\n> - Scripting Commands: Local Effect\n> - Scripting Commands: Global Effect\n> - Scripting Commands: Server Execution\n> - Functions: Local Effect\n> - Functions: Global Effect\n> - Functions: Server Execution\n\n#### Different machines and how to target them\n\n> [!NOTE]\n> - For obvious reasons, a server cannot be JIP.\n> - Use didJIP to determine if a client joined during the game.\n\n| Scripting Commands | Server | Player client | Headless client | Note |  |\n|---|---|---|---|---|---|\n| Dedicated | Player-Hosted |  |  |  |  |\n| ```sqf<br>isDedicated<br>``` | ✓ | ✗ | ✗ | ✗ | Dedicated server |\n| ```sqf<br>hasInterface && isServer<br>``` | ✗ | ✓ | ✗ | ✗ | Player server |\n| ```sqf<br>hasInterface && not isServer<br>``` | ✗ | ✗ | ✓ | ✗ | Player client |\n| ```sqf<br>not hasInterface && not isDedicated<br>``` | ✗ | ✗ | ✗ | ✓ | Headless client |\n| ```sqf<br>isServer<br>``` | ✓ | ✓ | ✗ | ✗ | Any server |\n| ```sqf<br>hasInterface<br>``` | ✗ | ✓ | ✓ | ✗ | Any player |\n| Miscellaneous |  |  |  |  |  |\n| ```sqf<br>not isServer<br>``` | ✗ | ✗ | ✓ | ✓ | All server clients, including headless clients, but excluding player host |\n| ```sqf<br>not isDedicated<br>``` | ✗ | ✓ | ✓ | ✓ | Everything but a dedicated server |\n| ```sqf<br>not hasInterface<br>``` | ✓ | ✗ | ✗ | ✓ | Headless clients and dedicated server |\n\n**For an extended version for all games, click**\n\n> [!NOTE]\n> Before Operation Flashpoint v1.99 and the backport of isServer, the server could be identified by placing a Game Logic in the editor (that would always remain local to the server), then using the following: `local myLogic`.\n\n| Targeted machine | Operation Flashpoint | Armed Assault | Arma 2 | Arma 3 |\n|---|---|---|---|---|\n| **Dedicated Server**<br>A server without a human player behind it | ```sqf<br>isServer && isNull player<br>``` | ```sqf<br>isServer && isNull player<br>``` | ```sqf<br>isDedicated<br>``` | ```sqf<br>isDedicated<br>``` |\n| **Player Server**<br>A server hosted by a player | ```sqf<br>isServer && not isNull player<br>``` | ```sqf<br>isServer && not isNull player<br>``` | ```sqf<br>isServer && not isDedicated<br>``` | ```sqf<br>hasInterface && isServer<br>``` |\n| **Server**<br>Any server, dedicated or hosted | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` |\n| **Player Client**<br>A player connected since the lobby | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>hasInterface && not isServer<br>``` |\n| **JIP Player Client**<br>A player connected in the middle of a mission | N/A | ```sqf<br>not isServer && isNull player<br>``` | ```sqf<br>not isServer && isNull player<br>``` | ```sqf<br>hasInterface && didJIP<br>``` |\n| **Headless Client**<br>A client without a human player behind it<br>(used to offload server calculations) | colspan=\"3\" N/A | ```sqf<br>not hasInterface && not isServer<br>``` |  |  |\n| **JIP Headless Client**<br>Headless client connected during the ongoing mission | colspan=\"3\" N/A | ```sqf<br>not hasInterface && not isServer && didJIP<br>``` |  |  |\n\n- If you want to know if the current machine is a server (Dedicated Server or Player Server), use isServer.\n- If you want to know if the current machine has a player (Player Server included), use hasInterface.\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3, a server-only init file is available: **initServer.sqf** (see Event Scripts)\n\n> [!NOTE]\n> **Arma 3:** **BIS_fnc_getNetMode** can be used to have a string value representing the local machine status (\"DedicatedServer\", \"Server\", \"HeadlessClient\", \"Client\", \"SinglePlayer\" ).\n>\n> This function doesn't make the JIP distinction and should be used along didJIP.\n\n#### General information about locality\n\n- about player:\n  - a player's unit is **always** local to the (human) player's machine\n  - a dedicated server doesn't have a player unit (`isNull player` returns true)\n  - to know if a certain unit is *a* player, use isPlayer\n- groups and AI:\n  - an AI group with a player-leader will be local to the player's computer\n  - a subordinate player being in a player-lead group will remain local to its computer (see bulletpoint #1)\n- objects:\n  - a driven vehicle is always local to the machine of its driver (not the commander's, not the gunner's)\n  - terrain objects (buildings, vegetation, roads etc.) are local everywhere (`local nearestBuilding player` returns true on every client)\n  - editor-placed objects and empty vehicles are local to the server\n  - editor-placed **triggers** are created on every machine unless specified otherwise (\"Server Only\" Eden Editor option ticked)\n  - units created with createUnit will be local to the computer that issued the command\n  - objects and vehicles created with createVehicle will be local to the computer that issued the command\n\n#### Locality changes\n\n- if the player-leader dies, the AI is transferred to the machine where the new leader is local (server in case of AI, client in case of another player)\n- joining AI units will change locality to the new leader's computer\n- locality will change from server to client when a player gets in an empty vehicle\n- locality can also change in the event of a Team Switch or usage of selectPlayer\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 the \"Local\" Event Handler triggers when an object's locality is changed.\n\n#### Code examples\n\n| Code | Argu-ments | Effect | Description |\n|---|---|---|---|\n| ```sqf<br>remoteUnit setDamage 1;<br>``` | Global Argument | Global Effect | Any unit (local or remote) will die, and all the computers will know |\n| ```sqf<br>localUnit addMagazine \"30Rnd_556x45_STANAG\";<br>``` | Local Argument | Global Effect | Only a local unit can have its inventory edited with this command, but all the machines will be notified: if a player looks into the *localUnit* inventory, the added magazine will be there |\n| ```sqf<br>remoteUnit setFace \"Miller\";<br>``` | Global Argument | Local Effect | Any unit (local or remote) can get its face changed, but the new face will not be propagated through the network. Only the local machine's player will see the effect of the command<br>> [!NOTE]<br>> This command should ideally be **executed on every machine**, for example with:<br>><br>> ```sqf<br>> [remoteUnit, \"Miller\"] remoteExec [\"setFace\", 0, true];<br>> ```<br>><br>> See the #Remote Execution chapter for more information. |\n| ```sqf<br>localCamera cameraEffect [\"Internal\", \"Back\"];<br>``` | Local Argument | Local Effect | Only a local camera can be entered, and of course only the local machine will see through this camera |\n\n### Network ID\n\nNetwork IDs identify machines and network objects. They can be used to target proper machines with remote execution; see the #Remote Execution chapter for more information.\n\n> [!WARNING]\n> **A machine ID** (ownerID) is not to be confused with **an object's network ID** (netId).\n\n#### Machine network ID\n\nEvery machine, including the server, has a **network ID**.\n\nA server always has an ID of **2**, every new client has the next number (the first client will be number **3**, second client number **4**, etc.)\n- To get the current machine's ID, use clientOwner.\n- To get the machine ID of an object's owner, use owner *object*  (MP only).\n- To get the machine ID of a group's owner, use groupOwner *object* (MP only).\n\n> [!NOTE]\n> **0** and **1** are special values:\n> - **0** means **everyone** (including the server)\n> - **1** means **current machine** but **is not implemented** and should **not** be used.\n\n#### Object network ID\n\nEvery object synchronised through the network has a network ID, shortened to **netId**.\n- To get an object's netId, use netId (MP only). **SP & MP variant:** BIS_fnc_netId\n- To get an object from a netId, use objectFromNetId (MP only). **SP & MP variant:** BIS_fnc_objectFromNetId\n- To get a group from a netId, use groupFromNetId (MP only). **SP & MP variant:** BIS_fnc_groupFromNetId\n\n### Sending information across network\n\n#### Remote Execution\n\nSince Arma 3 v1.50, remoteExec and remoteExecCall efficient engine network commands are available:\n\n```sqf\n\"Message to everyone, including JIP players!\" remoteExec [\"hint\", 0, true];\n```\n\nSee Arma 3: Remote Execution for more information.\n\nArma 3 alpha introduced BIS_fnc_MP (**obsolete** since Arma 3 v1.50, use the above version):\n\n```sqf\n[\"Message to everyone, including JIP  players!\", \"hint\", true, true] call BIS_fnc_MP;  // obsolete since Arma 3 v1.50, use remoteExec or remoteExecCall\n```\n\nArma 2 introduced the Arma 2: Multiplayer Framework (not present in Arma 3):\n\n```sqf\n// having the Functions module placed in the editor\nwaitUntil { not isNil \"BIS_MPF_InitDone\"; };\n[nil, nil, rHINT, \"Message to everyone!\"] call RE;\n```\n\n#### PublicVariable commands\n\nPublicVariable commands allow to send **global** variables to specified machines.\n- Network reception is guaranteed\n- Short variable names should be used for network performance\n- These commands shouldn't be used intensely for the same reason\n\n| Command | Effect | JIP synchronised |\n|---|---|---|\n| publicVariable | Set/update a variable value from the local machine to all the other machines (including server) | ✓ |\n| publicVariableServer | Set/update a variable value **from a client to the server** | ✗ |\n| publicVariableClient | Set/update a variable value **from the local machine** (not necessarily the server) **to a specific client** | ✗ |\n\n##### How it works\n\nThe server has the variable `ABC_Score` to broadcast:\n\n```sqf\nABC_Score = 5;                // sets the value\npublicVariable \"ABC_Score\"    // publishes the variable (do not forget the quotes!)\n```\n\nThis sends the variable name and value to the clients.\n- If the variable is not yet declared on their machine, it will declare it as well.\n- If the variable already exists, **the value is overridden** by the server's value.\n- If the variable changes again on the server, it has to be manually publicVariable'd once again!\n- A JIP player will synchronise **server's** publicVariable'd variables **before** executing **init.sqf**. See Initialisation Order for more information.\n  - A JIP player will **not** synchronise publicVariableClient-received variables after he disconnects/reconnects. Only server-known public variables sent with publicVariable will be synchronised.\n\n#### setVariable command\n\nAvailable since Arma 2, the **public** version of the setVariable command (alternative syntax) allows you to store a variable into an object and spread this variable across the network.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3 it is possible to broadcast the nil value, thus deleting the variable from the target.\n\n### Player connection events\n\nThe following commands will execute given code when a player is connecting or disconnecting. This code will run for players connecting in the lobby **and** for JIP players!\n- \"PlayerConnected\" mission Event Handler\n- \"PlayerDisconnected\" mission Event Handler\n\n> [!NOTE]\n> Before Arma 3 v1.58, use BIS_fnc_addStackedEventHandler for onPlayerConnected/onPlayerDisconnected.\n\n### Client state\n\nA client state is the client's connection state. It can be obtained with getClientState and getClientStateNumber commands on both server and clients.\n\n| getClientStateNumber | getClientState | Description |\n|---|---|---|\n| 0 | \"NONE\" | No client (or singleplayer) |\n| 1 | \"CREATED\" | Client is created |\n| 2 | \"CONNECTED\" | Client is connected to server, message formats are registered |\n| 3 | \"LOGGED IN\" | Identity is created |\n| 4 | \"MISSION SELECTED\" | Mission is selected |\n| 5 | \"MISSION ASKED\" | Server was asked to send / not send mission |\n| 6 | \"ROLE ASSIGNED\" | Role was assigned (and confirmed) |\n| 7 | \"MISSION RECEIVED\" | Mission received |\n| 8 | \"GAME LOADED\" | Island loaded, vehicles received |\n| 9 | \"BRIEFING SHOWN\" | Briefing was displayed |\n| 10 | \"BRIEFING READ\" | Ready to play mission |\n| 11 | \"GAME FINISHED\" | Game was finished |\n| 12 | \"DEBRIEFING READ\" | Debriefing read, ready to continue with next mission |\n\n### Join In Progress (Armed Assault v1.00)\n\n**Join In Progress** (JIP) is the ability for a player to connect while a game is running, unlike in Operation Flashpoint where one had to wait for the game to be over.\n\nIt was introduced in  on Xbox and Armed Assault on PC.\n\nA player that joined in progress will be referred to as **JIP player**.\n\n> [!NOTE]\n> To disable JIP on a server:\n> - the server admin can disable playable slots on the role selection screen\n> - the mission designer can disable AI within mission config\n> However, JIP remains available if respawn is enabled in the mission.\n\n#### JIP Synchronisation\n\nA JIP player will have a lot of information synchronised (publicVariable'd and setVariable server variables for example) by the game **before** accessing the mission itself; see below:\n\n| Information | Arma 1 | Arma 2 | Arma 3 |\n|---|---|---|---|\n| date/time | ✓ | ✓ | ✓ |\n| date/time + setDate/skipTime | ✗ | ✗ | ✓ |\n| weather (overcast, fog) | ✗ | ✓ | ✓ |\n| weather + setOvercast/setFog/setRain/setLightnings | ✗ | ✗ | ✓ |\n| time passed since mission start (time command) |  |  | ✓ |\n| publicVariable-sent variables (Number, String, Structured Text, Array, Code) | ✓ | ✓ | ✓ |\n| publicVariable-sent variables (nil) | ✗ | ✗ | ✓ |\n| setVariable-assigned variables (when alternative syntax's *public* parameter is set to true) | N/A | ✓ | ✓ |\n| remoteExec- and remoteExecCall-executed code if *JIP* prerequisites are met | colspan=\"2\" N/A | ✓ |  |\n\n> [!WARNING]\n> All the **initialisation fields** code get executed again for **each and every JIP connecting player**.\n>\n> This means that code with global effect Global Effect (such as setDamage) **WILL** be re-executed (depending on locality)!\n\n#### Related Commands\n\n- remoteExec\n- remoteExecCall\n- didJIP\n- didJIPOwner\n- exportJIPMessages\n- isRemoteExecutedJIP\n\n### See also\n\n- Headless Client\n- Initialisation Order\n- Arma 3: Remote Execution\n\n## Structuring Multiplayer code\n\n### Responsibilities\n\n- The **server** initialises and works with **variables**\n- A connecting or connected **player-client** gets the mission data from the server\n- Once an objective is reached, **the server tells the players** via remoteExec/remoteExecCall, publicVariable or setVariable\n- Players can get their client-side UI code triggered by the server\nSee this earlier chapter to know how to target specific machines.\n\n#### Server\n\nThe **Server** must be considered as the one ruler of the mission. He is the game's referee and all the decisions should come from it. All the values on the server should be considered as **true**.\n\nConsider the server as a powerful machine where you can put all the mission conditions and heavy scripting on.\nIn case of a very heavy mission, the server can be assisted by Headless Clients (this involves a per-mission specific design).\n\nServer-side code must gather or wait all the variables (potentially from client-side scripts and publicVariableServer) and take and broadcast its decisions accordingly using publicVariable.\n\nServer-side code should ideally **not** make any reference to a player variable considering a server can potentially be **dedicated**, unless you want to force this mission to be player-hosted (such as Arma 2's campaign).\n\n> [!NOTE]\n> Use allPlayers, BIS_fnc_listPlayers, playableUnits (and switchableUnits for SP compatibility) to refer to players.\n\n#### Client\n\nThe **Client** must be considered as an average machine that can leave the game at any moment.\n**No mission-vital code must be executed on its side** and **no decisions must be taken client-side**.\n\nAgain, **one must expect that any client can disconnect at any moment**.\n\nThe client executes all the (local) UI code (Post Process Effects, Dialogs, etc.)\n\nThe player's machine should not deal with a great piece of code.\n\n> [!IMPORTANT]\n> Do not forget that a server **can** be a player, and therefore should execute player code in that case.\n\nThe proper way to check for player-side condition is\n\n```sqf\nif (hasInterface) then { /* (...) */ };\n```\n\nNote that the following example is **incorrect**:\n\n```sqf\nif (isServer) then\n{\n    // ...\n}\nelse // WRONG: a server CAN be a player\n{\n    // ...\n};\n```\n\n### Code writing\n\nThe usual four steps of coding are the following:\n- Think it well\n  - If you cannot figure out how to write your code, say what you want to do out loud or write it down in your language, then replace it by code little by little.\n- Make it work\n  - use the -showScriptErrors startup parameter to see your code errors.\n- Make it readable\n  - name your variables properly, as if you had to give it to someone that should get it without the need of explaining\n- Optimise then\n  - use more performance-friendly commands, reduce your search radius and loop frequencies once everything works.\n\nSee Code Optimisation#Rules for advices and more information.\n\n### See also\n\n- Event Scripts\n- Code Optimisation\n\n## Local Multiplayer Testing\n\nTo ensure all cases, your mission should ideally work properly:\n- in Singleplayer\n- in Player-hosted Multiplayer\n- in a Dedicated Server-hosted game\n\nThe following chapters explain how to mimic multiple clients on one computer. Of course, nothing prevents you from inviting friends to play your mission and report bugs!\n\n### Dedicated Server\n\nTo properly test MP scripting locality issues, it is recommended to run a **dedicated server** and connect with **two** clients. In order to do so:\n- In your server executable's server.cfg: \n\n```cpp\nloopback = true;    // force LAN-only server\nkickDuplicate = 0;    // disable duplicate Arma kick\n\n// needed in case of Headless Client test only\nheadlessClients[]    = { \"127.0.0.1\" };\nlocalClient[]        = { \"127.0.0.1\" };\n```\n\n- Run the game twice from Steam and connect each (with `-showScriptErrors` flag)\n  - If you use one screen for the first client and the other screen for the second client, use `-noPause -window` launcher options. This will not pause render if the window doesn't have focus.\n\n> [!IMPORTANT]\n> Be sure to disable BattlEye or it will close any additional instances.\n\n- Try your mission and check for script errors:\n  - on client's screens and RPT files\n  - in your server's RPT files\n\n| Pros | Cons |\n|---|---|\n| - Tests almost all \"can go wrong\" scenarios<br>- Can test Headless Clients, persistent server, server restart, admin login/logout | - Misses cases where isDedicated is used instead of isServer<br>- \"Big\" setup |\n\n### Player-Hosted Server\n\nWhile this method covers less cases than the #Dedicated Server Test method above, this method is faster:\n- Open the Arma 3: Launcher and disable BattlEye\n- Select the mods that the host will use (if any)\n- Launch the game using the `Play`/`Play with Mods` button\n- Select the mods that clients will use\n- Launch the game again using the `Play`/`Play with Mods` button\n- In the first game instance (server), host the mission either through local hosting or with Eden Editor MP mission type launch\n- In the second game instance (client), join the session using the MP tab LAN section and entering the mission hosted by the server\n\n| Pros | Cons |\n|---|---|\n| - Fast setup (with quick modlist support)<br>- Helps find cases where isDedicated is used instead of isServer | - May miss locality issues (code that happens to run on the server because it runs on the server's *client* like e.g hideObjectGlobal)<br>- No headless client testing (this can be solved by using a custom server.cfg) |\n\n### See Also\n\n- Arma 3: Dedicated Server\n- server config","sections":[{"heading":null,"level":1,"markdown":"This page aims to explain notions and specificities of Multiplayer Scripting and its differences with Singleplayer Scripting.\n\nIt features three parts:\n1. #Notions and general knowledge\n1. #Structuring Multiplayer code\n1. Testing locally"},{"heading":"Notions and general knowledge","level":2,"markdown":""},{"heading":"The basics","level":3,"markdown":"- In Multiplayer, players are connected to a **server**.\n  - The server is a machine that distributes information among clients, such as unit positions, vehicle speeds, etc.\n  - The server can be either a dedicated machine, or hosted by a player; in the latter it means the server can have a player unit.\n- A machine connected to a server is called a **client**.\n  - Clients can join a mission *after* it started: they are considered \"JIP\" and scripting should be adapted to them. See the #Join In Progress chapter for more information.\n\n> [!NOTE]\n> In Singleplayer, the game acts as a player-hosted server (isServer returns true).\n\n> [!WARNING]\n> Some Multiplayer commands do **not** work in Singleplayer, such as netId!\n>\n> The other way around, some Singleplayer commands do not work in Multiplayer (e.g  setAccTime)."},{"heading":"Locality","level":3,"markdown":""},{"heading":"Definitions","level":4,"markdown":"- **LOCAL** is an attribute for the machine where the command/script/function is executed or the AI calculated.\n  - to check if an argument is local, use the local command\n- **REMOTE** means **non local** - on another machine. All player-controlled soldiers are remote units to a dedicated server, for example.\n  - to check if an argument is remote, simply use `not local _myObject`\n- commands arguments and effects can be either **local** or **global**:\n\n|  |  |\n|---|---|\n| Local Argument | a **local** argument means an argument that is processed on the machine where the command is executed |\n| Global Argument | a **global** argument means any argument, even a remote one |\n| Local Effect | a **local** effect means that the effect will only happen on the machine where the command is executed |\n| Global Effect | a **global** effect means that all the computers will receive it |\n| Server Execution | **server exec** means that the command or function has to be executed on the server machine, either mission host or dedicated server |\n\n> [!NOTE]\n> See also:\n> - Scripting Commands: Local Effect\n> - Scripting Commands: Global Effect\n> - Scripting Commands: Server Execution\n> - Functions: Local Effect\n> - Functions: Global Effect\n> - Functions: Server Execution"},{"heading":"Different machines and how to target them","level":4,"markdown":"> [!NOTE]\n> - For obvious reasons, a server cannot be JIP.\n> - Use didJIP to determine if a client joined during the game.\n\n| Scripting Commands | Server | Player client | Headless client | Note |  |\n|---|---|---|---|---|---|\n| Dedicated | Player-Hosted |  |  |  |  |\n| ```sqf<br>isDedicated<br>``` | ✓ | ✗ | ✗ | ✗ | Dedicated server |\n| ```sqf<br>hasInterface && isServer<br>``` | ✗ | ✓ | ✗ | ✗ | Player server |\n| ```sqf<br>hasInterface && not isServer<br>``` | ✗ | ✗ | ✓ | ✗ | Player client |\n| ```sqf<br>not hasInterface && not isDedicated<br>``` | ✗ | ✗ | ✗ | ✓ | Headless client |\n| ```sqf<br>isServer<br>``` | ✓ | ✓ | ✗ | ✗ | Any server |\n| ```sqf<br>hasInterface<br>``` | ✗ | ✓ | ✓ | ✗ | Any player |\n| Miscellaneous |  |  |  |  |  |\n| ```sqf<br>not isServer<br>``` | ✗ | ✗ | ✓ | ✓ | All server clients, including headless clients, but excluding player host |\n| ```sqf<br>not isDedicated<br>``` | ✗ | ✓ | ✓ | ✓ | Everything but a dedicated server |\n| ```sqf<br>not hasInterface<br>``` | ✓ | ✗ | ✗ | ✓ | Headless clients and dedicated server |\n\n**For an extended version for all games, click**\n\n> [!NOTE]\n> Before Operation Flashpoint v1.99 and the backport of isServer, the server could be identified by placing a Game Logic in the editor (that would always remain local to the server), then using the following: `local myLogic`.\n\n| Targeted machine | Operation Flashpoint | Armed Assault | Arma 2 | Arma 3 |\n|---|---|---|---|---|\n| **Dedicated Server**<br>A server without a human player behind it | ```sqf<br>isServer && isNull player<br>``` | ```sqf<br>isServer && isNull player<br>``` | ```sqf<br>isDedicated<br>``` | ```sqf<br>isDedicated<br>``` |\n| **Player Server**<br>A server hosted by a player | ```sqf<br>isServer && not isNull player<br>``` | ```sqf<br>isServer && not isNull player<br>``` | ```sqf<br>isServer && not isDedicated<br>``` | ```sqf<br>hasInterface && isServer<br>``` |\n| **Server**<br>Any server, dedicated or hosted | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` | ```sqf<br>isServer<br>``` |\n| **Player Client**<br>A player connected since the lobby | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>not isServer && not isNull player<br>``` | ```sqf<br>hasInterface && not isServer<br>``` |\n| **JIP Player Client**<br>A player connected in the middle of a mission | N/A | ```sqf<br>not isServer && isNull player<br>``` | ```sqf<br>not isServer && isNull player<br>``` | ```sqf<br>hasInterface && didJIP<br>``` |\n| **Headless Client**<br>A client without a human player behind it<br>(used to offload server calculations) | colspan=\"3\" N/A | ```sqf<br>not hasInterface && not isServer<br>``` |  |  |\n| **JIP Headless Client**<br>Headless client connected during the ongoing mission | colspan=\"3\" N/A | ```sqf<br>not hasInterface && not isServer && didJIP<br>``` |  |  |\n\n- If you want to know if the current machine is a server (Dedicated Server or Player Server), use isServer.\n- If you want to know if the current machine has a player (Player Server included), use hasInterface.\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3, a server-only init file is available: **initServer.sqf** (see Event Scripts)\n\n> [!NOTE]\n> **Arma 3:** **BIS_fnc_getNetMode** can be used to have a string value representing the local machine status (\"DedicatedServer\", \"Server\", \"HeadlessClient\", \"Client\", \"SinglePlayer\" ).\n>\n> This function doesn't make the JIP distinction and should be used along didJIP."},{"heading":"General information about locality","level":4,"markdown":"- about player:\n  - a player's unit is **always** local to the (human) player's machine\n  - a dedicated server doesn't have a player unit (`isNull player` returns true)\n  - to know if a certain unit is *a* player, use isPlayer\n- groups and AI:\n  - an AI group with a player-leader will be local to the player's computer\n  - a subordinate player being in a player-lead group will remain local to its computer (see bulletpoint #1)\n- objects:\n  - a driven vehicle is always local to the machine of its driver (not the commander's, not the gunner's)\n  - terrain objects (buildings, vegetation, roads etc.) are local everywhere (`local nearestBuilding player` returns true on every client)\n  - editor-placed objects and empty vehicles are local to the server\n  - editor-placed **triggers** are created on every machine unless specified otherwise (\"Server Only\" Eden Editor option ticked)\n  - units created with createUnit will be local to the computer that issued the command\n  - objects and vehicles created with createVehicle will be local to the computer that issued the command"},{"heading":"Locality changes","level":4,"markdown":"- if the player-leader dies, the AI is transferred to the machine where the new leader is local (server in case of AI, client in case of another player)\n- joining AI units will change locality to the new leader's computer\n- locality will change from server to client when a player gets in an empty vehicle\n- locality can also change in the event of a Team Switch or usage of selectPlayer\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 the \"Local\" Event Handler triggers when an object's locality is changed."},{"heading":"Code examples","level":4,"markdown":"| Code | Argu-ments | Effect | Description |\n|---|---|---|---|\n| ```sqf<br>remoteUnit setDamage 1;<br>``` | Global Argument | Global Effect | Any unit (local or remote) will die, and all the computers will know |\n| ```sqf<br>localUnit addMagazine \"30Rnd_556x45_STANAG\";<br>``` | Local Argument | Global Effect | Only a local unit can have its inventory edited with this command, but all the machines will be notified: if a player looks into the *localUnit* inventory, the added magazine will be there |\n| ```sqf<br>remoteUnit setFace \"Miller\";<br>``` | Global Argument | Local Effect | Any unit (local or remote) can get its face changed, but the new face will not be propagated through the network. Only the local machine's player will see the effect of the command<br>> [!NOTE]<br>> This command should ideally be **executed on every machine**, for example with:<br>><br>> ```sqf<br>> [remoteUnit, \"Miller\"] remoteExec [\"setFace\", 0, true];<br>> ```<br>><br>> See the #Remote Execution chapter for more information. |\n| ```sqf<br>localCamera cameraEffect [\"Internal\", \"Back\"];<br>``` | Local Argument | Local Effect | Only a local camera can be entered, and of course only the local machine will see through this camera |"},{"heading":"Network ID","level":3,"markdown":"Network IDs identify machines and network objects. They can be used to target proper machines with remote execution; see the #Remote Execution chapter for more information.\n\n> [!WARNING]\n> **A machine ID** (ownerID) is not to be confused with **an object's network ID** (netId)."},{"heading":"Machine network ID","level":4,"markdown":"Every machine, including the server, has a **network ID**.\n\nA server always has an ID of **2**, every new client has the next number (the first client will be number **3**, second client number **4**, etc.)\n- To get the current machine's ID, use clientOwner.\n- To get the machine ID of an object's owner, use owner *object*  (MP only).\n- To get the machine ID of a group's owner, use groupOwner *object* (MP only).\n\n> [!NOTE]\n> **0** and **1** are special values:\n> - **0** means **everyone** (including the server)\n> - **1** means **current machine** but **is not implemented** and should **not** be used."},{"heading":"Object network ID","level":4,"markdown":"Every object synchronised through the network has a network ID, shortened to **netId**.\n- To get an object's netId, use netId (MP only). **SP & MP variant:** BIS_fnc_netId\n- To get an object from a netId, use objectFromNetId (MP only). **SP & MP variant:** BIS_fnc_objectFromNetId\n- To get a group from a netId, use groupFromNetId (MP only). **SP & MP variant:** BIS_fnc_groupFromNetId"},{"heading":"Sending information across network","level":3,"markdown":""},{"heading":"Remote Execution","level":4,"markdown":"Since Arma 3 v1.50, remoteExec and remoteExecCall efficient engine network commands are available:\n\n```sqf\n\"Message to everyone, including JIP players!\" remoteExec [\"hint\", 0, true];\n```\n\nSee Arma 3: Remote Execution for more information.\n\nArma 3 alpha introduced BIS_fnc_MP (**obsolete** since Arma 3 v1.50, use the above version):\n\n```sqf\n[\"Message to everyone, including JIP  players!\", \"hint\", true, true] call BIS_fnc_MP;  // obsolete since Arma 3 v1.50, use remoteExec or remoteExecCall\n```\n\nArma 2 introduced the Arma 2: Multiplayer Framework (not present in Arma 3):\n\n```sqf\n// having the Functions module placed in the editor\nwaitUntil { not isNil \"BIS_MPF_InitDone\"; };\n[nil, nil, rHINT, \"Message to everyone!\"] call RE;\n```"},{"heading":"PublicVariable commands","level":4,"markdown":"PublicVariable commands allow to send **global** variables to specified machines.\n- Network reception is guaranteed\n- Short variable names should be used for network performance\n- These commands shouldn't be used intensely for the same reason\n\n| Command | Effect | JIP synchronised |\n|---|---|---|\n| publicVariable | Set/update a variable value from the local machine to all the other machines (including server) | ✓ |\n| publicVariableServer | Set/update a variable value **from a client to the server** | ✗ |\n| publicVariableClient | Set/update a variable value **from the local machine** (not necessarily the server) **to a specific client** | ✗ |"},{"heading":"How it works","level":5,"markdown":"The server has the variable `ABC_Score` to broadcast:\n\n```sqf\nABC_Score = 5;                // sets the value\npublicVariable \"ABC_Score\"    // publishes the variable (do not forget the quotes!)\n```\n\nThis sends the variable name and value to the clients.\n- If the variable is not yet declared on their machine, it will declare it as well.\n- If the variable already exists, **the value is overridden** by the server's value.\n- If the variable changes again on the server, it has to be manually publicVariable'd once again!\n- A JIP player will synchronise **server's** publicVariable'd variables **before** executing **init.sqf**. See Initialisation Order for more information.\n  - A JIP player will **not** synchronise publicVariableClient-received variables after he disconnects/reconnects. Only server-known public variables sent with publicVariable will be synchronised."},{"heading":"setVariable command","level":4,"markdown":"Available since Arma 2, the **public** version of the setVariable command (alternative syntax) allows you to store a variable into an object and spread this variable across the network.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3 it is possible to broadcast the nil value, thus deleting the variable from the target."},{"heading":"Player connection events","level":3,"markdown":"The following commands will execute given code when a player is connecting or disconnecting. This code will run for players connecting in the lobby **and** for JIP players!\n- \"PlayerConnected\" mission Event Handler\n- \"PlayerDisconnected\" mission Event Handler\n\n> [!NOTE]\n> Before Arma 3 v1.58, use BIS_fnc_addStackedEventHandler for onPlayerConnected/onPlayerDisconnected."},{"heading":"Client state","level":3,"markdown":"A client state is the client's connection state. It can be obtained with getClientState and getClientStateNumber commands on both server and clients.\n\n| getClientStateNumber | getClientState | Description |\n|---|---|---|\n| 0 | \"NONE\" | No client (or singleplayer) |\n| 1 | \"CREATED\" | Client is created |\n| 2 | \"CONNECTED\" | Client is connected to server, message formats are registered |\n| 3 | \"LOGGED IN\" | Identity is created |\n| 4 | \"MISSION SELECTED\" | Mission is selected |\n| 5 | \"MISSION ASKED\" | Server was asked to send / not send mission |\n| 6 | \"ROLE ASSIGNED\" | Role was assigned (and confirmed) |\n| 7 | \"MISSION RECEIVED\" | Mission received |\n| 8 | \"GAME LOADED\" | Island loaded, vehicles received |\n| 9 | \"BRIEFING SHOWN\" | Briefing was displayed |\n| 10 | \"BRIEFING READ\" | Ready to play mission |\n| 11 | \"GAME FINISHED\" | Game was finished |\n| 12 | \"DEBRIEFING READ\" | Debriefing read, ready to continue with next mission |"},{"heading":"Join In Progress (Armed Assault v1.00)","level":3,"markdown":"**Join In Progress** (JIP) is the ability for a player to connect while a game is running, unlike in Operation Flashpoint where one had to wait for the game to be over.\n\nIt was introduced in  on Xbox and Armed Assault on PC.\n\nA player that joined in progress will be referred to as **JIP player**.\n\n> [!NOTE]\n> To disable JIP on a server:\n> - the server admin can disable playable slots on the role selection screen\n> - the mission designer can disable AI within mission config\n> However, JIP remains available if respawn is enabled in the mission."},{"heading":"JIP Synchronisation","level":4,"markdown":"A JIP player will have a lot of information synchronised (publicVariable'd and setVariable server variables for example) by the game **before** accessing the mission itself; see below:\n\n| Information | Arma 1 | Arma 2 | Arma 3 |\n|---|---|---|---|\n| date/time | ✓ | ✓ | ✓ |\n| date/time + setDate/skipTime | ✗ | ✗ | ✓ |\n| weather (overcast, fog) | ✗ | ✓ | ✓ |\n| weather + setOvercast/setFog/setRain/setLightnings | ✗ | ✗ | ✓ |\n| time passed since mission start (time command) |  |  | ✓ |\n| publicVariable-sent variables (Number, String, Structured Text, Array, Code) | ✓ | ✓ | ✓ |\n| publicVariable-sent variables (nil) | ✗ | ✗ | ✓ |\n| setVariable-assigned variables (when alternative syntax's *public* parameter is set to true) | N/A | ✓ | ✓ |\n| remoteExec- and remoteExecCall-executed code if *JIP* prerequisites are met | colspan=\"2\" N/A | ✓ |  |\n\n> [!WARNING]\n> All the **initialisation fields** code get executed again for **each and every JIP connecting player**.\n>\n> This means that code with global effect Global Effect (such as setDamage) **WILL** be re-executed (depending on locality)!"},{"heading":"Related Commands","level":4,"markdown":"- remoteExec\n- remoteExecCall\n- didJIP\n- didJIPOwner\n- exportJIPMessages\n- isRemoteExecutedJIP"},{"heading":"See also","level":3,"markdown":"- Headless Client\n- Initialisation Order\n- Arma 3: Remote Execution"},{"heading":"Structuring Multiplayer code","level":2,"markdown":""},{"heading":"Responsibilities","level":3,"markdown":"- The **server** initialises and works with **variables**\n- A connecting or connected **player-client** gets the mission data from the server\n- Once an objective is reached, **the server tells the players** via remoteExec/remoteExecCall, publicVariable or setVariable\n- Players can get their client-side UI code triggered by the server\nSee this earlier chapter to know how to target specific machines."},{"heading":"Server","level":4,"markdown":"The **Server** must be considered as the one ruler of the mission. He is the game's referee and all the decisions should come from it. All the values on the server should be considered as **true**.\n\nConsider the server as a powerful machine where you can put all the mission conditions and heavy scripting on.\nIn case of a very heavy mission, the server can be assisted by Headless Clients (this involves a per-mission specific design).\n\nServer-side code must gather or wait all the variables (potentially from client-side scripts and publicVariableServer) and take and broadcast its decisions accordingly using publicVariable.\n\nServer-side code should ideally **not** make any reference to a player variable considering a server can potentially be **dedicated**, unless you want to force this mission to be player-hosted (such as Arma 2's campaign).\n\n> [!NOTE]\n> Use allPlayers, BIS_fnc_listPlayers, playableUnits (and switchableUnits for SP compatibility) to refer to players."},{"heading":"Client","level":4,"markdown":"The **Client** must be considered as an average machine that can leave the game at any moment.\n**No mission-vital code must be executed on its side** and **no decisions must be taken client-side**.\n\nAgain, **one must expect that any client can disconnect at any moment**.\n\nThe client executes all the (local) UI code (Post Process Effects, Dialogs, etc.)\n\nThe player's machine should not deal with a great piece of code.\n\n> [!IMPORTANT]\n> Do not forget that a server **can** be a player, and therefore should execute player code in that case.\n\nThe proper way to check for player-side condition is\n\n```sqf\nif (hasInterface) then { /* (...) */ };\n```\n\nNote that the following example is **incorrect**:\n\n```sqf\nif (isServer) then\n{\n    // ...\n}\nelse // WRONG: a server CAN be a player\n{\n    // ...\n};\n```"},{"heading":"Code writing","level":3,"markdown":"The usual four steps of coding are the following:\n- Think it well\n  - If you cannot figure out how to write your code, say what you want to do out loud or write it down in your language, then replace it by code little by little.\n- Make it work\n  - use the -showScriptErrors startup parameter to see your code errors.\n- Make it readable\n  - name your variables properly, as if you had to give it to someone that should get it without the need of explaining\n- Optimise then\n  - use more performance-friendly commands, reduce your search radius and loop frequencies once everything works.\n\nSee Code Optimisation#Rules for advices and more information."},{"heading":"See also","level":3,"markdown":"- Event Scripts\n- Code Optimisation"},{"heading":"Local Multiplayer Testing","level":2,"markdown":"To ensure all cases, your mission should ideally work properly:\n- in Singleplayer\n- in Player-hosted Multiplayer\n- in a Dedicated Server-hosted game\n\nThe following chapters explain how to mimic multiple clients on one computer. Of course, nothing prevents you from inviting friends to play your mission and report bugs!"},{"heading":"Dedicated Server","level":3,"markdown":"To properly test MP scripting locality issues, it is recommended to run a **dedicated server** and connect with **two** clients. In order to do so:\n- In your server executable's server.cfg: \n\n```cpp\nloopback = true;    // force LAN-only server\nkickDuplicate = 0;    // disable duplicate Arma kick\n\n// needed in case of Headless Client test only\nheadlessClients[]    = { \"127.0.0.1\" };\nlocalClient[]        = { \"127.0.0.1\" };\n```\n\n- Run the game twice from Steam and connect each (with `-showScriptErrors` flag)\n  - If you use one screen for the first client and the other screen for the second client, use `-noPause -window` launcher options. This will not pause render if the window doesn't have focus.\n\n> [!IMPORTANT]\n> Be sure to disable BattlEye or it will close any additional instances.\n\n- Try your mission and check for script errors:\n  - on client's screens and RPT files\n  - in your server's RPT files\n\n| Pros | Cons |\n|---|---|\n| - Tests almost all \"can go wrong\" scenarios<br>- Can test Headless Clients, persistent server, server restart, admin login/logout | - Misses cases where isDedicated is used instead of isServer<br>- \"Big\" setup |"},{"heading":"Player-Hosted Server","level":3,"markdown":"While this method covers less cases than the #Dedicated Server Test method above, this method is faster:\n- Open the Arma 3: Launcher and disable BattlEye\n- Select the mods that the host will use (if any)\n- Launch the game using the `Play`/`Play with Mods` button\n- Select the mods that clients will use\n- Launch the game again using the `Play`/`Play with Mods` button\n- In the first game instance (server), host the mission either through local hosting or with Eden Editor MP mission type launch\n- In the second game instance (client), join the session using the MP tab LAN section and entering the mission hosted by the server\n\n| Pros | Cons |\n|---|---|\n| - Fast setup (with quick modlist support)<br>- Helps find cases where isDedicated is used instead of isServer | - May miss locality issues (code that happens to run on the server because it runs on the server's *client* like e.g hideObjectGlobal)<br>- No headless client testing (this can be solved by using a custom server.cfg) |"},{"heading":"See Also","level":3,"markdown":"- Arma 3: Dedicated Server\n- server config"}],"categories":["Arma Scripting Tutorials"],"groups":["Scripting"]},{"name":"Namespace","title":"Namespace","type":"topic","url":"https://community.bistudio.com/wiki/Namespace","revid":369024,"updated":"2024-08-26T13:59:25Z","aliases":[],"markdown":"Arma 2 v1.00\n\nA Namespace is a container for Variables.\nAny global variable is always part of exactly one namespace - another namespace may contain a variable with the same Identifier, but they remain two distinct independent variables.\nScripts and functions are always executed in the context of some namespace.\n\nThe default namespace is the missionNamespace.\n\n### Namespaces\n\n| Game | Namespace | Description | Lifetime |\n|---|---|---|---|\n| Arma 2 v1.00 | missionNamespace | The global namespace of the mission. Every mission has its own missionNamespace. | Mission duration |\n| Arma 2 v1.00 | parsingNamespace | The global namespace attached to the Config Parser. | Game session |\n| Arma 2 v1.00 | uiNamespace | The global namespace attached to the user interface. | Game session |\n| Take On Helicopters v1.00 | profileNamespace | The global namespace attached to the user profile. | Profile lifetime |\n| Arma 3 v2.00 | localNamespace | This namespace is like the missionNamespace, except that its variables can not be sent over network (e.g. with publicVariable) or serialised. | Mission duration |\n| Arma 3 v2.06 | serverNamespace | The namespace used by Server Event Handlers. This namespace is only available on servers. | Game session |\n| Arma 3 v2.10 | missionProfileNamespace | This namespace is like profileNamespace but is also attached to a missionName or missionGroup. Automatically loaded before init.sqf. | Profile lifetime |\n\n### Serialisation\n\nOnly the missionNamespace is serialised, as in only the variables from this namespace are saved when the game is saved (e.g. with saveGame) and loaded when the game is loaded (e.g. with loadGame).\nThis is also the reason the game will complain that one should use disableSerialization when storing UI variables in missionNamespace - UI elements are temporary and therefore exempt from serialisation by default.\n\n### Scripting\n\nInteracting with namespaces is not difficult:\n- The getVariable and setVariable commands can be used to work with variables from different namespaces.\n- The with-do construct can be used to switch the context of an entire code block to another namespace.\n- The currentNamespace command can be used to obtain the namespace which the calling script is running in.","sections":[{"heading":null,"level":1,"markdown":"Arma 2 v1.00\n\nA Namespace is a container for Variables.\nAny global variable is always part of exactly one namespace - another namespace may contain a variable with the same Identifier, but they remain two distinct independent variables.\nScripts and functions are always executed in the context of some namespace.\n\nThe default namespace is the missionNamespace."},{"heading":"Namespaces","level":3,"markdown":"| Game | Namespace | Description | Lifetime |\n|---|---|---|---|\n| Arma 2 v1.00 | missionNamespace | The global namespace of the mission. Every mission has its own missionNamespace. | Mission duration |\n| Arma 2 v1.00 | parsingNamespace | The global namespace attached to the Config Parser. | Game session |\n| Arma 2 v1.00 | uiNamespace | The global namespace attached to the user interface. | Game session |\n| Take On Helicopters v1.00 | profileNamespace | The global namespace attached to the user profile. | Profile lifetime |\n| Arma 3 v2.00 | localNamespace | This namespace is like the missionNamespace, except that its variables can not be sent over network (e.g. with publicVariable) or serialised. | Mission duration |\n| Arma 3 v2.06 | serverNamespace | The namespace used by Server Event Handlers. This namespace is only available on servers. | Game session |\n| Arma 3 v2.10 | missionProfileNamespace | This namespace is like profileNamespace but is also attached to a missionName or missionGroup. Automatically loaded before init.sqf. | Profile lifetime |"},{"heading":"Serialisation","level":3,"markdown":"Only the missionNamespace is serialised, as in only the variables from this namespace are saved when the game is saved (e.g. with saveGame) and loaded when the game is loaded (e.g. with loadGame).\nThis is also the reason the game will complain that one should use disableSerialization when storing UI variables in missionNamespace - UI elements are temporary and therefore exempt from serialisation by default."},{"heading":"Scripting","level":3,"markdown":"Interacting with namespaces is not difficult:\n- The getVariable and setVariable commands can be used to work with variables from different namespaces.\n- The with-do construct can be used to switch the context of an entire code block to another namespace.\n- The currentNamespace command can be used to obtain the namespace which the calling script is running in."}],"categories":["Data Types","Introduced with Arma 2 version 1.00"],"groups":["Data Types"]},{"name":"NaN","title":"NaN","type":"topic","url":"https://community.bistudio.com/wiki/NaN","revid":245383,"updated":"2021-02-11T19:08:30Z","aliases":[],"markdown":"**Description:**\n\nA dummy data type to trigger errors.\n\nIntroduced with Arma 3.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\n\nA dummy data type to trigger errors.\n\nIntroduced with Arma 3."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Nothing","title":"Nothing","type":"topic","url":"https://community.bistudio.com/wiki/Nothing","revid":87135,"updated":"2014-12-22T17:42:31Z","aliases":[],"markdown":"An expression of type **Nothing** is no value. It cannot be assigned to a variable. It exists because each expression needs to return some value and needs to have some clearly identified type.\n\nIts presence can be checked using isNil.","sections":[{"heading":null,"level":1,"markdown":"An expression of type **Nothing** is no value. It cannot be assigned to a variable. It exists because each expression needs to return some value and needs to have some clearly identified type.\n\nIts presence can be checked using isNil."}],"categories":["Magic Types"],"groups":["Data Types"]},{"name":"Number","title":"Number","type":"topic","url":"https://community.bistudio.com/wiki/Number","revid":373155,"updated":"2025-04-07T12:09:57Z","aliases":["Scalar"],"markdown":"A number is, depending on scope, either a [single precision floating-point number](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) (when talking about scripting) or a range of numerical types when talking about config context.\n\n### Scripting\n\nIn SQF, there are multiple accepted number formats.\nHowever, all of them will result in the same `SCALAR` (typeName) value type **as long as they remain within float range**;\n\n|  |  |  |  |\n|---|---|---|---|\n| + Infinity string representation | Value | Before<br>Arma 3 v2.18 | Since<br>Arma 3 v2.18 |\n| +Inf | `1.#INF` | `inf` |  |\n| -Inf | `-1.#INF` | `-inf` |  |\n\nThe **largest positive** number that can be achieved is `3.4028235e38` and the **largest negative** is `-3.4028235e38`.\nIt is possible to generate positive or negative infinity values using either `1e39` or `-1e39`, both being of `\"NaN\"` typeName.\n\nTo check if a number is finite one can use the finite operator.\n\n> [!NOTE]\n> Regex to match all numbers in SQF is `(((\\$|0x)[0-9a-fA-F]+)|(\\.[0-9]+))|(\\b[0-9]+(\\.[0-9]+|[eE][-+]?[0-9]+)?)\\b`\n\n> [!IMPORTANT]\n> Due to technical limitations, the precision of floating-point numbers is limited. Please refer to [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) for more info about the technical details.\n\n#### Decimal (Base 10)\n\nA decimal number is your normal `0.5` syntax stuff with one extra: You may omit the initial pack of digits.\n\nSome Examples would be:\n- `5.197`\n- `0.47`\n- `16.0`\n- `.8314`\n- `12345`\n\nA regex catching these kind of numbers could look like this `((\\.[0-9]+)|(\\b[0-9]+(\\.[0-9]+)?))\\b`\n\n##### Scientific Notation\n\nThe [Scientific Notation](https://en.wikipedia.org/wiki/Scientific_notation) is a way of expressing numbers that are too big or too small to be conveniently written in decimal form.\n\nIt starts of like a normal decimal and then gets expressed by an `E` (Not case-sensitive, thus `e` is also valid) followed by an **optional** `+` or `-` sign and ends with a range of digits.\n\nSome examples would be:\n- `1.23E4 ⇔ 1.23 ⋅ 104  ⇔ 12300`\n- `5e-2   ⇔    5 ⋅ 10-2 ⇔  0.05`\n\nA regex catching these kind of numbers could look like this  `([0-9]+.)?[0-9]+[eE][+-]?[0-9]+`\n\n#### Hexadecimal (Base 16)\n\nIn SQF, [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) (also base 16, or hex) is a positional numeral system with a base of 16.\nThey start either with `0x` or with a single `$`.\n\nThis gets followed by one of the following characters: `0 1 2 3 4 5 6 7 8 9 A B C D E F`.\n\nNote that casing does not matter, thus both `0xa` and `0xA` are valid.\n\nSome Examples would be:\n- `0xa5`\n- `$5C`\n- `$FFFFFF`\n- `0x123ABC`\n\nA regex catching these kind of numbers could look like this `((\\$|0x)[0-9a-fA-F]+)\\b`\n\n### Config\n\nUnlike scripting, configs actually do allow for multiple number types (Integer, Float, etc). They are properly stored with their corresponding type in mind.\n\n> [!NOTE]\n> In a config, a Number can also mean a Boolean: in Description.ext for example, `disabledAI = 1;` means true.\n\n```cpp\nclass MyClass\n{\n    myInt = 1;        // integer\n    myFloat = 0.01;    // float\n};\n\n// description.ext example\ndisabledAI = 1;        // boolean: 0 = false, everything else = true (usually 1)\n```\n\n### Floating-point Precision\n\nHumans are typically used to performing mathematical calculations on the set of *real numbers* (ℝ). There are no gaps between real numbers, i.e. there is always another real number between two real numbers. However, as mentioned above, every number in scripting is a *floating-point number*. Because any given floating-point number can only consist of a finite amount of bits (a computer's memory is finite after all), any given floating-point format can only represent a finite amount of distinct numbers. Consequently, there are gaps between floating-point numbers.\n\nThis induces the following problem: There are real numbers that the computer does not have a binary representation for (and that it therefore can not work with) because there is no representation for these numbers in the specific floating-point format used by the computer. Of course, by extension, this also applies to the Real Virtuality Engine - there are real numbers that it does not have a representation for.\n\nThis issue is dealt with by rounding to the nearest number that can actually be represented as a floating-point number.\n\n| `n` ∈ ℝ | `n` in Arma 3<br>(value of `n toFixed 20`) |\n|---|---|\n| 0 | 0.00000000000000000000 |\n| 1 | 1.00000000000000000000 |\n| 1.1 | 1.10000002384185790000 |\n| 2.5 | 2.50000000000000000000 |\n| 2.51 | 2.50999999046325680000 |\n\nUnfortunately, this rounding introduces a new problem in the form of unexpected, seemingly erroneous behaviour: For instance, despite being entirely correct mathematically, the expression `0.3 + 0.4 == 0.7` surprisingly returns false in Arma 3. In order to understand why this happens, examine the evaluation of the expression step by step:\n1. The 0.3 from the source code has to be rounded to 0.30000001192092896\n1. The 0.4 from the source code has to be rounded to 0.40000000596046448\n1. Now the addition can be performed: 0.30000001192092896 + 0.40000000596046448 = 0.70000004768371582\n(that is the result with floating-point arithmetic; the result of the same addition in ℝ is 0.70000001788139344)\n1. The 0.7 from the source code has to be rounded to 0.69999998807907104\n1. Finally, the comparison `0.70000004768371582 == 0.69999998807907104` returns false\n\nTo add to the confusion, `0.3 + 0.4` will actually output `0.7` in the Debug Console or when used with commands like hint or systemChat - that is because numbers are rounded yet again when they are converted to String for the output. If this needs to be avoided, the toFixed command can be used to obtain the accurate value of a number.\n\nFloating-point formats are designed so that the density of floating-point numbers is highest around the number zero. Accordingly, there are more floating-point numbers between 0 and 1 than there are between 100,000 and 100,001. As such, the gaps between consecutive floating-point numbers with small absolute values are also small, while the gaps between consecutive floating-point numbers with large absolute values become increasingly larger. For instance, the next larger floating-point number after 87,654,320 is 87,654,328 in Arma 3.\n\n#### Consequences\n\n- Fractional floating-point numbers should not be compared for exact equality. Instead, one should check the distance (i.e. absolute difference) between the numbers. Numbers can then be considered equal if the distance between them is smaller than some threshold (e.g. 0.000001). Consequently, expressions like `0.3 + 0.4 == 0.7` should be replaced with expressions such as `_res = 0.3 + 0.4; abs (_res - 0.7) < 0.000001`.\nNote that this is only necessary if fractional numbers are involved; if only whole numbers are involved, this procedure is not necessary.\n- Large numbers can not always be incremented / decremented. For example, `87654320 + 1` returns `87,654,320` because any real number between 87,654,316 and 87,654,324 has to be rounded to 87,654,320 in Arma 3.\n\n### String Number Formats\n\nArma 3 v2.20\nSome config entries or script parameters support receiving numbers as a string.\n\nThese string formats are Case-Sensitive!\n\n#### Time\n\nSpecifies a time duration.\n\nTime also supports decimals like \"0.5s\".\n\nSupported variants:\n\n```cpp\n\"5ns\" // Nanoseconds\n\"5us\" // Microseconds\n\"5ms\" // Milliseconds\n\"5s\" // Seconds\n\"5m\" // Minutes\n\"5h\" // Hours\n\"5d\" // Days\n\"5fps\" // Duration of one frame at specified frames per second rate (5fps = 1000ms/5 = 200ms = 0.2s)\n```\n\n#### Data Size\n\nSpecifies some amount of data in bytes.\nDoes not support decimals like \"0.5MB\", only whole numbers like \"500KB\" are supported.\n\nSupported variants:\n\n```cpp\n\"5B\" // bytes\n\"5KB\" // Kilobytes\n\"5MB\" // Megabytes\n\"5GB\" // Gigabytes\n\"5TB\" // Terabytes\n\"5KiB\" // Kibibytes\n\"5MiB\" // Mebibytes\n\"5GiB\" // Gibibytes\n\"5TiB\" // Tibibytes\n```\n\n#### Data Transfer rate\n\nSpecifies a data transfer rates in Bytes or Bits per second\nDoes not support decimals like \"0.5Mbps\", only whole numbers like \"500kbps\" are supported.\n\nSupported variants:\n\n```cpp\n\"5bps\" // Bits per second\n\"5kbps\" // Kilobits per second\n\"5Mbps\" // Megabits per second\n\"5Gbps\" // Gigabits per second\n\"5bit/s\" // Bits per second\n\"5kbit/s\" // Kilobits per second\n\"5Mbit/s\" // Megabits per second\n\"5Gbit/s\" // Gigabits per second\n\n\"5Kibps\" // Kibibits per second\n\"5Mibps\" // Mebibits per second\n\"5Gibps\" // Gibibits per second\n\"5Kibit/s\" // Kibibits per second\n\"5Mibit/s\" // Mebibits per second\n\"5Gibit/s\" // Gibibits per second\n\n\"5kB/s\" // Kilobytes per second\n\"5MB/s\" // Megabytes per second\n\"5GB/s\" // Gigabytes per second\n\n\"5KiB/s\" // Kibibytes per second\n\"5MiB/s\" // Mebibytes per second\n\"5GiB/s\" // Gibibytes per second\n```","sections":[{"heading":null,"level":1,"markdown":"A number is, depending on scope, either a [single precision floating-point number](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) (when talking about scripting) or a range of numerical types when talking about config context."},{"heading":"Scripting","level":3,"markdown":"In SQF, there are multiple accepted number formats.\nHowever, all of them will result in the same `SCALAR` (typeName) value type **as long as they remain within float range**;\n\n|  |  |  |  |\n|---|---|---|---|\n| + Infinity string representation | Value | Before<br>Arma 3 v2.18 | Since<br>Arma 3 v2.18 |\n| +Inf | `1.#INF` | `inf` |  |\n| -Inf | `-1.#INF` | `-inf` |  |\n\nThe **largest positive** number that can be achieved is `3.4028235e38` and the **largest negative** is `-3.4028235e38`.\nIt is possible to generate positive or negative infinity values using either `1e39` or `-1e39`, both being of `\"NaN\"` typeName.\n\nTo check if a number is finite one can use the finite operator.\n\n> [!NOTE]\n> Regex to match all numbers in SQF is `(((\\$|0x)[0-9a-fA-F]+)|(\\.[0-9]+))|(\\b[0-9]+(\\.[0-9]+|[eE][-+]?[0-9]+)?)\\b`\n\n> [!IMPORTANT]\n> Due to technical limitations, the precision of floating-point numbers is limited. Please refer to [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) for more info about the technical details."},{"heading":"Decimal (Base 10)","level":4,"markdown":"A decimal number is your normal `0.5` syntax stuff with one extra: You may omit the initial pack of digits.\n\nSome Examples would be:\n- `5.197`\n- `0.47`\n- `16.0`\n- `.8314`\n- `12345`\n\nA regex catching these kind of numbers could look like this `((\\.[0-9]+)|(\\b[0-9]+(\\.[0-9]+)?))\\b`"},{"heading":"Scientific Notation","level":5,"markdown":"The [Scientific Notation](https://en.wikipedia.org/wiki/Scientific_notation) is a way of expressing numbers that are too big or too small to be conveniently written in decimal form.\n\nIt starts of like a normal decimal and then gets expressed by an `E` (Not case-sensitive, thus `e` is also valid) followed by an **optional** `+` or `-` sign and ends with a range of digits.\n\nSome examples would be:\n- `1.23E4 ⇔ 1.23 ⋅ 104  ⇔ 12300`\n- `5e-2   ⇔    5 ⋅ 10-2 ⇔  0.05`\n\nA regex catching these kind of numbers could look like this  `([0-9]+.)?[0-9]+[eE][+-]?[0-9]+`"},{"heading":"Hexadecimal (Base 16)","level":4,"markdown":"In SQF, [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) (also base 16, or hex) is a positional numeral system with a base of 16.\nThey start either with `0x` or with a single `$`.\n\nThis gets followed by one of the following characters: `0 1 2 3 4 5 6 7 8 9 A B C D E F`.\n\nNote that casing does not matter, thus both `0xa` and `0xA` are valid.\n\nSome Examples would be:\n- `0xa5`\n- `$5C`\n- `$FFFFFF`\n- `0x123ABC`\n\nA regex catching these kind of numbers could look like this `((\\$|0x)[0-9a-fA-F]+)\\b`"},{"heading":"Config","level":3,"markdown":"Unlike scripting, configs actually do allow for multiple number types (Integer, Float, etc). They are properly stored with their corresponding type in mind.\n\n> [!NOTE]\n> In a config, a Number can also mean a Boolean: in Description.ext for example, `disabledAI = 1;` means true.\n\n```cpp\nclass MyClass\n{\n    myInt = 1;        // integer\n    myFloat = 0.01;    // float\n};\n\n// description.ext example\ndisabledAI = 1;        // boolean: 0 = false, everything else = true (usually 1)\n```"},{"heading":"Floating-point Precision","level":3,"markdown":"Humans are typically used to performing mathematical calculations on the set of *real numbers* (ℝ). There are no gaps between real numbers, i.e. there is always another real number between two real numbers. However, as mentioned above, every number in scripting is a *floating-point number*. Because any given floating-point number can only consist of a finite amount of bits (a computer's memory is finite after all), any given floating-point format can only represent a finite amount of distinct numbers. Consequently, there are gaps between floating-point numbers.\n\nThis induces the following problem: There are real numbers that the computer does not have a binary representation for (and that it therefore can not work with) because there is no representation for these numbers in the specific floating-point format used by the computer. Of course, by extension, this also applies to the Real Virtuality Engine - there are real numbers that it does not have a representation for.\n\nThis issue is dealt with by rounding to the nearest number that can actually be represented as a floating-point number.\n\n| `n` ∈ ℝ | `n` in Arma 3<br>(value of `n toFixed 20`) |\n|---|---|\n| 0 | 0.00000000000000000000 |\n| 1 | 1.00000000000000000000 |\n| 1.1 | 1.10000002384185790000 |\n| 2.5 | 2.50000000000000000000 |\n| 2.51 | 2.50999999046325680000 |\n\nUnfortunately, this rounding introduces a new problem in the form of unexpected, seemingly erroneous behaviour: For instance, despite being entirely correct mathematically, the expression `0.3 + 0.4 == 0.7` surprisingly returns false in Arma 3. In order to understand why this happens, examine the evaluation of the expression step by step:\n1. The 0.3 from the source code has to be rounded to 0.30000001192092896\n1. The 0.4 from the source code has to be rounded to 0.40000000596046448\n1. Now the addition can be performed: 0.30000001192092896 + 0.40000000596046448 = 0.70000004768371582\n(that is the result with floating-point arithmetic; the result of the same addition in ℝ is 0.70000001788139344)\n1. The 0.7 from the source code has to be rounded to 0.69999998807907104\n1. Finally, the comparison `0.70000004768371582 == 0.69999998807907104` returns false\n\nTo add to the confusion, `0.3 + 0.4` will actually output `0.7` in the Debug Console or when used with commands like hint or systemChat - that is because numbers are rounded yet again when they are converted to String for the output. If this needs to be avoided, the toFixed command can be used to obtain the accurate value of a number.\n\nFloating-point formats are designed so that the density of floating-point numbers is highest around the number zero. Accordingly, there are more floating-point numbers between 0 and 1 than there are between 100,000 and 100,001. As such, the gaps between consecutive floating-point numbers with small absolute values are also small, while the gaps between consecutive floating-point numbers with large absolute values become increasingly larger. For instance, the next larger floating-point number after 87,654,320 is 87,654,328 in Arma 3."},{"heading":"Consequences","level":4,"markdown":"- Fractional floating-point numbers should not be compared for exact equality. Instead, one should check the distance (i.e. absolute difference) between the numbers. Numbers can then be considered equal if the distance between them is smaller than some threshold (e.g. 0.000001). Consequently, expressions like `0.3 + 0.4 == 0.7` should be replaced with expressions such as `_res = 0.3 + 0.4; abs (_res - 0.7) < 0.000001`.\nNote that this is only necessary if fractional numbers are involved; if only whole numbers are involved, this procedure is not necessary.\n- Large numbers can not always be incremented / decremented. For example, `87654320 + 1` returns `87,654,320` because any real number between 87,654,316 and 87,654,324 has to be rounded to 87,654,320 in Arma 3."},{"heading":"String Number Formats","level":3,"markdown":"Arma 3 v2.20\nSome config entries or script parameters support receiving numbers as a string.\n\nThese string formats are Case-Sensitive!"},{"heading":"Time","level":4,"markdown":"Specifies a time duration.\n\nTime also supports decimals like \"0.5s\".\n\nSupported variants:\n\n```cpp\n\"5ns\" // Nanoseconds\n\"5us\" // Microseconds\n\"5ms\" // Milliseconds\n\"5s\" // Seconds\n\"5m\" // Minutes\n\"5h\" // Hours\n\"5d\" // Days\n\"5fps\" // Duration of one frame at specified frames per second rate (5fps = 1000ms/5 = 200ms = 0.2s)\n```"},{"heading":"Data Size","level":4,"markdown":"Specifies some amount of data in bytes.\nDoes not support decimals like \"0.5MB\", only whole numbers like \"500KB\" are supported.\n\nSupported variants:\n\n```cpp\n\"5B\" // bytes\n\"5KB\" // Kilobytes\n\"5MB\" // Megabytes\n\"5GB\" // Gigabytes\n\"5TB\" // Terabytes\n\"5KiB\" // Kibibytes\n\"5MiB\" // Mebibytes\n\"5GiB\" // Gibibytes\n\"5TiB\" // Tibibytes\n```"},{"heading":"Data Transfer rate","level":4,"markdown":"Specifies a data transfer rates in Bytes or Bits per second\nDoes not support decimals like \"0.5Mbps\", only whole numbers like \"500kbps\" are supported.\n\nSupported variants:\n\n```cpp\n\"5bps\" // Bits per second\n\"5kbps\" // Kilobits per second\n\"5Mbps\" // Megabits per second\n\"5Gbps\" // Gigabits per second\n\"5bit/s\" // Bits per second\n\"5kbit/s\" // Kilobits per second\n\"5Mbit/s\" // Megabits per second\n\"5Gbit/s\" // Gigabits per second\n\n\"5Kibps\" // Kibibits per second\n\"5Mibps\" // Mebibits per second\n\"5Gibps\" // Gibibits per second\n\"5Kibit/s\" // Kibibits per second\n\"5Mibit/s\" // Mebibits per second\n\"5Gibit/s\" // Gibibits per second\n\n\"5kB/s\" // Kilobytes per second\n\"5MB/s\" // Megabytes per second\n\"5GB/s\" // Gigabytes per second\n\n\"5KiB/s\" // Kibibytes per second\n\"5MiB/s\" // Mebibytes per second\n\"5GiB/s\" // Gibibytes per second\n```"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Object","title":"Object","type":"topic","url":"https://community.bistudio.com/wiki/Object","revid":352059,"updated":"2024-02-01T23:24:36Z","aliases":["Game Logic","Logic","ObjectRTD"],"markdown":"**Object** refers to a building block within a scenario. In general when using this term the author refers to the representation of an object (soldier, house, crate, etc.) that can be manipulated when in the 3D environment via the scripting language. As there is a special representation that is used in the mission editor, one might distinguish between a 'game object' (this article) and an 'editor object' (see Editor Object).\n\n### Object Type\n\nAn Object in the scripting language is a generic reference for a soldier, vehicle or building. Such an object can be animated (a house, a tank), can have AI associated with it (a soldier), or, simply be a rock. Various commands in the scripting language can refer as equally to generic (e.g. Object) types, as much as specific sub-types.\n\n```sqf\n_posAGL = getPos player;\n_posATL = getPosATL _house;\n```\n\n### Sub-types\n\nIn this wiki, when describing commands, various 'subtypes' of an object are distinguished. Although in general the commands accept parameters of type 'object', when a subtype is listed, the use of subtypes indicates that the command might not make sense or might not work on all objects.\n\n| Sub-type | Description | Only for |\n|---|---|---|\n| Vehicle | A vehicle is an object such as a tank, car, helicopter or jet. | - |\n| ObjectRTD, HelicopterRTD | A helicopter using the advanced flight model. | Arma 3, Take On Helicopters |\n| Game Logic | If a game logic is created via scripting after mission start, then the logic will be local to the client that created it. A logic is an invisible object with no model. It has a namespace like every object and it has simulation like most objects. <br>> [!NOTE]<br>> In multiplayer, a game logic will always be local to the host computer, if it was placed in the mission editor. This works on both dedicated and player-hosted servers. | - |\n| Person | A human | - |\n| Animal | An animal such as dog and goat. | - |\n| Rope | A rope is flexible and is connected to another object at one or both ends. See ropeCreate | Arma 3, Take On Helicopters |\n| Unit | A unit is either a person or a vehicle. | - |\n| Units | Units are an Array of type unit. | - |\n| Unit(s) | Unit(s) refers to either an array of type unit, a single unit or a Group. This distinction in the command reference refers to very different types, any of which could be used in the same command syntax. | - |\n| Building | When used in the command reference, this object specifically refers to a non AI type model, such as a house, a rock or any other static object. | - |\n| Container | A container can hold items such as weapons, magazines and uniforms.<br>\\| Container \\|  \\|  \\|<br>\\|---\\|---\\|---\\|<br>\\| Sub-type \\| Command usually contains \\| Example \\|<br>\\| Vehicle with inventory \\| `cargo*` \\| ```sqf<br>clearWeaponCargo _truck;<br>``` \\|<br>\\| Backpack \\| `backpack*` \\| ```sqf<br>clearAllItemsFromBackpack player;<br>``` \\|<br>\\| Vest \\| `vest*` \\| ```sqf<br>vestContainer player;<br>``` \\|<br>\\| Uniform \\| `uniform*` \\| ```sqf<br>uniformContainer player;<br>``` \\|<br>\\| Scripted weapon holder \\| `cargo*` \\| ```sqf<br>backpackCargo _ammoBox;<br>``` \\|<br>\\| Ammo box, supply box \\| `cargo*` \\| ```sqf<br>backpackCargo _ammoBox;<br>``` \\| | - |","sections":[{"heading":null,"level":1,"markdown":"**Object** refers to a building block within a scenario. In general when using this term the author refers to the representation of an object (soldier, house, crate, etc.) that can be manipulated when in the 3D environment via the scripting language. As there is a special representation that is used in the mission editor, one might distinguish between a 'game object' (this article) and an 'editor object' (see Editor Object)."},{"heading":"Object Type","level":3,"markdown":"An Object in the scripting language is a generic reference for a soldier, vehicle or building. Such an object can be animated (a house, a tank), can have AI associated with it (a soldier), or, simply be a rock. Various commands in the scripting language can refer as equally to generic (e.g. Object) types, as much as specific sub-types.\n\n```sqf\n_posAGL = getPos player;\n_posATL = getPosATL _house;\n```"},{"heading":"Sub-types","level":3,"markdown":"In this wiki, when describing commands, various 'subtypes' of an object are distinguished. Although in general the commands accept parameters of type 'object', when a subtype is listed, the use of subtypes indicates that the command might not make sense or might not work on all objects.\n\n| Sub-type | Description | Only for |\n|---|---|---|\n| Vehicle | A vehicle is an object such as a tank, car, helicopter or jet. | - |\n| ObjectRTD, HelicopterRTD | A helicopter using the advanced flight model. | Arma 3, Take On Helicopters |\n| Game Logic | If a game logic is created via scripting after mission start, then the logic will be local to the client that created it. A logic is an invisible object with no model. It has a namespace like every object and it has simulation like most objects. <br>> [!NOTE]<br>> In multiplayer, a game logic will always be local to the host computer, if it was placed in the mission editor. This works on both dedicated and player-hosted servers. | - |\n| Person | A human | - |\n| Animal | An animal such as dog and goat. | - |\n| Rope | A rope is flexible and is connected to another object at one or both ends. See ropeCreate | Arma 3, Take On Helicopters |\n| Unit | A unit is either a person or a vehicle. | - |\n| Units | Units are an Array of type unit. | - |\n| Unit(s) | Unit(s) refers to either an array of type unit, a single unit or a Group. This distinction in the command reference refers to very different types, any of which could be used in the same command syntax. | - |\n| Building | When used in the command reference, this object specifically refers to a non AI type model, such as a house, a rock or any other static object. | - |\n| Container | A container can hold items such as weapons, magazines and uniforms.<br>\\| Container \\|  \\|  \\|<br>\\|---\\|---\\|---\\|<br>\\| Sub-type \\| Command usually contains \\| Example \\|<br>\\| Vehicle with inventory \\| `cargo*` \\| ```sqf<br>clearWeaponCargo _truck;<br>``` \\|<br>\\| Backpack \\| `backpack*` \\| ```sqf<br>clearAllItemsFromBackpack player;<br>``` \\|<br>\\| Vest \\| `vest*` \\| ```sqf<br>vestContainer player;<br>``` \\|<br>\\| Uniform \\| `uniform*` \\| ```sqf<br>uniformContainer player;<br>``` \\|<br>\\| Scripted weapon holder \\| `cargo*` \\| ```sqf<br>backpackCargo _ammoBox;<br>``` \\|<br>\\| Ammo box, supply box \\| `cargo*` \\| ```sqf<br>backpackCargo _ammoBox;<br>``` \\| | - |"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Operators","title":"Operators","type":"topic","url":"https://community.bistudio.com/wiki/Operators","revid":363637,"updated":"2024-04-09T03:49:39Z","aliases":[],"markdown":"**Operators** are the base commands each programming language is built on. They provide ability to perform basic mathematical and logical operations.\n\n### Requirements\n\nTo understand this article, you should read the following articles:\n\n- Variables\n\n### Terms\n\n**Operand**\nAn operand is any value given to an operator.\n\n**Expression**\nAn expression is basically any code that returns a value. Read expression for more information.\n\n**Unary Operator**\nAn unary operator is an operator that requires only one operand.\n\nUnary operation:\n`*operator* expression`\n\n**Binary Operator**\nA binary operator is an operator that requires two operands.\n\nBinary operation:\n`expression *operator* expression`\n\n### Operators\n\n#### Assignment Operators\n\nAssignment operators are used to assign values to a variable. OFP's scripting language provides only one assignment operator.\n\n**Assignment:**\n identifier = expression\n\n**Example 1:**\n\n```sqf\na = b\n```\n\nYou might think that this operator compares `a` and `b`, but that is not the case. `=` simply sets the left value to be the right one. Other assignment operators like ,  that can be found in other programming languages do not exist in SQF/SQS.\n\n**Example 2:**\n\n```sqf\na = b * c\n```\n\n#### Arithmetic Operators\n\nRemember arithmetic operations from school? These work just the same way.\nAll operands of arithmetic operations must be Numbers. Arithmetic operations always return a Number.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary arithmetic operators (in order of precedence) | Operator | Name | Example |\n| - | Negation | ```sqf<br>-a<br>``` |  |\n| + | Duplication | ```sqf<br>+a<br>``` |  |\n| ( | Bracket | ```sqf<br>(expression)<br>``` |  |\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary arithmetic operators | Operator | Name | Example |\n| + | Addition | ```sqf<br>a + b<br>``` |  |\n| - | Subtraction | ```sqf<br>a - b<br>``` |  |\n| * | Multiplication | ```sqf<br>a * b<br>``` |  |\n| / | Division | ```sqf<br>a / b<br>``` |  |\n| % | Modulo | ```sqf<br>a % b<br>``` |  |\n| mod | Modulo | ```sqf<br>a mod b<br>``` |  |\n| ^ | Raise to the power of | ```sqf<br>a ^ b<br>``` |  |\n\n> [!NOTE]\n> See also Math Commands.\n\n#### Logical Operators\n\nLogical operators evaluate Boolean values. All operands of logical operations are Booleans.\nA logical operation always returns a Boolean.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary logical operators | Operator | Name | Example |\n| ! | Not | ```sqf<br>!a<br>``` |  |\n| not | Not | ```sqf<br>not a<br>``` |  |\n\nThe `Not`-operator always returns the inverse Boolean value. If a Boolean `a` is `true`, `!a` returns `false` and vice versa.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary logical operators | Operator | Name | Example |\n| && | And | ```sqf<br>a && b<br>``` |  |\n| and | And | ```sqf<br>a and b<br>``` |  |\n| \\|\\| | Or | ```sqf<br>a \\|\\| b<br>``` |  |\n| or | Or | ```sqf<br>a or b<br>``` |  |\n\n- `And` only returns `true` if *both* operands are `true`\n- `Or` returns `true` if *one or both* operands are `true`\n\nThere is no Xor, Nor and Nand operator. Those can be simulated using the basic operators though:\n\n|  |  |  |\n|---|---|---|\n| + Combined logical operators | Name | Combination |\n| Xor | ```sqf<br>((a \\|\\| b) && !(a && b))<br>``` |  |\n| Nor | ```sqf<br>!(a \\|\\| b)<br>``` |  |\n| Nand | ```sqf<br>!(a && b)<br>``` |  |\n\n- `Xor` returns `true` if *exactly one* of both values is `true`\n- `Nor` returns `true` if *none* of both values is `true`\n- `Nand` returns `true` if *not both* values are `true` at the same time\n\n#### Comparison Operators\n\nComparison operators compare two values. Operands of comparisons may be of type Number, Side, String, Object, Group, Structured Text, Config, Display or Control for  and , and Number for .\nComparisons always return a Boolean: `true` if the comparison matches, `false` if not.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Comparison operators | Operator | Name | Example |\n| == | Equal | ```sqf<br>a == b<br>``` |  |\n| != | Not equal | ```sqf<br>a != b<br>``` |  |\n| < | Less than | ```sqf<br>a < b<br>``` |  |\n| > | Greater than | ```sqf<br>a > b<br>``` |  |\n| <= | Less or equal | ```sqf<br>a <= b<br>``` |  |\n| >= | Greater or equal | ```sqf<br>a >= b<br>``` |  |\n\n> [!NOTE]\n>\n\n#### Array Operators\n\nThe scripting language offers own operators to deal with arrays. All operands, of course, have to be of type Array.\nThe return value of an array operation is an Array.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary array operators | Operator | Name | Example |\n| + | Copy | ```sqf<br>+myArray<br>``` |  |\n\nNormally arrays are assigned *by reference*. That means, if you assign array `a` to array `b` and change `a` afterwards, also `b` is changed. Use the copy operator to avoid this otherwise useful feature.\n\n**Example 1:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = _arrayA;\n_arrayA set [0,5];\n\n// _arrayA => [5,2]\n// _arrayB => [5,2]\n```\n\n**Example 2:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = +_arrayA;\n_arrayA set [0,5];\n\n// _arrayA => [5,2]\n// _arrayB => [1,2]\n```\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary array operators | Operator | Name | Example |\n| + | Concatenation | ```sqf<br>myArray1 + myArray2<br>``` |  |\n| - | Removal | ```sqf<br>myArray1 - myArray2<br>``` |  |\n\n- `+` adds the second operand on the end of the first operand\n- `-` removes all elements of the second operand from the first operand\n\n**Example 1:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = [3,2,4];\n\n_arrayC = _arrayA + _arrayB;\n\n// _arrayC => [1,2,3,2,4]\n```\n\n**Example 2:**\n\n```sqf\n_arrayA = [1,2,3,2,4];\n_arrayB = [2,3];\n\n_arrayC = _arrayA - _arrayB;\n\n// _arrayC => [1,4]\n```\n\n#### String Operators\n\nThe scripting language offers one single string operator to concatenate strings. Both operands must be Strings.\nThe return value of a string operation is a String.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary string operators | Operator | Name | Example |\n| + | Concatenation | ```sqf<br>myString1 + myString2<br>``` |  |\n\n- `+` adds the second operand on the end of the first operand\n\n**Example:**\n\n```sqf\n_stringA = \"Hello \";\n_stringB = \"World!\";\n\n_stringC = _stringA + _stringB;\n\n// _stringC => \"Hello World!\"\n```\n\n#### Config Operators\n\n|  |  |  |  |\n|---|---|---|---|\n| + Config operators | Operator | Name | Example |\n| += | Append Array | ```cpp<br>myProperty[] += {element_1, element_2};<br>``` |  |\n\n**Example:**\n\n```cpp\nclass B_Soldier_F;\nclass MySoldier: B_Soldier_F\n{\n    RespawnItems[] += {\"FirstAidKit\"}; //Adds additional FAK\n};\n\n/*\n    Original RespawnItems[] array in config viewer:\n    RespawnItems[] = {\"FirstAidKit\"};\n\n    Modified RespawnItems[] array in config viewer:\n    RespawnItems[] = {\"FirstAidKit\",\"FirstAidKit\"};\n*/\n```\n\n### Order of Precedence\n\nSee Order of Precedence.\n\n### See Also\n\n- SQF Syntax\n- SQS Syntax","sections":[{"heading":null,"level":1,"markdown":"**Operators** are the base commands each programming language is built on. They provide ability to perform basic mathematical and logical operations."},{"heading":"Requirements","level":3,"markdown":"To understand this article, you should read the following articles:\n\n- Variables"},{"heading":"Terms","level":3,"markdown":"**Operand**\nAn operand is any value given to an operator.\n\n**Expression**\nAn expression is basically any code that returns a value. Read expression for more information.\n\n**Unary Operator**\nAn unary operator is an operator that requires only one operand.\n\nUnary operation:\n`*operator* expression`\n\n**Binary Operator**\nA binary operator is an operator that requires two operands.\n\nBinary operation:\n`expression *operator* expression`"},{"heading":"Operators","level":3,"markdown":""},{"heading":"Assignment Operators","level":4,"markdown":"Assignment operators are used to assign values to a variable. OFP's scripting language provides only one assignment operator.\n\n**Assignment:**\n identifier = expression\n\n**Example 1:**\n\n```sqf\na = b\n```\n\nYou might think that this operator compares `a` and `b`, but that is not the case. `=` simply sets the left value to be the right one. Other assignment operators like ,  that can be found in other programming languages do not exist in SQF/SQS.\n\n**Example 2:**\n\n```sqf\na = b * c\n```"},{"heading":"Arithmetic Operators","level":4,"markdown":"Remember arithmetic operations from school? These work just the same way.\nAll operands of arithmetic operations must be Numbers. Arithmetic operations always return a Number.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary arithmetic operators (in order of precedence) | Operator | Name | Example |\n| - | Negation | ```sqf<br>-a<br>``` |  |\n| + | Duplication | ```sqf<br>+a<br>``` |  |\n| ( | Bracket | ```sqf<br>(expression)<br>``` |  |\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary arithmetic operators | Operator | Name | Example |\n| + | Addition | ```sqf<br>a + b<br>``` |  |\n| - | Subtraction | ```sqf<br>a - b<br>``` |  |\n| * | Multiplication | ```sqf<br>a * b<br>``` |  |\n| / | Division | ```sqf<br>a / b<br>``` |  |\n| % | Modulo | ```sqf<br>a % b<br>``` |  |\n| mod | Modulo | ```sqf<br>a mod b<br>``` |  |\n| ^ | Raise to the power of | ```sqf<br>a ^ b<br>``` |  |\n\n> [!NOTE]\n> See also Math Commands."},{"heading":"Logical Operators","level":4,"markdown":"Logical operators evaluate Boolean values. All operands of logical operations are Booleans.\nA logical operation always returns a Boolean.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary logical operators | Operator | Name | Example |\n| ! | Not | ```sqf<br>!a<br>``` |  |\n| not | Not | ```sqf<br>not a<br>``` |  |\n\nThe `Not`-operator always returns the inverse Boolean value. If a Boolean `a` is `true`, `!a` returns `false` and vice versa.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary logical operators | Operator | Name | Example |\n| && | And | ```sqf<br>a && b<br>``` |  |\n| and | And | ```sqf<br>a and b<br>``` |  |\n| \\|\\| | Or | ```sqf<br>a \\|\\| b<br>``` |  |\n| or | Or | ```sqf<br>a or b<br>``` |  |\n\n- `And` only returns `true` if *both* operands are `true`\n- `Or` returns `true` if *one or both* operands are `true`\n\nThere is no Xor, Nor and Nand operator. Those can be simulated using the basic operators though:\n\n|  |  |  |\n|---|---|---|\n| + Combined logical operators | Name | Combination |\n| Xor | ```sqf<br>((a \\|\\| b) && !(a && b))<br>``` |  |\n| Nor | ```sqf<br>!(a \\|\\| b)<br>``` |  |\n| Nand | ```sqf<br>!(a && b)<br>``` |  |\n\n- `Xor` returns `true` if *exactly one* of both values is `true`\n- `Nor` returns `true` if *none* of both values is `true`\n- `Nand` returns `true` if *not both* values are `true` at the same time"},{"heading":"Comparison Operators","level":4,"markdown":"Comparison operators compare two values. Operands of comparisons may be of type Number, Side, String, Object, Group, Structured Text, Config, Display or Control for  and , and Number for .\nComparisons always return a Boolean: `true` if the comparison matches, `false` if not.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Comparison operators | Operator | Name | Example |\n| == | Equal | ```sqf<br>a == b<br>``` |  |\n| != | Not equal | ```sqf<br>a != b<br>``` |  |\n| < | Less than | ```sqf<br>a < b<br>``` |  |\n| > | Greater than | ```sqf<br>a > b<br>``` |  |\n| <= | Less or equal | ```sqf<br>a <= b<br>``` |  |\n| >= | Greater or equal | ```sqf<br>a >= b<br>``` |  |\n\n> [!NOTE]\n>"},{"heading":"Array Operators","level":4,"markdown":"The scripting language offers own operators to deal with arrays. All operands, of course, have to be of type Array.\nThe return value of an array operation is an Array.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Unary array operators | Operator | Name | Example |\n| + | Copy | ```sqf<br>+myArray<br>``` |  |\n\nNormally arrays are assigned *by reference*. That means, if you assign array `a` to array `b` and change `a` afterwards, also `b` is changed. Use the copy operator to avoid this otherwise useful feature.\n\n**Example 1:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = _arrayA;\n_arrayA set [0,5];\n\n// _arrayA => [5,2]\n// _arrayB => [5,2]\n```\n\n**Example 2:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = +_arrayA;\n_arrayA set [0,5];\n\n// _arrayA => [5,2]\n// _arrayB => [1,2]\n```\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary array operators | Operator | Name | Example |\n| + | Concatenation | ```sqf<br>myArray1 + myArray2<br>``` |  |\n| - | Removal | ```sqf<br>myArray1 - myArray2<br>``` |  |\n\n- `+` adds the second operand on the end of the first operand\n- `-` removes all elements of the second operand from the first operand\n\n**Example 1:**\n\n```sqf\n_arrayA = [1,2];\n_arrayB = [3,2,4];\n\n_arrayC = _arrayA + _arrayB;\n\n// _arrayC => [1,2,3,2,4]\n```\n\n**Example 2:**\n\n```sqf\n_arrayA = [1,2,3,2,4];\n_arrayB = [2,3];\n\n_arrayC = _arrayA - _arrayB;\n\n// _arrayC => [1,4]\n```"},{"heading":"String Operators","level":4,"markdown":"The scripting language offers one single string operator to concatenate strings. Both operands must be Strings.\nThe return value of a string operation is a String.\n\n|  |  |  |  |\n|---|---|---|---|\n| + Binary string operators | Operator | Name | Example |\n| + | Concatenation | ```sqf<br>myString1 + myString2<br>``` |  |\n\n- `+` adds the second operand on the end of the first operand\n\n**Example:**\n\n```sqf\n_stringA = \"Hello \";\n_stringB = \"World!\";\n\n_stringC = _stringA + _stringB;\n\n// _stringC => \"Hello World!\"\n```"},{"heading":"Config Operators","level":4,"markdown":"|  |  |  |  |\n|---|---|---|---|\n| + Config operators | Operator | Name | Example |\n| += | Append Array | ```cpp<br>myProperty[] += {element_1, element_2};<br>``` |  |\n\n**Example:**\n\n```cpp\nclass B_Soldier_F;\nclass MySoldier: B_Soldier_F\n{\n    RespawnItems[] += {\"FirstAidKit\"}; //Adds additional FAK\n};\n\n/*\n    Original RespawnItems[] array in config viewer:\n    RespawnItems[] = {\"FirstAidKit\"};\n\n    Modified RespawnItems[] array in config viewer:\n    RespawnItems[] = {\"FirstAidKit\",\"FirstAidKit\"};\n*/\n```"},{"heading":"Order of Precedence","level":3,"markdown":"See Order of Precedence."},{"heading":"See Also","level":3,"markdown":"- SQF Syntax\n- SQS Syntax"}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"Order of Precedence","title":"Order of Precedence","type":"topic","url":"https://community.bistudio.com/wiki/Order_of_Precedence","revid":376136,"updated":"2025-09-02T10:05:38Z","aliases":[],"markdown":"Order of operations, also called operator precedence, is a set of rules specifying which procedures should be performed first in a mathematical expression.\n\n#### Precedence Overview\n\n> [!NOTE]\n> - Highest precedence means highest priority\n> - Associativity is (then) done from left to right, for example `3 + 5 + 8` will be processed as `((3 + 5) + 8)`\n\n| Precedence | Type of Operator | Examples |\n|---|---|---|\n| 11 | Nular operators (commands with no arguments):<br>- `commandName` | - Variables<br>- Values<br>- `()` / `[]` / `{}` / `\"\"` / `''` -enclosed expressions |\n| 10 | Unary operators (commands with 1 argument):<br>- `commandName` a | * +a<br>- -a<br>- +array<br>- ! b<br>- not b |\n| 9 | Hash-select operator | - array # index |\n| 8 | Power operator | - a ^ b |\n| 7 | - Number multiplication, division and remainder<br>- atan2<br>- Config access (/) | * a * b<br>- a / b<br>- a % b<br>- a mod b<br>- a / b<br>- a atan2 b |\n| 6 | - Number addition and subtraction<br>- Array addition and subtraction<br>- String addition<br>- min and max commands | * a + b<br>- a - b<br>- arr1 + arr2<br>- arr1 - arr2<br>- str1 + str2<br>- a min b<br>- a max b |\n| 5 | - else (if-then-else structure) | N/A |\n| 4 | Binary operators (commands with 2 arguments):<br>- a `commandName` b | - setDir<br>- switch colon (:) |\n| 3 | - == and != comparisons<br>- Number comparisons<br>- Config access (>>) | - a == b<br>- a != b<br>- a > b<br>- a < b<br>- a >= b<br>- a <= b<br>- config >> name |\n| 2 | Logical and operator | - &&<br>- and |\n| 1 | Logical or operator | - \\|\\|<br>- or |\n\n#### Examples\n\n| Input | Process | Comment |\n|---|---|---|\n| ```sqf<br>1 + 2 * 3<br>``` | ```sqf<br>1 + (2 * 3)<br>``` | result equals 7, and not 9 (see also [PEMDAS](https://en.wikipedia.org/wiki/Order_of_operations)) |\n| ```sqf<br>sleep 10 + random 20<br>``` | ```sqf<br>(sleep 10) + random 20<br>``` | `sleep 10` will return Nothing, then `+ random 20` will be calculated but not used.<br>`sleep (10 + random 20)` should be used instead |","sections":[{"heading":null,"level":1,"markdown":"Order of operations, also called operator precedence, is a set of rules specifying which procedures should be performed first in a mathematical expression."},{"heading":"Precedence Overview","level":4,"markdown":"> [!NOTE]\n> - Highest precedence means highest priority\n> - Associativity is (then) done from left to right, for example `3 + 5 + 8` will be processed as `((3 + 5) + 8)`\n\n| Precedence | Type of Operator | Examples |\n|---|---|---|\n| 11 | Nular operators (commands with no arguments):<br>- `commandName` | - Variables<br>- Values<br>- `()` / `[]` / `{}` / `\"\"` / `''` -enclosed expressions |\n| 10 | Unary operators (commands with 1 argument):<br>- `commandName` a | * +a<br>- -a<br>- +array<br>- ! b<br>- not b |\n| 9 | Hash-select operator | - array # index |\n| 8 | Power operator | - a ^ b |\n| 7 | - Number multiplication, division and remainder<br>- atan2<br>- Config access (/) | * a * b<br>- a / b<br>- a % b<br>- a mod b<br>- a / b<br>- a atan2 b |\n| 6 | - Number addition and subtraction<br>- Array addition and subtraction<br>- String addition<br>- min and max commands | * a + b<br>- a - b<br>- arr1 + arr2<br>- arr1 - arr2<br>- str1 + str2<br>- a min b<br>- a max b |\n| 5 | - else (if-then-else structure) | N/A |\n| 4 | Binary operators (commands with 2 arguments):<br>- a `commandName` b | - setDir<br>- switch colon (:) |\n| 3 | - == and != comparisons<br>- Number comparisons<br>- Config access (>>) | - a == b<br>- a != b<br>- a > b<br>- a < b<br>- a >= b<br>- a <= b<br>- config >> name |\n| 2 | Logical and operator | - &&<br>- and |\n| 1 | Logical or operator | - \\|\\|<br>- or |"},{"heading":"Examples","level":4,"markdown":"| Input | Process | Comment |\n|---|---|---|\n| ```sqf<br>1 + 2 * 3<br>``` | ```sqf<br>1 + (2 * 3)<br>``` | result equals 7, and not 9 (see also [PEMDAS](https://en.wikipedia.org/wiki/Order_of_operations)) |\n| ```sqf<br>sleep 10 + random 20<br>``` | ```sqf<br>(sleep 10) + random 20<br>``` | `sleep 10` will return Nothing, then `+ random 20` will be calculated but not used.<br>`sleep (10 + random 20)` should be used instead |"}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"Position","title":"Position","type":"topic","url":"https://community.bistudio.com/wiki/Position","revid":364535,"updated":"2024-05-16T20:46:45Z","aliases":["Position2D","Position3D","PositionAGL","PositionAGLS","PositionASL","PositionASLW","PositionATL","PositionConfig","PositionRelative","PositionWorld"],"markdown":"Positions in Arma games are always represented as arrays. There are two types of positions:\n- 2D position: `[X, Y]`\n- 3D position: `[X, Y, Z]`\n\nOn the map and on the terrain, the X-axis runs from west to east and the Y-axis runs from south to north. The origin `[0, 0]` is (usually) located in the bottom left corner.\n\nWhile the Z-coordinate is always the height/altitude, the point relative to which that height is measured depends on the specific position format (see #Types below).\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 v1.94: X, Y and Z are limited to values between -50km and +500km. Using any **setPos*** command with values greater than that will [clamp](https://en.wikipedia.org/wiki/Clamping_(graphics)) the value to within these boundaries, not throwing any errors. e.g:\n>\n> ```sqf\n> player setPosASL [-50001, 500001, 500001]; // player will be set to [-50000, 500000, 500000]\n> ```\n\n### Commands\n\nSee:\n- Command Group: Positions\n- Command Group: Render Time Scope\n\n### Types\n\nThere are a number of formats available in Real Virtuality:\n\n|  |  |\n|---|---|\n| **ASL:** | Presumably \"**A**bove **S**ea **L**evel\" |\n| **ATL:** | Presumably \"**A**bove **T**errain **L**evel\" |\n| **ASLW:** | Presumably \"**A**bove **S**ea **L**evel including **W**aves\" |\n| **AGL:** | Presumably \"**A**bove **G**eneric/**G**round **L**evel\" |\n| **AGLS:** | Presumably \"**A**bove **G**eneric/**G**round **L**evel including **S**urfaces\" |\n| **World:** | Raw world coordinate system |\n| **Relative:** | Position relative to an object within its model space |\n| **Config:** | Position used in configs |\n| **Object:** | When object is used for position, PositionWorld of the object is used |\n| **Visual:** | Used for rendering objects on the screen. Useful for per-frame applications, such as drawIcon3D - see Command Group: Render Time Scope and Simulation vs Render Time Scope. |\n\n> [!IMPORTANT]\n> Note that the only **absolute position format** in Arma for 3D calculations is the ASL format. Always pay attention to this fact when performing 3D calculations. For example, when a unit is climbing a mountain, the Z in ATL format is **always 0**. The following example demonstrates this behavior:\n>\n> Let's say it is desired to see if there is an intersection between two horizontal positions:\n>\n> ```sqf\n> private _pos1 = getPosATL _unit;\n> private _pos2 = _pos1 vectorAdd [0,200,0]; // make a horizontal line by shifting the y, so z remains the same\n> private _intersects = lineIntersects [ATLToASL _pos1, ATLToASL _pos2]; // lineIntersects needs ASL, so we just convert _pos1 and _pos2 to ASL...\n> ```\n>\n> However, this is incorrect. ATL is a relative format, and while the ATL height between the coordinates is the same, the ASL height might not be (think of the mountain example again).\n>\n> This is the correct way to write the above code:\n>\n> ```sqf\n> private _pos1 = getPosASL _unit;\n> private _pos2 = _pos1 vectorAdd [0,200,0]; // make a horizontal line by shifting the y\n> private _intersects = lineIntersects [_pos1, _pos2];\n> ```\n\n#### Position2D\n\nThis array only has two elements and is usually used with 2D information, for example standard markers or UI commands. If used with e.g distance, Z is assumed to be 0.\n\n#### PositionASL\n\nZ is measured from the sea level which is constant across the map.\n\n**See also:**\ngetPosASL, setPosASL, getPosASLVisual, visiblePositionASL, ASLToATL, ATLToASL, AGLToASL, ASLToAGL, eyePos, aimPos, getTerrainHeightASL, lineIntersects, lineIntersectsWith, lineIntersectsObjs, lineIntersectsSurfaces, terrainIntersectASL, playSound3D, setDefaultCamera\n\n#### PositionASLW\n\nZ is measured from the surface of water at that position. Both waves and pond objects affect the result.\n\n**See also:**\ngetPosASLW, setPosASLW\n\n#### PositionATL\n\nZ is measured from the terrain level which varies across the map.\n\n**See also:**\ngetPosATL, setPosATL, getPosATLVisual, ASLToATL, ATLToASL\n\n#### PositionAGL\n\nZ is the same as in PositionASLW when over sea and is the same as in PositionATL when over land. Most commands either take or return PositionAGL.\n\n**See also:**\nmodelToWorld, worldToModel, modelToWorldVisual, worldToModelVisual, positionCameraToWorld, intersect, terrainIntersect, isOnRoad, drawIcon3D, drawLine3D, distance, moveTo, doMove, move, setDestination, buildingPos, screenToWorld, worldToScreen, AGLToASL, ASLToAGL, unitAimPosition, unitAimPositionVisual\n\n#### PositionAGLS\n\nOver land, Z is measured as height over terrain level minus the height of surface over terrain level underneath. If such surface exists and is counted in, the resulting Z becomes 0.\n\nOver sea it gets even more complicated as instead of PositionATL, PositionASLW is used minus the offset for the surface height, presumably over waves too, as Z seems static. As there is currently no way to obtain Hsurface, it becomes impossible to convert given PositionAGLS into other formats, unlike with other position formats.\n\n**See also:**\nposition, visiblePosition, getPos, getPosVisual\n\n##### setPosAGLS\n\nThe function below will place passed object onto walkable surface, if there is one, otherwise on the ground. If only X and Y of the position are supplied, the object will be placed on surface, if Z is supplied, it will be treated as offset from the surface level.\n\n```sqf\nKK_fnc_setPosAGLS = {\n    params [\"_obj\", \"_pos\", \"_offset\"];\n    _offset = _pos select 2;\n    if (isNil \"_offset\") then {_offset = 0};\n    _pos set [2, worldSize];\n    _obj setPosASL _pos;\n    _pos set [2, vectorMagnitude (_pos vectorDiff getPosVisual _obj) + _offset];\n    _obj setPosASL _pos;\n};\n```\n\n```sqf\n// This will place the player exactly on top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,0]] call KK_fnc_setPosAGLS;\n\n// This will place the player 2m above top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,2]] call KK_fnc_setPosAGLS;\n\n// This will place the player 2m below top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,-2]] call KK_fnc_setPosAGLS;\n```\n\nAlternatively, setVehiclePosition can be used. It will put the object onto the nearest surface.\n\n```sqf\n// This will place the player inside Cargo HQ on Stratis:\nplayer setVehiclePosition [[2437.18,5693.47,0], [], 0, \"CAN_COLLIDE\"];\n\n// This will place the player on top deck of Cargo HQ on Stratis:\nplayer setVehiclePosition [[2437.18,5693.47,100], [], 0, \"CAN_COLLIDE\"];\n```\n\n#### PositionWorld\n\nSimilar to PositionASL, however Z is measured from the sea level to the the model centre `[0, 0, 0]` of the object, rather than transformed boundingCenter or land contact vertices.\n\n```sqf\n_identical = getPosWorld _obj isEqualTo AGLToASL (_obj modelToWorld [0,0,0]); // should be true\n```\n\n**See also:**\ngetPosWorld, setPosWorld, mapCenterOnCamera\n\n#### PositionRelative\n\nRelative position is normally an `[X, Y, Z]` offset from the model centre.\n\n**See also:**\ngetRelPos, positionCameraToWorld, selectionPosition, attachTo, modelToWorld, worldToModel, modelToWorldVisual, worldToModelVisual, camPrepareRelPos, camSetRelPos\n\n#### PositionConfig\n\nThe format used in configs, such as *mission.sqm*, is `[X, Z, Y]`, where Z and Y are swapped around. One other command that uses this format is positionCameraToWorld. Z in configs is measured from the sea level.","sections":[{"heading":null,"level":1,"markdown":"Positions in Arma games are always represented as arrays. There are two types of positions:\n- 2D position: `[X, Y]`\n- 3D position: `[X, Y, Z]`\n\nOn the map and on the terrain, the X-axis runs from west to east and the Y-axis runs from south to north. The origin `[0, 0]` is (usually) located in the bottom left corner.\n\nWhile the Z-coordinate is always the height/altitude, the point relative to which that height is measured depends on the specific position format (see #Types below).\n\n> [!NOTE]\n> **Arma 3:** Since Arma 3 v1.94: X, Y and Z are limited to values between -50km and +500km. Using any **setPos*** command with values greater than that will [clamp](https://en.wikipedia.org/wiki/Clamping_(graphics)) the value to within these boundaries, not throwing any errors. e.g:\n>\n> ```sqf\n> player setPosASL [-50001, 500001, 500001]; // player will be set to [-50000, 500000, 500000]\n> ```"},{"heading":"Commands","level":3,"markdown":"See:\n- Command Group: Positions\n- Command Group: Render Time Scope"},{"heading":"Types","level":3,"markdown":"There are a number of formats available in Real Virtuality:\n\n|  |  |\n|---|---|\n| **ASL:** | Presumably \"**A**bove **S**ea **L**evel\" |\n| **ATL:** | Presumably \"**A**bove **T**errain **L**evel\" |\n| **ASLW:** | Presumably \"**A**bove **S**ea **L**evel including **W**aves\" |\n| **AGL:** | Presumably \"**A**bove **G**eneric/**G**round **L**evel\" |\n| **AGLS:** | Presumably \"**A**bove **G**eneric/**G**round **L**evel including **S**urfaces\" |\n| **World:** | Raw world coordinate system |\n| **Relative:** | Position relative to an object within its model space |\n| **Config:** | Position used in configs |\n| **Object:** | When object is used for position, PositionWorld of the object is used |\n| **Visual:** | Used for rendering objects on the screen. Useful for per-frame applications, such as drawIcon3D - see Command Group: Render Time Scope and Simulation vs Render Time Scope. |\n\n> [!IMPORTANT]\n> Note that the only **absolute position format** in Arma for 3D calculations is the ASL format. Always pay attention to this fact when performing 3D calculations. For example, when a unit is climbing a mountain, the Z in ATL format is **always 0**. The following example demonstrates this behavior:\n>\n> Let's say it is desired to see if there is an intersection between two horizontal positions:\n>\n> ```sqf\n> private _pos1 = getPosATL _unit;\n> private _pos2 = _pos1 vectorAdd [0,200,0]; // make a horizontal line by shifting the y, so z remains the same\n> private _intersects = lineIntersects [ATLToASL _pos1, ATLToASL _pos2]; // lineIntersects needs ASL, so we just convert _pos1 and _pos2 to ASL...\n> ```\n>\n> However, this is incorrect. ATL is a relative format, and while the ATL height between the coordinates is the same, the ASL height might not be (think of the mountain example again).\n>\n> This is the correct way to write the above code:\n>\n> ```sqf\n> private _pos1 = getPosASL _unit;\n> private _pos2 = _pos1 vectorAdd [0,200,0]; // make a horizontal line by shifting the y\n> private _intersects = lineIntersects [_pos1, _pos2];\n> ```"},{"heading":"Position2D","level":4,"markdown":"This array only has two elements and is usually used with 2D information, for example standard markers or UI commands. If used with e.g distance, Z is assumed to be 0."},{"heading":"PositionASL","level":4,"markdown":"Z is measured from the sea level which is constant across the map.\n\n**See also:**\ngetPosASL, setPosASL, getPosASLVisual, visiblePositionASL, ASLToATL, ATLToASL, AGLToASL, ASLToAGL, eyePos, aimPos, getTerrainHeightASL, lineIntersects, lineIntersectsWith, lineIntersectsObjs, lineIntersectsSurfaces, terrainIntersectASL, playSound3D, setDefaultCamera"},{"heading":"PositionASLW","level":4,"markdown":"Z is measured from the surface of water at that position. Both waves and pond objects affect the result.\n\n**See also:**\ngetPosASLW, setPosASLW"},{"heading":"PositionATL","level":4,"markdown":"Z is measured from the terrain level which varies across the map.\n\n**See also:**\ngetPosATL, setPosATL, getPosATLVisual, ASLToATL, ATLToASL"},{"heading":"PositionAGL","level":4,"markdown":"Z is the same as in PositionASLW when over sea and is the same as in PositionATL when over land. Most commands either take or return PositionAGL.\n\n**See also:**\nmodelToWorld, worldToModel, modelToWorldVisual, worldToModelVisual, positionCameraToWorld, intersect, terrainIntersect, isOnRoad, drawIcon3D, drawLine3D, distance, moveTo, doMove, move, setDestination, buildingPos, screenToWorld, worldToScreen, AGLToASL, ASLToAGL, unitAimPosition, unitAimPositionVisual"},{"heading":"PositionAGLS","level":4,"markdown":"Over land, Z is measured as height over terrain level minus the height of surface over terrain level underneath. If such surface exists and is counted in, the resulting Z becomes 0.\n\nOver sea it gets even more complicated as instead of PositionATL, PositionASLW is used minus the offset for the surface height, presumably over waves too, as Z seems static. As there is currently no way to obtain Hsurface, it becomes impossible to convert given PositionAGLS into other formats, unlike with other position formats.\n\n**See also:**\nposition, visiblePosition, getPos, getPosVisual"},{"heading":"setPosAGLS","level":5,"markdown":"The function below will place passed object onto walkable surface, if there is one, otherwise on the ground. If only X and Y of the position are supplied, the object will be placed on surface, if Z is supplied, it will be treated as offset from the surface level.\n\n```sqf\nKK_fnc_setPosAGLS = {\n    params [\"_obj\", \"_pos\", \"_offset\"];\n    _offset = _pos select 2;\n    if (isNil \"_offset\") then {_offset = 0};\n    _pos set [2, worldSize];\n    _obj setPosASL _pos;\n    _pos set [2, vectorMagnitude (_pos vectorDiff getPosVisual _obj) + _offset];\n    _obj setPosASL _pos;\n};\n```\n\n```sqf\n// This will place the player exactly on top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,0]] call KK_fnc_setPosAGLS;\n\n// This will place the player 2m above top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,2]] call KK_fnc_setPosAGLS;\n\n// This will place the player 2m below top deck of Cargo HQ on Stratis:\n[player, [2437.18,5693.47,-2]] call KK_fnc_setPosAGLS;\n```\n\nAlternatively, setVehiclePosition can be used. It will put the object onto the nearest surface.\n\n```sqf\n// This will place the player inside Cargo HQ on Stratis:\nplayer setVehiclePosition [[2437.18,5693.47,0], [], 0, \"CAN_COLLIDE\"];\n\n// This will place the player on top deck of Cargo HQ on Stratis:\nplayer setVehiclePosition [[2437.18,5693.47,100], [], 0, \"CAN_COLLIDE\"];\n```"},{"heading":"PositionWorld","level":4,"markdown":"Similar to PositionASL, however Z is measured from the sea level to the the model centre `[0, 0, 0]` of the object, rather than transformed boundingCenter or land contact vertices.\n\n```sqf\n_identical = getPosWorld _obj isEqualTo AGLToASL (_obj modelToWorld [0,0,0]); // should be true\n```\n\n**See also:**\ngetPosWorld, setPosWorld, mapCenterOnCamera"},{"heading":"PositionRelative","level":4,"markdown":"Relative position is normally an `[X, Y, Z]` offset from the model centre.\n\n**See also:**\ngetRelPos, positionCameraToWorld, selectionPosition, attachTo, modelToWorld, worldToModel, modelToWorldVisual, worldToModelVisual, camPrepareRelPos, camSetRelPos"},{"heading":"PositionConfig","level":4,"markdown":"The format used in configs, such as *mission.sqm*, is `[X, Z, Y]`, where Z and Y are swapped around. One other command that uses this format is positionCameraToWorld. Z in configs is measured from the sea level."}],"categories":["Arrays"],"groups":["Scripting"]},{"name":"PreProcessor Commands","title":"PreProcessor Commands","type":"topic","url":"https://community.bistudio.com/wiki/PreProcessor_Commands","revid":378955,"updated":"2026-09-02T17:00:00Z","aliases":["Config Parser","PreProcessor Errors"],"markdown":"The PreProcessor and the Config Parser allow to use macros in configs.\nThe purpose of macros is to re-use the same definition in scripts and configs multiple times.\nIt also gives a centralised place to correct errors in this definition.\nKnow that edge cases may arise - see the collection of test-cases linked at the end of this page.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3, preprocessor commands are **case-sensitive!**\n\n### Parsing\n\nSee #Config Parser below:\n- **Config.cpp** - parsed when PBO is binarised.\n  - localize cannot be used in macros, as it would hardcode string of current language instead of creating reference.\n- **Description.ext** - parsed when mission is loaded or previewed in missions list.\n- **SQF script** - parsed when preprocessFile, preprocessFileLineNumbers, compileScript or execVM is used.\n\n### Macros\n\n#### Strings\n\nIn both Configs and SQF scripts, there are two ways to define strings: either using single quotes (`'text'`) or double quotes (`\"text\"`).\nWhile they are both identical, they are **treated differently** by the preprocessor.\nThe **single quote** string contents are **parsed** by the preprocessor, while the **double quote** ones are **ignored**.\n\n```sqf\n#define ARG world\n\nsystemChat 'hello ARG'; // prints: hello world (i.e. ARG was replaced by the preprocessor with world)\nsystemChat \"hello ARG\"; // prints: hello ARG\n```\n\n> [!WARNING]\n> While it is possible in config to define a string without quotes (the preprocessor will act as if the value were wrapped with single quotes), this practice is heavily discouraged.\n>\n> ```cpp\n> title = \"$STR_TranslationKey\";    // good\n> title = $STR_TranslationKey;    // tolerated but incorrect\n> ```\n\n#### Comments\n\nA comment is a line within code that is not actually processed by the game engine. They are used to make code more readable or to add notes for future reference.\nThe preprocessor removes all comments from the file before it is processed. Therefore, comments are never actually \"seen\" by the game engine.\n\n> [!WARNING]\n> Sometimes a problematic string can fail to purge these comment outs during preprocessing!\n>\n> ```sqf\n> private _a = '\"';\n> // this is just a comment, but failed to remove upon the preprocess so will return an error. Caused by that string\n> ```\n\n```cpp\n// this is a single-line comment\n\n/*\n    this is a\n    multi-line\n    comment\n*/\n\nmyValue = something; // only this part of the line is commented out\n\nmyArray = { \"apple\"/*, \"banana\"*/, \"pear\" }; // a portion in the middle of this line is commented out\n```\n\n#### #define\n\nUsing the `1. define` instruction, it is possible to define a keyword and assign a definition to it.\nThe keyword may contain any letter, digit or underscore in arbitrary order, as long as it does not start with a digit (RegEx: `[a-zA-Z_][0-9a-zA-Z_]*`).\nAs an example:\n\n```cpp\n#define true 1\n```\n\nThe above means that whenever *true* is used in a config, the parser will replace this with the value *1*.\n\nThe define-statement does swallow all spaces in between the macro-keyword and any non-space-character in the body (Note that tabs are not spaces! They don't get removed)\n\n```cpp\n#define MACRO test\nMACRO // preprocesses to test (without any spaces)\n\n#define MACRO    test // There's a tab between MACRO and test\nMACRO // preprocesses to \"    test\" (without quotes - they are only used to show that the tab character didn't get removed)\n```\n\nThe space between the macro-keyword and the body is also fully optional (though very useful to tell the preprocessor where the macro name ends and where the body begins):\n\n```cpp\n#define MACRO#test\nMACRO // preprocesses to \"test\"\n```\n\n##### Arguments\n\nArguments can be added to more complex macros, by including them between brackets after the keyword. For the name of the arguments the same rule as for the macro-keyword (see above) apply.\n\n```cpp\n#define CAR(NAME) displayName = NAME;\n```\n\nIf *CAR(\"Mini\")* is used, it will be replaced with *displayName = \"Mini\";*. Multiple arguments can also be used:\n\n```cpp\n#define BLASTOFF(UNIT,RATE) UNIT setVelocity [0,0,RATE];\n```\n\nMacro arguments may be composed of any characters, as long as they do not contain a comma (because commas are used as argument-delimiters).\nIf quotes are being used, they have to be balanced.\nThe same applies to single-quotes; this is because String detection is working in macro arguments - therefore commas can even get passed in as a macro argument as long as they are part of a String (This only works with Strings wrapped in double-quotes though).\nNote however that although the macro gets resolved properly, the comma gets removed from the String (probably a bug).\n\n```cpp\n#define MACRO(arg) arg\nMACRO(\"Some, content\") // preprocesses to \"Some content\" (note the missing comma)\n```\n\nQuote escaping is also not supported in this context (neither with double- nor with single-quotes)\n\n```cpp\n#define MACRO(arg) arg\nMACRO(\"Some \"\"content\"\"\") // preprocesses to \"Some \"\"content\"\"\"\n```\n\nPassing arrays with more than one element `[el1,el2,...]` as arguments into macros as well as any argument containing commas (e.g `\"some, sentence\"`) will need a small workaround:\n\n```cpp\n#define HINTARG(ARG) hint (\"Passed argument: \" + str ARG)\n```\n\nIncorrect usage:\n\n```cpp\nHINTARG([1,2,3,4,5,6,7,8,9,0]); // ERROR, won't even compile\n```\n\nCorrect usage:\n\n```cpp\n#define array1 [1,2,3,4,5,6,7,8,9,0]\nHINTARG(array1); // SUCCESS\n```\n\nThe argument replacement is performed before the expansion of the macro body. That means one doesn't have to worry about name-conflicts between argument-names of the current macro and already defined macros:\n\n```cpp\n#define ONE foo\n#define TWO(ONE) ONE\nTWO(bar) // will preprocess to bar\n```\n\n##### Replacing parts of words\n\nBy default, only whole words can be replaced by arguments. If only a part of the word should be replaced, use the `1.` instruction.\nThis is necessary when either the start or the end of the argument connects to another character that is not a `****` (semi-colon) or  (space).\n\n```cpp\nclass NAME##_Button_Slider: RscText \\\n{ \\\n    model = \\OFP2\\Structures\\Various\\##FOLDER##\\##FOLDER; \\\n```\n\nIt is also possible to use the single *#* to convert an argument to a string.\n\n```cpp\nstatement = (this animate [#SEL, 0]); \\\n```\n\n##### Multi-line\n\nFor longer definitions, one can stretch the macro across multiple lines. To create a multi-line definition, each line except the last one should end with a *\\* character:\n\n```cpp\n#define DRAWBUTTON(NAME)\\\n    __EXEC(idcNav = idcNav + 4) \\\n    // ...\n```\n\n> [!NOTE]\n> The backslash must be the last character in a line when defining a multi-line macro. Any character (including spaces) after the backslash will cause issues.\n\n##### Variadic Arguments (Arma 3 v2.24)\n\nReference https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html\n\nVariadic arguments allows to provide a variable number of arguments to a macro, instead of a fixed number.\n\nAnd there are several \"functions\" to work with these variable-length argument lists.\n\nA basic variadic macro looks like this\n\n```cpp\n#define MACRO(...) __VA_ARGS__\n```\n\nThere are a few special keywords and \"functions\" that are only valid when used inside a variadic macro\n- `__VA_ARGS__`\n- `__VA_OPT__(X)`\n- `__VA_OPT_INV__(X)`\n- `__VA_APPLY__(FUNC(,SEP))`\n- `__VA_SELECT__(index)`\n\n###### __VA_ARGS__\n\nis a special keyword that will be replaced by all the macro arguments, separated by \",\". For example:\n\n```cpp\n#define MACRO(...) __VA_ARGS__\n\nMACRO() // \"\", Zero is also a valid number of arguments\nMACRO(a,b,c) // \"a,b,c\", the arguments are \"a\", \"b\" and \"c\"\nMACRO({str [1,2,3]}) // \"{str [1,2,3]}\", the arguments are \"{str [1\", \"2\" and \"3]}\"\n```\n\nThis simple variant can replace helper macros like CBA mod's ARR_1, ARR_2, ARR_3, with just one ARR(...) macro.\n\nIt can also be used to wrap code blocks, which was difficult to do without it because they can contain commas and its not easy to tell the number of commas, like in the example above.\n\n###### __VA_OPT__(x) and __VA_OPT_INV__(x)\n\nare simple functions to handle the special case of there being zero variadic arguments.\n`__VA_OPT__(x)` is only active if arguments are present. And the INV variant is only active if no arguments are present\nFor example:\n\n```cpp\n#define HAS_ARGS __VA_OPT__(Yes I have Arguments!)__VA_OPT_INV__(Nothing!)\n\nHAS_ARGS() // \"Nothing!\"\nHAS_ARGS(a) // \"Yes I have Arguments!\"\nHAS_ARGS(a,b,c) // \"Yes I have Arguments!\", no matter how many arguments, if there is at least one, the optional data is inserted\n```\n\nThis is useful when the arguments are forwarded to something like:\n\n```cpp\n#define LOG(message, ...) diag_log __VA_OPT__([) message __VA_OPT__(,) __VA_ARGS__ __VA_OPT__(])\n\nLOG(\"My Message\") // 'diag_log  \"My Message\"   '\nLOG(\"My Message\",1,2,3) // 'diag_log [ \"My Message\" , 1,2,3 ]  '\n```\n\n###### __VA_APPLY__(FUNC, SEPARATOR)\n\nis similar to apply in that it applies a function(macro) on every argument. The second \"SEPARATOR\" argument is optional, it can be used to replace the usual \",\" separator with something different.\n\nThe macro passed to apply must have 0, 1 or 2 arguments.\n\nIf 0 arguments, every value will be replaced by the macro contents, for example:\n\n```cpp\n#define FUNC A\n#define TRANSFORM(...) __VA_APPLY__(FUNC)\nTRANSFORM(1,2,3) // 'A,A,A'\n```\n\nIf 1 argument, it will be the value of the argument, for example:\n\n```cpp\n#define QUOTE(x) #x\n#define TRANSFORM(...) __VA_APPLY__(QUOTE)\nTRANSFORM(1,2,3) // '\"1\",\"2\",\"3\"'\n```\n\nIf 2, the second argument MUST be named `__VA_INDEX__`, it will be filled with the index of the argument, for example:\n\n```cpp\n#define FUNC(x, __VA_INDEX__) __VA_INDEX__: #x\n#define TRANSFORM(...) __VA_APPLY__(FUNC)\nTRANSFORM(1,2,3) // '0: \"1\",1: \"2\",2: \"3\"'\n```\n\nBy default, just like `__VA_ARGS__` when the values are written to the output, they will be separated by \",\".\n\nThis can be changed by providing a separator argument, for example:\nFor example:\n\n```cpp\n#define VERBATIM(x) x\n#define SEPARATOR_NONE\n#define TRANSFORM_CONCAT(...) __VA_APPLY__(QUOTE, SEPARATOR_NONE)\nTRANSFORM_CONCAT(1,2,3) // '123'\n\n#define GET_VARIABLE(x) private _##x = player getVariable #x\n#define SEPARATOR_SEMI ;\n#define GET_VARIABLES(...) __VA_APPLY__(GET_VARIABLE, SEPARATOR_SEMI)\n\nGET_VARIABLES() // ''\nGET_VARIABLES(MyFnc) // 'private _MyFnc = player getVariable \"MyFnc\"'\nGET_VARIABLES(MyFnc,MyOtherFnc) // 'private _MyFnc = player getVariable \"MyFnc\";private _MyOtherFnc = player getVariable \"MyOtherFnc\"'\n```\n\nThe results of `__VA_APPLY__` can also be passed to another variadic macro, for example:\n\n```cpp\n#define QUOTE(x) #x\n#define WRITE_LOG(...) diag_log [__VA_ARGS__]\n#define MAKE_ARRAY(...) [__VA_ARGS__]\n\n#define DO_THINGS(...) WRITE_LOG(__VA_APPLY__(QUOTE)); _array = MAKE_ARRAY(__VA_ARGS__);\n\nDO_THINGS(a,b,c) // diag_log [\"a\",\"b\",\"c\"]; _array = [a,b,c];\n```\n\n###### __VA_SELECT__(index)\n\nwill select the specified element out of the `__VA_ARGS__` list. index must be a number.\nFor example:\n\n```cpp\n#define SELECT_ARG(index, ...) __VA_SELECT__(index)\n#define FORMAT_ARG(index) SELECT_ARG(index, \"A=%2\", \"B=%3\", \"C=%4\", \"D=%5\", \"E=%6\", \"F=%7\")\n#define FORMAT_GET_ARGSTR(arg, __VA_INDEX__) FORMAT_ARG(__VA_INDEX__)\n#define FORMAT(MESSAGE, ...) format [[__VA_OPT_INV__('%1') __VA_OPT__('%1:',) __VA_APPLY__(FORMAT_GET_ARGSTR)] joinString ' ', MESSAGE __VA_OPT__(,) __VA_ARGS__]\n\nFORMAT(\"Message\") // `format [['%1'  ] joinString ' ', \"Message\"  ]`\nFORMAT(\"Message\", value1, value2) // `format [[ '%1:',  \"A=%2\", \"B=%3\"] joinString ' ', \"Message\" ,  value1, value2]` which ends up as `format [\"%1: A=%2 B=%3\", \"Message\", value1, value2]`\n```\n\n#### #undef\n\nUndefine (delete) a macro previously set by the use of #define.\n\n```cpp\n#undef NAME\n```\n\n#### #if\n\n**Description:** Checks condition and processes content if condition returns 1. Skips content if it returns 0\n\n```cpp\n#if __GAME_VER_MAJ__ != 2\n// Do something...\n#endif\n```\n\n##### Comparison Operators\n\nThe following operations are supported:\n- <\n- >\n- <=\n- >=\n- ==\n- !=\n**Example:**\n\n```cpp\n#if __GAME_VER_MAJ__ != 2\n// Do something...\n#endif\n```\n\n#### #ifdef\n\nA simple if-then construction to check whether a certain set of definitions has already been made:\n\n```cpp\n#ifdef NAME\n    // config that will be used if NAME is defined\n#endif\n```\n\nIFDEFs *cannot* be nested. The preprocessor will generate errors for all inner definitions if the outer definition doesn't exist.\n\n#### #ifndef\n\nSame as #ifdef, but checks for absence of definition instead.\n\n```cpp\n#ifndef NAME\n    // config that will be used if NAME is -not- defined\n#endif\n```\n\n#### #else\n\nProvides alternative code to `1. if`, `1. ifdef`, `1. ifndef` checks.\n\n```cpp\n#ifndef NAME\n    // config that will be used if NAME is -not- defined\n#else\n    // config that will be used if NAME -is- defined\n#endif\n```\n\n#### #endif\n\nThis ends a conditional block as shown in the descriptions of #ifdef and #ifndef above.\n\n#### #include\n\nCopies the code from a target file and pastes it where #include directive is.\n\n```cpp\n#include \"file.hpp\"\n#include <file.txt> // Brackets are equivalent to quotation marks and may be used in their place.\n```\n\nSource directory is:\n- For any file without starting the include path with \\ - the file's current directory\n- When starting with \\ - the internal filesystem root (see Addon Prefix) or the Game's working directory (only with -filePatching enabled)\n\nA path beginning can be defined as follow:\n- drive (only with -filePatching enabled): \n\n```cpp\n#include \"D:\\file.txt\"\n```\n\n- PBO with PBOPREFIX: \n\n```cpp\n #include \"\\myMod\\myAddon\\file.txt\"\n```\n\n- PBO (keep in mind that in this case, if the PBO's file name will be changed, all '#include' referencing it will need to be updated):\n\n```cpp\n#include\"\\myMod\\myAddon\\file.txt\" // Arma 3\\@myMod\\addons\\myAddon.pbo\\file.txt;\n```\n\nTo move to parent directory use '..' (two dots) (Supported since Arma 3 v1.50):\n\n```cpp\n#include \"..\\file.sqf\"\n```\n\nPreprocessor does not support the use of macros for pre-defined file names.\n\n```cpp\n#define path \"codestrip.txt\"\n#include path // this will cause an error\n```\n\n#### #\n\n'#' (single hash) operator wraps the text with quotation marks.\n\n```cpp\n#define STRINGIFY(s) #s\n#define FOO 123\ntest1 = STRINGIFY(123); //test1 = \"123\";\ntest2 = STRINGIFY(FOO); //test2 = \"123\";\n```\n\nThis operator does only work on keywords following the rules for macro-names (see `1. define`-section).\nIf one wants to stringify anything else (like e.g. a number), one has to use a stringify-macro that takes an argument and stringifies that (as in the example above).\n\n```cpp\n#define MACRO Test #123\nMACRO // preprocesses to Test 123 - note that there are not any quotes inserted\n```\n\n#### ##\n\n'##' (double hash) operator concatenates what's before the ## with what's after it.\n\n```cpp\n#define GLUE(g1,g2) g1##g2\n#define FOO 123\n#define BAR 456\ntest1 = GLUE(123,456); //test1 = 123456;\ntest2 = GLUE(FOO,BAR); //test2 = 123456;\n```\n\n#### __LINE__\n\nThis keyword gets replaced with the line number in the file where it is found. For example, if `__LINE__` is found on the 10th line of a file, the word `__LINE__` will be replaced with the number 10.\n\n#### __FILE__\n\nThis keyword gets replaced with the CURRENT file being processed.\ne.g\n \"userconfig\\file1.sqf\"\n\n#### __FILE_NAME__ (Arma 3 v2.18)\n\nThis keyword gets replaced with the **name** of the current file being processed.\ne.g\n \"file1.sqf\"\n\n#### __FILE_SHORT__ (Arma 3 v2.18)\n\nThis keyword gets replaced with the **name** of the current file being processed, without extension.\ne.g\n \"file1\"\n\n#### __has_include (Arma 3 v2.02)\n\n**Description:** Checks if given file exists. Returns 1 if it does, 0 if it does not exist.\n\n> [!IMPORTANT]\n> - The file path must start with the backslash `\\` otherwise it would fail silently (returns `0` so does nothing unless you put something in `1. else`)!\n> - If you wanted to make an addon that can change its config dynamically depending on mods that loaded along, **do not** binarize the *config.cpp*!\n\n> [!NOTE]\n> To validate that the file exists in your game, you can use fileExists command to check.\n>\n> ```sqf\n> fileExists \"\\a3\\data_f\\config.bin\"; // returns true\n> fileExists \"\\z\\ace\\addons\\main\\script_component.hpp\"; // returns true if ACE is loaded, false otherwise\n> ```\n\n```cpp\n#if __has_include(\"\\z\\ace\\addons\\main\\script_component.hpp\")\n// file exists! Do something with it\n#else\n// file does not exist\n#endif\n```\n\n#### __DATE_ARR__ (Arma 3 v2.02)\n\n**Description:** Is replaced for current date in format array.\n\n```cpp\n__DATE_ARR__ // 2020,10,28,15,17,42\n```\n\n#### __DATE_STR__ (Arma 3 v2.02)\n\n**Description:** Is replaced for current date in format string.\n\n```cpp\n__DATE_STR__ // \"2020/10/28, 15:17:42\"\n```\n\n#### __DATE_STR_ISO8601__ (Arma 3 v2.02)\n\n**Description:** Is replaced for current date in format string. The date is presented in ISO8601 standard.\n\n```cpp\n__DATE_STR_ISO8601__ // \"2020-10-28T14:17:42Z\"\n```\n\n#### __TIME__ (Arma 3 v2.02)\n\n**Description:** Is replaced for current time.\n\n```cpp\n__TIME__ // 15:17:42\n```\n\n#### __TIME_UTC__ (Arma 3 v2.02)\n\n**Description:** Is replaced for UTC time.\n\n```cpp\n__TIME_UTC__ // 14:17:42\n```\n\n#### __DAY__ (Arma 3 v2.16)\n\n**Description:** Is replaced for UTC day.\n\n```cpp\n__DAY__ // 20\n```\n\n#### __MONTH__ (Arma 3 v2.16)\n\n**Description:** Is replaced for UTC month.\n\n```cpp\n__MONTH__ // 11\n```\n\n#### __YEAR__ (Arma 3 v2.16)\n\n**Description:** Is replaced for UTC year.\n\n```cpp\n__YEAR__ // 2023\n```\n\n#### __COUNTER__ (Arma 3 v2.02)\n\n**Description:** Counts 1 up everytime it is defined.\n\n```cpp\n__COUNTER__ // 0\n__COUNTER__ // 1\n__COUNTER__ // 2\n__COUNTER__ // 3\n__COUNTER_RESET__\n__COUNTER__ // 0\n__COUNTER__ // 1\n__COUNTER__ // 2\n```\n\n#### __TIMESTAMP_UTC__ (Arma 3 v2.06)\n\n**Description:** Is replaced to the current timestamp in UNIX timestamp.\n\n```cpp\n__TIMESTAMP_UTC__ // 1622639059\n```\n\n#### __COUNTER_RESET__ (Arma 3 v2.02)\n\n**Description:** Resets counter. See example above.\n\n#### __RAND_INT`N`__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by a random `N` bit integer. `N` can be 8, 16, 32 or 64, e.g:\n\n```cpp\n__RAND_INT8__\n__RAND_INT16__\n__RAND_INT32__\n__RAND_INT64__\n```\n\n```cpp\n__RAND_INT8__ // e.g -102\n```\n\n#### __RAND_UINT`N`__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by a random *unsigned* `N` bit integer. `N` can be 8, 16, 32 or 64, e.g:\n\n```cpp\n__RAND_UINT8__\n__RAND_UINT16__\n__RAND_UINT32__\n__RAND_UINT64__\n```\n\n```cpp\n__RAND_UINT8__ // 108\n```\n\n#### __GAME_VER__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by the game version.\n\n```cpp\n__GAME_VER__ // 02.00.146790\n```\n\n#### __GAME_VER_MAJ__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by the *major* game version.\n\n```cpp\n__GAME_VER_MAJ__ // 02\n```\n\n#### __GAME_VER_MIN__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by the *minor* game version.\n\n```cpp\n__GAME_VER_MIN__ // 00\n```\n\n#### __GAME_BUILD__ (Arma 3 v2.02)\n\n**Description:** Gets replaced by the build number.\n\n```cpp\n__GAME_BUILD__ // 146790\n```\n\n#### __A3_DIAG__ (Arma 3 v2.12)\n\n**Description:** Gets replaced by 1 on diag, undefined otherwise.\n\n```cpp\n__A3_DIAG__// 1\n```\n\n#### __ARMA__ (Arma 3 v2.02)\n\n**Description:**\n\n```cpp\n__ARMA__ // 1\n```\n\n#### __ARMA3__ (Arma 3 v2.02)\n\n**Description:**\n\n```cpp\n__ARMA3__ // 1\n```\n\n#### __A3_DEBUG__ (Arma 3 v2.02)\n\n**Description:** This macro is only set when the -debug parameter was provided. It can be used to switch mods or scripts to debug mode dynamically.\n\n```cpp\n__A3_DEBUG__ // 1 (if -debug was enabled)\n```\n\n#### __A3_EXPERIMENTAL__ (Arma 3 v2.15)\n\n**Description:** This macro is only set in experimental game builds (Development branch or Profiling branch)\n\n```cpp\n__A3_EXPERIMENTAL__ // 1 (if on dev or profiling branch)\n```\n\ncan be combined with game build to check for bugfixes added to profiling branch (in case a stable branch hotfix is released with a higher buildnumber but that doesn't include the fix)\n\n```cpp\n#if __GAME_VER_MIN__ >= 16 //#TODO remove this workaround when 2.16 is released\n#define BUG_FIXED\n#endif\n\n#if __GAME_BUILD__ > 151035 // Builds newer than this\n#if __A3_EXPERIMENTAL__ // But on experimental only\n#define BUG_FIXED\n#endif\n#endif\n\n#ifdef BUG_FIXED\nuse the thing\n#else\ndon't use the thing and have some workaround\n#endif\n```\n\n#### __A3_PROFILING__ (Arma 3 v2.15)\n\n**Description:** This macro is only set when Profiling commands are available (Development branch diag binary or in Profiling branch profiling binary)\n\n```cpp\n#if __A3_PROFILING__\ndiag_captureFrame 1;\n#endif\n```\n\n### Config Parser\n\n> [!IMPORTANT]\n> - `__EXEC` and `__EVAL` **cannot** be used in preprocessor #Macros, e.g **##if**!\n\n> [!NOTE]\n> - `__EXEC` and `__EVAL` can be used in configs (such as config.cpp, Description.ext, RVMat etc) but are not suitable for SQF or SQS scripts.\n> - As they use parsingNamespace, both global and local variables set in `__EXEC` are available in `__EVAL`.\n> - parsingNamespace can then be accessed through scripting; see the __EXEC example below.\n\n#### __EXEC\n\nThis **Config Parser** macro allows to assign values to internal variables or just execute arbitrary code.\nThe code inside `__EXEC` macros runs in parsingNamespace and variables defined in it will also be created in parsingNamespace. The variables can then be used to create more complex macros:\n\n```cpp\n__EXEC(cat = 5 + 1;)\n__EXEC(lev = cat - 2;)\n```\n\n```sqf\n_cat = parsingNamespace getVariable \"cat\"; // 6\n_lev = parsingNamespace getVariable \"lev\"; // 4\n```\n\n> [!WARNING]\n> `__EXEC` does not like round brackets `()` inside expressions. If grouping is needed, perhaps values could be calculated inside the brackets separately and assigned to local variables:\n>\n> ```cpp\n> __EXEC(a = (1+2);) // ERROR\n> ```\n>\n> ```cpp\n> __EXEC(_expr = 1+2;)\n> __EXEC(a = _expr;) // OK\n> ```\n\n#### __EVAL\n\nWith this **Config Parser** macro expressions can be evaluated, including previously assigned internal variables. Unlike `__EXEC`, `__EVAL` supports multiple parentheses:\n\n```cpp\nw = __EVAL(safeZoneW - (5 * ((1 / (getResolution select 2)) * 1.25 * 4)));\n```\n\n- `__EVAL` macros **must** be assigned to a config property and the expression **must** be terminated with `****`.\n- `__EVAL` can only return Number or String. Any other type is represented as String, even Boolean type (which would result in either `\"true\"` or `\"false\"`).\n\n> [!NOTE]\n> if code is needed in the expression, use compile String instead. Like so:\n>\n> ```cpp\n> result = __EVAL(call compile \"123\");\n> ```\n>\n> that is because `__EVAL` is incapable of dealing with curly brackets `{`}\n\n### Errors\n\n#### Error 2\n\n**Problem: Preprocessor failed error 2.**\n\n**How to fix: Add quotation marks in the title, or the file path. (*e.g.* `1. include \"soGood.sqf\"`).**\n\n#### Error 6\n\n**Problem: Preprocessor failed on file X - error 6.**\n\n**Known reasons:**\n\"The problem is using `1. ifdef #ifdef #endif #endif`, a.k.a nested `1. ifdef`. This doesn't work in Arma. It's only possible to use `1. ifdef` and `1. endif` once and not nested.\"\n`1. endif` without preceding `1. ifdef` or `1. ifndef`\n\n#### Error 7\n\n**Problem: Preprocessor failed on file X - error 7.**\n\n**Known reasons: The preprocessor encountered an unknown directive. Read, as a typo most has likely found a way into the file (something like `1. in*lc*ude` or `1. defi*en*`). Double-check all preprocessor directives in that file.**\n\n### External links\n\n- [Operation Flashpoint - Preprocessor Guide (Wayback Machine)](https://ofp-faguss.com/files/ofp_preprocessor_explained.pdf)\n- [Collection of preprocessor test-cases](https://github.com/Krzmbrzl/ArmaPreprocessorTestCases)","sections":[{"heading":null,"level":1,"markdown":"The PreProcessor and the Config Parser allow to use macros in configs.\nThe purpose of macros is to re-use the same definition in scripts and configs multiple times.\nIt also gives a centralised place to correct errors in this definition.\nKnow that edge cases may arise - see the collection of test-cases linked at the end of this page.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3, preprocessor commands are **case-sensitive!**"},{"heading":"Parsing","level":3,"markdown":"See #Config Parser below:\n- **Config.cpp** - parsed when PBO is binarised.\n  - localize cannot be used in macros, as it would hardcode string of current language instead of creating reference.\n- **Description.ext** - parsed when mission is loaded or previewed in missions list.\n- **SQF script** - parsed when preprocessFile, preprocessFileLineNumbers, compileScript or execVM is used."},{"heading":"Macros","level":3,"markdown":""},{"heading":"Strings","level":4,"markdown":"In both Configs and SQF scripts, there are two ways to define strings: either using single quotes (`'text'`) or double quotes (`\"text\"`).\nWhile they are both identical, they are **treated differently** by the preprocessor.\nThe **single quote** string contents are **parsed** by the preprocessor, while the **double quote** ones are **ignored**.\n\n```sqf\n#define ARG world\n\nsystemChat 'hello ARG'; // prints: hello world (i.e. ARG was replaced by the preprocessor with world)\nsystemChat \"hello ARG\"; // prints: hello ARG\n```\n\n> [!WARNING]\n> While it is possible in config to define a string without quotes (the preprocessor will act as if the value were wrapped with single quotes), this practice is heavily discouraged.\n>\n> ```cpp\n> title = \"$STR_TranslationKey\";    // good\n> title = $STR_TranslationKey;    // tolerated but incorrect\n> ```"},{"heading":"Comments","level":4,"markdown":"A comment is a line within code that is not actually processed by the game engine. They are used to make code more readable or to add notes for future reference.\nThe preprocessor removes all comments from the file before it is processed. Therefore, comments are never actually \"seen\" by the game engine.\n\n> [!WARNING]\n> Sometimes a problematic string can fail to purge these comment outs during preprocessing!\n>\n> ```sqf\n> private _a = '\"';\n> // this is just a comment, but failed to remove upon the preprocess so will return an error. Caused by that string\n> ```\n\n```cpp\n// this is a single-line comment\n\n/*\n    this is a\n    multi-line\n    comment\n*/\n\nmyValue = something; // only this part of the line is commented out\n\nmyArray = { \"apple\"/*, \"banana\"*/, \"pear\" }; // a portion in the middle of this line is commented out\n```"},{"heading":"#define","level":4,"markdown":"Using the `1. define` instruction, it is possible to define a keyword and assign a definition to it.\nThe keyword may contain any letter, digit or underscore in arbitrary order, as long as it does not start with a digit (RegEx: `[a-zA-Z_][0-9a-zA-Z_]*`).\nAs an example:\n\n```cpp\n#define true 1\n```\n\nThe above means that whenever *true* is used in a config, the parser will replace this with the value *1*.\n\nThe define-statement does swallow all spaces in between the macro-keyword and any non-space-character in the body (Note that tabs are not spaces! They don't get removed)\n\n```cpp\n#define MACRO test\nMACRO // preprocesses to test (without any spaces)\n\n#define MACRO    test // There's a tab between MACRO and test\nMACRO // preprocesses to \"    test\" (without quotes - they are only used to show that the tab character didn't get removed)\n```\n\nThe space between the macro-keyword and the body is also fully optional (though very useful to tell the preprocessor where the macro name ends and where the body begins):\n\n```cpp\n#define MACRO#test\nMACRO // preprocesses to \"test\"\n```"},{"heading":"Arguments","level":5,"markdown":"Arguments can be added to more complex macros, by including them between brackets after the keyword. For the name of the arguments the same rule as for the macro-keyword (see above) apply.\n\n```cpp\n#define CAR(NAME) displayName = NAME;\n```\n\nIf *CAR(\"Mini\")* is used, it will be replaced with *displayName = \"Mini\";*. Multiple arguments can also be used:\n\n```cpp\n#define BLASTOFF(UNIT,RATE) UNIT setVelocity [0,0,RATE];\n```\n\nMacro arguments may be composed of any characters, as long as they do not contain a comma (because commas are used as argument-delimiters).\nIf quotes are being used, they have to be balanced.\nThe same applies to single-quotes; this is because String detection is working in macro arguments - therefore commas can even get passed in as a macro argument as long as they are part of a String (This only works with Strings wrapped in double-quotes though).\nNote however that although the macro gets resolved properly, the comma gets removed from the String (probably a bug).\n\n```cpp\n#define MACRO(arg) arg\nMACRO(\"Some, content\") // preprocesses to \"Some content\" (note the missing comma)\n```\n\nQuote escaping is also not supported in this context (neither with double- nor with single-quotes)\n\n```cpp\n#define MACRO(arg) arg\nMACRO(\"Some \"\"content\"\"\") // preprocesses to \"Some \"\"content\"\"\"\n```\n\nPassing arrays with more than one element `[el1,el2,...]` as arguments into macros as well as any argument containing commas (e.g `\"some, sentence\"`) will need a small workaround:\n\n```cpp\n#define HINTARG(ARG) hint (\"Passed argument: \" + str ARG)\n```\n\nIncorrect usage:\n\n```cpp\nHINTARG([1,2,3,4,5,6,7,8,9,0]); // ERROR, won't even compile\n```\n\nCorrect usage:\n\n```cpp\n#define array1 [1,2,3,4,5,6,7,8,9,0]\nHINTARG(array1); // SUCCESS\n```\n\nThe argument replacement is performed before the expansion of the macro body. That means one doesn't have to worry about name-conflicts between argument-names of the current macro and already defined macros:\n\n```cpp\n#define ONE foo\n#define TWO(ONE) ONE\nTWO(bar) // will preprocess to bar\n```"},{"heading":"Replacing parts of words","level":5,"markdown":"By default, only whole words can be replaced by arguments. If only a part of the word should be replaced, use the `1.` instruction.\nThis is necessary when either the start or the end of the argument connects to another character that is not a `****` (semi-colon) or  (space).\n\n```cpp\nclass NAME##_Button_Slider: RscText \\\n{ \\\n    model = \\OFP2\\Structures\\Various\\##FOLDER##\\##FOLDER; \\\n```\n\nIt is also possible to use the single *#* to convert an argument to a string.\n\n```cpp\nstatement = (this animate [#SEL, 0]); \\\n```"},{"heading":"Multi-line","level":5,"markdown":"For longer definitions, one can stretch the macro across multiple lines. To create a multi-line definition, each line except the last one should end with a *\\* character:\n\n```cpp\n#define DRAWBUTTON(NAME)\\\n    __EXEC(idcNav = idcNav + 4) \\\n    // ...\n```\n\n> [!NOTE]\n> The backslash must be the last character in a line when defining a multi-line macro. Any character (including spaces) after the backslash will cause issues."},{"heading":"Variadic Arguments (Arma 3 v2.24)","level":5,"markdown":"Reference https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html\n\nVariadic arguments allows to provide a variable number of arguments to a macro, instead of a fixed number.\n\nAnd there are several \"functions\" to work with these variable-length argument lists.\n\nA basic variadic macro looks like this\n\n```cpp\n#define MACRO(...) __VA_ARGS__\n```\n\nThere are a few special keywords and \"functions\" that are only valid when used inside a variadic macro\n- `__VA_ARGS__`\n- `__VA_OPT__(X)`\n- `__VA_OPT_INV__(X)`\n- `__VA_APPLY__(FUNC(,SEP))`\n- `__VA_SELECT__(index)`"},{"heading":"__VA_ARGS__","level":6,"markdown":"is a special keyword that will be replaced by all the macro arguments, separated by \",\". For example:\n\n```cpp\n#define MACRO(...) __VA_ARGS__\n\nMACRO() // \"\", Zero is also a valid number of arguments\nMACRO(a,b,c) // \"a,b,c\", the arguments are \"a\", \"b\" and \"c\"\nMACRO({str [1,2,3]}) // \"{str [1,2,3]}\", the arguments are \"{str [1\", \"2\" and \"3]}\"\n```\n\nThis simple variant can replace helper macros like CBA mod's ARR_1, ARR_2, ARR_3, with just one ARR(...) macro.\n\nIt can also be used to wrap code blocks, which was difficult to do without it because they can contain commas and its not easy to tell the number of commas, like in the example above."},{"heading":"__VA_OPT__(x) and __VA_OPT_INV__(x)","level":6,"markdown":"are simple functions to handle the special case of there being zero variadic arguments.\n`__VA_OPT__(x)` is only active if arguments are present. And the INV variant is only active if no arguments are present\nFor example:\n\n```cpp\n#define HAS_ARGS __VA_OPT__(Yes I have Arguments!)__VA_OPT_INV__(Nothing!)\n\nHAS_ARGS() // \"Nothing!\"\nHAS_ARGS(a) // \"Yes I have Arguments!\"\nHAS_ARGS(a,b,c) // \"Yes I have Arguments!\", no matter how many arguments, if there is at least one, the optional data is inserted\n```\n\nThis is useful when the arguments are forwarded to something like:\n\n```cpp\n#define LOG(message, ...) diag_log __VA_OPT__([) message __VA_OPT__(,) __VA_ARGS__ __VA_OPT__(])\n\nLOG(\"My Message\") // 'diag_log  \"My Message\"   '\nLOG(\"My Message\",1,2,3) // 'diag_log [ \"My Message\" , 1,2,3 ]  '\n```"},{"heading":"__VA_APPLY__(FUNC, SEPARATOR)","level":6,"markdown":"is similar to apply in that it applies a function(macro) on every argument. The second \"SEPARATOR\" argument is optional, it can be used to replace the usual \",\" separator with something different.\n\nThe macro passed to apply must have 0, 1 or 2 arguments.\n\nIf 0 arguments, every value will be replaced by the macro contents, for example:\n\n```cpp\n#define FUNC A\n#define TRANSFORM(...) __VA_APPLY__(FUNC)\nTRANSFORM(1,2,3) // 'A,A,A'\n```\n\nIf 1 argument, it will be the value of the argument, for example:\n\n```cpp\n#define QUOTE(x) #x\n#define TRANSFORM(...) __VA_APPLY__(QUOTE)\nTRANSFORM(1,2,3) // '\"1\",\"2\",\"3\"'\n```\n\nIf 2, the second argument MUST be named `__VA_INDEX__`, it will be filled with the index of the argument, for example:\n\n```cpp\n#define FUNC(x, __VA_INDEX__) __VA_INDEX__: #x\n#define TRANSFORM(...) __VA_APPLY__(FUNC)\nTRANSFORM(1,2,3) // '0: \"1\",1: \"2\",2: \"3\"'\n```\n\nBy default, just like `__VA_ARGS__` when the values are written to the output, they will be separated by \",\".\n\nThis can be changed by providing a separator argument, for example:\nFor example:\n\n```cpp\n#define VERBATIM(x) x\n#define SEPARATOR_NONE\n#define TRANSFORM_CONCAT(...) __VA_APPLY__(QUOTE, SEPARATOR_NONE)\nTRANSFORM_CONCAT(1,2,3) // '123'\n\n#define GET_VARIABLE(x) private _##x = player getVariable #x\n#define SEPARATOR_SEMI ;\n#define GET_VARIABLES(...) __VA_APPLY__(GET_VARIABLE, SEPARATOR_SEMI)\n\nGET_VARIABLES() // ''\nGET_VARIABLES(MyFnc) // 'private _MyFnc = player getVariable \"MyFnc\"'\nGET_VARIABLES(MyFnc,MyOtherFnc) // 'private _MyFnc = player getVariable \"MyFnc\";private _MyOtherFnc = player getVariable \"MyOtherFnc\"'\n```\n\nThe results of `__VA_APPLY__` can also be passed to another variadic macro, for example:\n\n```cpp\n#define QUOTE(x) #x\n#define WRITE_LOG(...) diag_log [__VA_ARGS__]\n#define MAKE_ARRAY(...) [__VA_ARGS__]\n\n#define DO_THINGS(...) WRITE_LOG(__VA_APPLY__(QUOTE)); _array = MAKE_ARRAY(__VA_ARGS__);\n\nDO_THINGS(a,b,c) // diag_log [\"a\",\"b\",\"c\"]; _array = [a,b,c];\n```"},{"heading":"__VA_SELECT__(index)","level":6,"markdown":"will select the specified element out of the `__VA_ARGS__` list. index must be a number.\nFor example:\n\n```cpp\n#define SELECT_ARG(index, ...) __VA_SELECT__(index)\n#define FORMAT_ARG(index) SELECT_ARG(index, \"A=%2\", \"B=%3\", \"C=%4\", \"D=%5\", \"E=%6\", \"F=%7\")\n#define FORMAT_GET_ARGSTR(arg, __VA_INDEX__) FORMAT_ARG(__VA_INDEX__)\n#define FORMAT(MESSAGE, ...) format [[__VA_OPT_INV__('%1') __VA_OPT__('%1:',) __VA_APPLY__(FORMAT_GET_ARGSTR)] joinString ' ', MESSAGE __VA_OPT__(,) __VA_ARGS__]\n\nFORMAT(\"Message\") // `format [['%1'  ] joinString ' ', \"Message\"  ]`\nFORMAT(\"Message\", value1, value2) // `format [[ '%1:',  \"A=%2\", \"B=%3\"] joinString ' ', \"Message\" ,  value1, value2]` which ends up as `format [\"%1: A=%2 B=%3\", \"Message\", value1, value2]`\n```"},{"heading":"#undef","level":4,"markdown":"Undefine (delete) a macro previously set by the use of #define.\n\n```cpp\n#undef NAME\n```"},{"heading":"#if","level":4,"markdown":"**Description:** Checks condition and processes content if condition returns 1. Skips content if it returns 0\n\n```cpp\n#if __GAME_VER_MAJ__ != 2\n// Do something...\n#endif\n```"},{"heading":"Comparison Operators","level":5,"markdown":"The following operations are supported:\n- <\n- >\n- <=\n- >=\n- ==\n- !=\n**Example:**\n\n```cpp\n#if __GAME_VER_MAJ__ != 2\n// Do something...\n#endif\n```"},{"heading":"#ifdef","level":4,"markdown":"A simple if-then construction to check whether a certain set of definitions has already been made:\n\n```cpp\n#ifdef NAME\n    // config that will be used if NAME is defined\n#endif\n```\n\nIFDEFs *cannot* be nested. The preprocessor will generate errors for all inner definitions if the outer definition doesn't exist."},{"heading":"#ifndef","level":4,"markdown":"Same as #ifdef, but checks for absence of definition instead.\n\n```cpp\n#ifndef NAME\n    // config that will be used if NAME is -not- defined\n#endif\n```"},{"heading":"#else","level":4,"markdown":"Provides alternative code to `1. if`, `1. ifdef`, `1. ifndef` checks.\n\n```cpp\n#ifndef NAME\n    // config that will be used if NAME is -not- defined\n#else\n    // config that will be used if NAME -is- defined\n#endif\n```"},{"heading":"#endif","level":4,"markdown":"This ends a conditional block as shown in the descriptions of #ifdef and #ifndef above."},{"heading":"#include","level":4,"markdown":"Copies the code from a target file and pastes it where #include directive is.\n\n```cpp\n#include \"file.hpp\"\n#include <file.txt> // Brackets are equivalent to quotation marks and may be used in their place.\n```\n\nSource directory is:\n- For any file without starting the include path with \\ - the file's current directory\n- When starting with \\ - the internal filesystem root (see Addon Prefix) or the Game's working directory (only with -filePatching enabled)\n\nA path beginning can be defined as follow:\n- drive (only with -filePatching enabled): \n\n```cpp\n#include \"D:\\file.txt\"\n```\n\n- PBO with PBOPREFIX: \n\n```cpp\n #include \"\\myMod\\myAddon\\file.txt\"\n```\n\n- PBO (keep in mind that in this case, if the PBO's file name will be changed, all '#include' referencing it will need to be updated):\n\n```cpp\n#include\"\\myMod\\myAddon\\file.txt\" // Arma 3\\@myMod\\addons\\myAddon.pbo\\file.txt;\n```\n\nTo move to parent directory use '..' (two dots) (Supported since Arma 3 v1.50):\n\n```cpp\n#include \"..\\file.sqf\"\n```\n\nPreprocessor does not support the use of macros for pre-defined file names.\n\n```cpp\n#define path \"codestrip.txt\"\n#include path // this will cause an error\n```"},{"heading":"#","level":4,"markdown":"'#' (single hash) operator wraps the text with quotation marks.\n\n```cpp\n#define STRINGIFY(s) #s\n#define FOO 123\ntest1 = STRINGIFY(123); //test1 = \"123\";\ntest2 = STRINGIFY(FOO); //test2 = \"123\";\n```\n\nThis operator does only work on keywords following the rules for macro-names (see `1. define`-section).\nIf one wants to stringify anything else (like e.g. a number), one has to use a stringify-macro that takes an argument and stringifies that (as in the example above).\n\n```cpp\n#define MACRO Test #123\nMACRO // preprocesses to Test 123 - note that there are not any quotes inserted\n```"},{"heading":"##","level":4,"markdown":"'##' (double hash) operator concatenates what's before the ## with what's after it.\n\n```cpp\n#define GLUE(g1,g2) g1##g2\n#define FOO 123\n#define BAR 456\ntest1 = GLUE(123,456); //test1 = 123456;\ntest2 = GLUE(FOO,BAR); //test2 = 123456;\n```"},{"heading":"__LINE__","level":4,"markdown":"This keyword gets replaced with the line number in the file where it is found. For example, if `__LINE__` is found on the 10th line of a file, the word `__LINE__` will be replaced with the number 10."},{"heading":"__FILE__","level":4,"markdown":"This keyword gets replaced with the CURRENT file being processed.\ne.g\n \"userconfig\\file1.sqf\""},{"heading":"__FILE_NAME__ (Arma 3 v2.18)","level":4,"markdown":"This keyword gets replaced with the **name** of the current file being processed.\ne.g\n \"file1.sqf\""},{"heading":"__FILE_SHORT__ (Arma 3 v2.18)","level":4,"markdown":"This keyword gets replaced with the **name** of the current file being processed, without extension.\ne.g\n \"file1\""},{"heading":"__has_include (Arma 3 v2.02)","level":4,"markdown":"**Description:** Checks if given file exists. Returns 1 if it does, 0 if it does not exist.\n\n> [!IMPORTANT]\n> - The file path must start with the backslash `\\` otherwise it would fail silently (returns `0` so does nothing unless you put something in `1. else`)!\n> - If you wanted to make an addon that can change its config dynamically depending on mods that loaded along, **do not** binarize the *config.cpp*!\n\n> [!NOTE]\n> To validate that the file exists in your game, you can use fileExists command to check.\n>\n> ```sqf\n> fileExists \"\\a3\\data_f\\config.bin\"; // returns true\n> fileExists \"\\z\\ace\\addons\\main\\script_component.hpp\"; // returns true if ACE is loaded, false otherwise\n> ```\n\n```cpp\n#if __has_include(\"\\z\\ace\\addons\\main\\script_component.hpp\")\n// file exists! Do something with it\n#else\n// file does not exist\n#endif\n```"},{"heading":"__DATE_ARR__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Is replaced for current date in format array.\n\n```cpp\n__DATE_ARR__ // 2020,10,28,15,17,42\n```"},{"heading":"__DATE_STR__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Is replaced for current date in format string.\n\n```cpp\n__DATE_STR__ // \"2020/10/28, 15:17:42\"\n```"},{"heading":"__DATE_STR_ISO8601__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Is replaced for current date in format string. The date is presented in ISO8601 standard.\n\n```cpp\n__DATE_STR_ISO8601__ // \"2020-10-28T14:17:42Z\"\n```"},{"heading":"__TIME__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Is replaced for current time.\n\n```cpp\n__TIME__ // 15:17:42\n```"},{"heading":"__TIME_UTC__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Is replaced for UTC time.\n\n```cpp\n__TIME_UTC__ // 14:17:42\n```"},{"heading":"__DAY__ (Arma 3 v2.16)","level":4,"markdown":"**Description:** Is replaced for UTC day.\n\n```cpp\n__DAY__ // 20\n```"},{"heading":"__MONTH__ (Arma 3 v2.16)","level":4,"markdown":"**Description:** Is replaced for UTC month.\n\n```cpp\n__MONTH__ // 11\n```"},{"heading":"__YEAR__ (Arma 3 v2.16)","level":4,"markdown":"**Description:** Is replaced for UTC year.\n\n```cpp\n__YEAR__ // 2023\n```"},{"heading":"__COUNTER__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Counts 1 up everytime it is defined.\n\n```cpp\n__COUNTER__ // 0\n__COUNTER__ // 1\n__COUNTER__ // 2\n__COUNTER__ // 3\n__COUNTER_RESET__\n__COUNTER__ // 0\n__COUNTER__ // 1\n__COUNTER__ // 2\n```"},{"heading":"__TIMESTAMP_UTC__ (Arma 3 v2.06)","level":4,"markdown":"**Description:** Is replaced to the current timestamp in UNIX timestamp.\n\n```cpp\n__TIMESTAMP_UTC__ // 1622639059\n```"},{"heading":"__COUNTER_RESET__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Resets counter. See example above."},{"heading":"__RAND_INT`N`__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by a random `N` bit integer. `N` can be 8, 16, 32 or 64, e.g:\n\n```cpp\n__RAND_INT8__\n__RAND_INT16__\n__RAND_INT32__\n__RAND_INT64__\n```\n\n```cpp\n__RAND_INT8__ // e.g -102\n```"},{"heading":"__RAND_UINT`N`__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by a random *unsigned* `N` bit integer. `N` can be 8, 16, 32 or 64, e.g:\n\n```cpp\n__RAND_UINT8__\n__RAND_UINT16__\n__RAND_UINT32__\n__RAND_UINT64__\n```\n\n```cpp\n__RAND_UINT8__ // 108\n```"},{"heading":"__GAME_VER__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by the game version.\n\n```cpp\n__GAME_VER__ // 02.00.146790\n```"},{"heading":"__GAME_VER_MAJ__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by the *major* game version.\n\n```cpp\n__GAME_VER_MAJ__ // 02\n```"},{"heading":"__GAME_VER_MIN__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by the *minor* game version.\n\n```cpp\n__GAME_VER_MIN__ // 00\n```"},{"heading":"__GAME_BUILD__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** Gets replaced by the build number.\n\n```cpp\n__GAME_BUILD__ // 146790\n```"},{"heading":"__A3_DIAG__ (Arma 3 v2.12)","level":4,"markdown":"**Description:** Gets replaced by 1 on diag, undefined otherwise.\n\n```cpp\n__A3_DIAG__// 1\n```"},{"heading":"__ARMA__ (Arma 3 v2.02)","level":4,"markdown":"**Description:**\n\n```cpp\n__ARMA__ // 1\n```"},{"heading":"__ARMA3__ (Arma 3 v2.02)","level":4,"markdown":"**Description:**\n\n```cpp\n__ARMA3__ // 1\n```"},{"heading":"__A3_DEBUG__ (Arma 3 v2.02)","level":4,"markdown":"**Description:** This macro is only set when the -debug parameter was provided. It can be used to switch mods or scripts to debug mode dynamically.\n\n```cpp\n__A3_DEBUG__ // 1 (if -debug was enabled)\n```"},{"heading":"__A3_EXPERIMENTAL__ (Arma 3 v2.15)","level":4,"markdown":"**Description:** This macro is only set in experimental game builds (Development branch or Profiling branch)\n\n```cpp\n__A3_EXPERIMENTAL__ // 1 (if on dev or profiling branch)\n```\n\ncan be combined with game build to check for bugfixes added to profiling branch (in case a stable branch hotfix is released with a higher buildnumber but that doesn't include the fix)\n\n```cpp\n#if __GAME_VER_MIN__ >= 16 //#TODO remove this workaround when 2.16 is released\n#define BUG_FIXED\n#endif\n\n#if __GAME_BUILD__ > 151035 // Builds newer than this\n#if __A3_EXPERIMENTAL__ // But on experimental only\n#define BUG_FIXED\n#endif\n#endif\n\n#ifdef BUG_FIXED\nuse the thing\n#else\ndon't use the thing and have some workaround\n#endif\n```"},{"heading":"__A3_PROFILING__ (Arma 3 v2.15)","level":4,"markdown":"**Description:** This macro is only set when Profiling commands are available (Development branch diag binary or in Profiling branch profiling binary)\n\n```cpp\n#if __A3_PROFILING__\ndiag_captureFrame 1;\n#endif\n```"},{"heading":"Config Parser","level":3,"markdown":"> [!IMPORTANT]\n> - `__EXEC` and `__EVAL` **cannot** be used in preprocessor #Macros, e.g **##if**!\n\n> [!NOTE]\n> - `__EXEC` and `__EVAL` can be used in configs (such as config.cpp, Description.ext, RVMat etc) but are not suitable for SQF or SQS scripts.\n> - As they use parsingNamespace, both global and local variables set in `__EXEC` are available in `__EVAL`.\n> - parsingNamespace can then be accessed through scripting; see the __EXEC example below."},{"heading":"__EXEC","level":4,"markdown":"This **Config Parser** macro allows to assign values to internal variables or just execute arbitrary code.\nThe code inside `__EXEC` macros runs in parsingNamespace and variables defined in it will also be created in parsingNamespace. The variables can then be used to create more complex macros:\n\n```cpp\n__EXEC(cat = 5 + 1;)\n__EXEC(lev = cat - 2;)\n```\n\n```sqf\n_cat = parsingNamespace getVariable \"cat\"; // 6\n_lev = parsingNamespace getVariable \"lev\"; // 4\n```\n\n> [!WARNING]\n> `__EXEC` does not like round brackets `()` inside expressions. If grouping is needed, perhaps values could be calculated inside the brackets separately and assigned to local variables:\n>\n> ```cpp\n> __EXEC(a = (1+2);) // ERROR\n> ```\n>\n> ```cpp\n> __EXEC(_expr = 1+2;)\n> __EXEC(a = _expr;) // OK\n> ```"},{"heading":"__EVAL","level":4,"markdown":"With this **Config Parser** macro expressions can be evaluated, including previously assigned internal variables. Unlike `__EXEC`, `__EVAL` supports multiple parentheses:\n\n```cpp\nw = __EVAL(safeZoneW - (5 * ((1 / (getResolution select 2)) * 1.25 * 4)));\n```\n\n- `__EVAL` macros **must** be assigned to a config property and the expression **must** be terminated with `****`.\n- `__EVAL` can only return Number or String. Any other type is represented as String, even Boolean type (which would result in either `\"true\"` or `\"false\"`).\n\n> [!NOTE]\n> if code is needed in the expression, use compile String instead. Like so:\n>\n> ```cpp\n> result = __EVAL(call compile \"123\");\n> ```\n>\n> that is because `__EVAL` is incapable of dealing with curly brackets `{`}"},{"heading":"Errors","level":3,"markdown":""},{"heading":"Error 2","level":4,"markdown":"**Problem: Preprocessor failed error 2.**\n\n**How to fix: Add quotation marks in the title, or the file path. (*e.g.* `1. include \"soGood.sqf\"`).**"},{"heading":"Error 6","level":4,"markdown":"**Problem: Preprocessor failed on file X - error 6.**\n\n**Known reasons:**\n\"The problem is using `1. ifdef #ifdef #endif #endif`, a.k.a nested `1. ifdef`. This doesn't work in Arma. It's only possible to use `1. ifdef` and `1. endif` once and not nested.\"\n`1. endif` without preceding `1. ifdef` or `1. ifndef`"},{"heading":"Error 7","level":4,"markdown":"**Problem: Preprocessor failed on file X - error 7.**\n\n**Known reasons: The preprocessor encountered an unknown directive. Read, as a typo most has likely found a way into the file (something like `1. in*lc*ude` or `1. defi*en*`). Double-check all preprocessor directives in that file.**"},{"heading":"External links","level":3,"markdown":"- [Operation Flashpoint - Preprocessor Guide (Wayback Machine)](https://ofp-faguss.com/files/ofp_preprocessor_explained.pdf)\n- [Collection of preprocessor test-cases](https://github.com/Krzmbrzl/ArmaPreprocessorTestCases)"}],"categories":["Scripting Topics","Stubs"],"groups":["Scripting"]},{"name":"Scheduler","title":"Scheduler","type":"topic","url":"https://community.bistudio.com/wiki/Scheduler","revid":351907,"updated":"2024-01-24T14:43:29Z","aliases":[],"markdown":"The Scheduler is the part of the game engine that decides which script runs at a certain point in time. It has the ability to pause a running script, move it to the back of the running queue and start a new script.\n\n### Scripts\n\nA new script can be started by using spawn, execVM, exec and execFSM commands. The script started this way will be added into the script scheduler and will be executed in turns, giving priority to the scripts waiting longest since their last suspension. Completed scripts are removed from the scheduler while scripts not completed in allocated time are suspended.\n\n### Scheduled Environment\n\nRunning code in a scheduled environment starts a new script. The executing instance will not wait for the result of scheduled code and will continue on with its execution, so it is not possible to return any values from code executed in this manner although a Script Handle for started script is provided.\n\nAs described below there is no way to predict when scheduled code will have finished, although you can use the command scriptDone with the provided Script Handle to query if the script execution has finished and there is also the command terminate to abort the script.\n\nBecause the scheduled code can run only for a fixed duration, heavy scripts spread their load over time, and thus are having lesser impact on the game performance.\n\n**All scheduled scripts can run for a maximum of 3ms in a frame**. (Except if inside loadingscreen where it is 50ms per frame)\n\nEach Script that runs add's up to the total runtime and as soon as the total runtime of 3ms is reached the current script is paused and the game continues calculating everything else it needs to calculate that frame (For example sound and graphics rendering). On the next frame the scheduler again starts to run scripts for 3ms, starting with the script which has not been executed for the longest time.\n\nThis means any script that ran as the 3ms runtime was reached will be paused in the middle of it is execution and depending on how many scripts are spawned it might take several frames till it will run again.\nA while true loop with sleep started in scheduled environment therefore has little chance to follow with exact interval, because sleep only marks the script as done in the current frame and the next time the script is executed the engine will check if the sleep is over.\nThis means at 20 FPS the time between one frame and the next is roughly 50ms. That would make a sleep 0.01 wait for atleast 0.05 seconds.This effect get's bigger when the fps get even lower and if the scheduler is so overfilled that your script only get's checked every few frames instead of every frame.\n\nIf you spawn a scheduled script it will only start to run in the next frame when the scheduler starts fresh again.\n\n#### Where code starts scheduled\n\n- init.sqf\n- initServer.sqf\n- initPlayerLocal.sqf\n- initPlayerServer.sqf\n- functions with postInit attribute (although suspension is allowed, any long term suspension will halt the mission loading until suspension has finished)\n- code executed with spawn\n- code executed with execVM\n- code executed with exec\n- code executed with call from a scheduled environment\n\n#### Scheduler diagnostics commands\n\nThe following commands are available:\n- diag_activeSQSScripts - for all execed scripts in the scheduler\n- diag_activeSQFScripts - for all execVMed and spawned scripts in the scheduler\n- diag_activeMissionFSMs - for all execFSMed scripts in the scheduler\n- diag_activeScripts - for all scripts in the scheduler\n\n### Unscheduled Environment\n\nOften also called non-scheduled environment but means the same and you will find both terms used in this wiki.\nThe unscheduled environment runs (as described above) in the executing instance. The executing instance waits until the called function is finished. This ensures the execution order and is the fastest way for scripters to execute their code. The disadvantage is that a called function can halt or slow down the game if the function has a high performance consumption. Therefore those functions should be spawned and thereby run in a scheduled environment.\n\n#### Where code starts unscheduled\n\n- Debug Console\n- Triggers\n- Waypoints (condition *and* activation)\n- All pre-init code executions including functions with preInit attribute\n- Code executed by FSM (actions, conditions, etc.)\n- Event Handlers on units and in GUI\n- *EachFrame* code (Event Handler / Scripted EH / onEachFrame)\n- Object initialisation fields\n- Expressions of Eden Editor entity/mission attributes\n- Code execution with call from an unscheduled environment\n- Code executed with remoteExecCall\n- Code inside isNil\n- SQF code called from SQS code\n- Conversation Event Handler\n- Code inside collect3DENHistory\n\n#### while Loops\n\nA while-do loop is limited to (hard-coded) **10,000** iterations in a non-scheduled environment.\n\n### Suspension\n\nSuspension is the process to wait a period of time or to wait for something to happen. Commands for suspension are sleep, uiSleep, waitUntil.\n\nSuspension is **forbidden** in an unscheduled environment and trying to use such command will fail with an error; you must ensure that you are running your code in a scheduled environment **and** can suspend with the **canSuspend** command.","sections":[{"heading":null,"level":1,"markdown":"The Scheduler is the part of the game engine that decides which script runs at a certain point in time. It has the ability to pause a running script, move it to the back of the running queue and start a new script."},{"heading":"Scripts","level":3,"markdown":"A new script can be started by using spawn, execVM, exec and execFSM commands. The script started this way will be added into the script scheduler and will be executed in turns, giving priority to the scripts waiting longest since their last suspension. Completed scripts are removed from the scheduler while scripts not completed in allocated time are suspended."},{"heading":"Scheduled Environment","level":3,"markdown":"Running code in a scheduled environment starts a new script. The executing instance will not wait for the result of scheduled code and will continue on with its execution, so it is not possible to return any values from code executed in this manner although a Script Handle for started script is provided.\n\nAs described below there is no way to predict when scheduled code will have finished, although you can use the command scriptDone with the provided Script Handle to query if the script execution has finished and there is also the command terminate to abort the script.\n\nBecause the scheduled code can run only for a fixed duration, heavy scripts spread their load over time, and thus are having lesser impact on the game performance.\n\n**All scheduled scripts can run for a maximum of 3ms in a frame**. (Except if inside loadingscreen where it is 50ms per frame)\n\nEach Script that runs add's up to the total runtime and as soon as the total runtime of 3ms is reached the current script is paused and the game continues calculating everything else it needs to calculate that frame (For example sound and graphics rendering). On the next frame the scheduler again starts to run scripts for 3ms, starting with the script which has not been executed for the longest time.\n\nThis means any script that ran as the 3ms runtime was reached will be paused in the middle of it is execution and depending on how many scripts are spawned it might take several frames till it will run again.\nA while true loop with sleep started in scheduled environment therefore has little chance to follow with exact interval, because sleep only marks the script as done in the current frame and the next time the script is executed the engine will check if the sleep is over.\nThis means at 20 FPS the time between one frame and the next is roughly 50ms. That would make a sleep 0.01 wait for atleast 0.05 seconds.This effect get's bigger when the fps get even lower and if the scheduler is so overfilled that your script only get's checked every few frames instead of every frame.\n\nIf you spawn a scheduled script it will only start to run in the next frame when the scheduler starts fresh again."},{"heading":"Where code starts scheduled","level":4,"markdown":"- init.sqf\n- initServer.sqf\n- initPlayerLocal.sqf\n- initPlayerServer.sqf\n- functions with postInit attribute (although suspension is allowed, any long term suspension will halt the mission loading until suspension has finished)\n- code executed with spawn\n- code executed with execVM\n- code executed with exec\n- code executed with call from a scheduled environment"},{"heading":"Scheduler diagnostics commands","level":4,"markdown":"The following commands are available:\n- diag_activeSQSScripts - for all execed scripts in the scheduler\n- diag_activeSQFScripts - for all execVMed and spawned scripts in the scheduler\n- diag_activeMissionFSMs - for all execFSMed scripts in the scheduler\n- diag_activeScripts - for all scripts in the scheduler"},{"heading":"Unscheduled Environment","level":3,"markdown":"Often also called non-scheduled environment but means the same and you will find both terms used in this wiki.\nThe unscheduled environment runs (as described above) in the executing instance. The executing instance waits until the called function is finished. This ensures the execution order and is the fastest way for scripters to execute their code. The disadvantage is that a called function can halt or slow down the game if the function has a high performance consumption. Therefore those functions should be spawned and thereby run in a scheduled environment."},{"heading":"Where code starts unscheduled","level":4,"markdown":"- Debug Console\n- Triggers\n- Waypoints (condition *and* activation)\n- All pre-init code executions including functions with preInit attribute\n- Code executed by FSM (actions, conditions, etc.)\n- Event Handlers on units and in GUI\n- *EachFrame* code (Event Handler / Scripted EH / onEachFrame)\n- Object initialisation fields\n- Expressions of Eden Editor entity/mission attributes\n- Code execution with call from an unscheduled environment\n- Code executed with remoteExecCall\n- Code inside isNil\n- SQF code called from SQS code\n- Conversation Event Handler\n- Code inside collect3DENHistory"},{"heading":"while Loops","level":4,"markdown":"A while-do loop is limited to (hard-coded) **10,000** iterations in a non-scheduled environment."},{"heading":"Suspension","level":3,"markdown":"Suspension is the process to wait a period of time or to wait for something to happen. Commands for suspension are sleep, uiSleep, waitUntil.\n\nSuspension is **forbidden** in an unscheduled environment and trying to use such command will fail with an error; you must ensure that you are running your code in a scheduled environment **and** can suspend with the **canSuspend** command."}],"categories":["Scripting Topics"],"groups":["Scripting"]},{"name":"Script Handle","title":"Script Handle","type":"topic","url":"https://community.bistudio.com/wiki/Script_Handle","revid":378908,"updated":"2026-08-11T15:02:59Z","aliases":["Script (Handle)"],"markdown":"A **Script Handle**, used to identify scripts in script operations called using spawn or execVM.\nIntroduced with Armed Assault, does not refer to Operation Flashpoint or Operation Flashpoint: Resistance.\n\nThis handle's status can be checked with scriptDone, it can be terminated with terminate.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3:\n> - the handle's status can also be checked with isNull (A completed script will become null)\n> - the handle can be accessed from whithin itself using `_thisScript` (since Arma 3 v1.54)\n\n> [!NOTE]\n> For more information about scripts and scripting, see Scripting Topics and Introduction to Arma Scripting.\n\n### Promise Handles (Arma 3 v2.22)\n\nScript handles can be used as [promises](https://en.wikipedia.org/wiki/Futures_and_promises).\n\nA Promise is either a Script Handle to a spawned or execVMed script, or an \"Empty Handle\" that does not hold a backing script.\nThe Handle can be used to wait for the a result to be available.\nIn case of a \"real\" handle that means the scheduled script returning a value, or in the case of a \"Empty Handle\" by using terminate to set a result value.\n\nA Promise can have continuations added onto it with continueWith, which is script code that will execute once the handle is completed.\n\nHandles can be used with waitUntil, continueWith, terminate, scriptDone, name.\n\n#### Creating a Promise\n\nEvery handle returned by spawn or execVM is a promise that gets resolved once the script exits.\n\nIt's also possible to create a \"Empty Handle\" which does not hold any scheduled script, and can also be used in unscheduled code.\n\nA \"Empty Handle\" needs to be \"completed\" by calling terminate on it.\n\n```sqf\nprivate _emptyHandle = spawn \"HandleName\"; // does not contain an actual script, it's only a holder for name and potentially a value\nprivate _normalHandle = 0 spawn { scriptName \"HandleName\"; }; // contains an actual scheduled script that will execute and return a value at the end\n```\n\n#### Using Promises\n\nPromises can be used to simplify asynchronous operations.\nFor example, when calling a function that takes some time to complete, and then wanting to execute code after it has completed.\n\nTo show it on an example, let's say we have a function that paradrops a vehicle.\nAnd we want to wait for the vehicle to touch the ground and then spawn a smoke grenade on it.\n\nPreviously, that could be solved like so:\n\n```sqf\nfnc_StartParadrop = {\n    params [\"_object\"];\n\n    private _parachute = createVehicle [\"B_Parachute_02_F\", [0, 0, 0], [], 0, \"CAN_COLLIDE\"];\n\n    // Put the parachute into the right position (setPos doesn't work on them)\n    _parachute attachTo [_object, [0, 0, 0]];\n    detach _parachute;\n\n    _object attachTo [_parachute, [0, 0, 0]];\n    // Now the object is hanging on parachute and gliding down\n    // But we want to wait for it to arrive at the bottom, the parachute will be deleted once it lands, so we can use that\n\n    // The parachute won't know about us, and we cannot get a value out of the eventhandler, so we will give the parachute a place to store the result\n    // Note this will not work across savegame save/load because the \"result\" reference will be lost.\n\n    private _result = [];\n    _parachute setVariable [\"result\", _result];\n    _parachute addEventHandler [\"Deleted\", {\n        params [\"_entity\"];\n        (_entity getVariable \"result\") set [0, getPos _entity]; // Store the landing position of the parachute\n    }];\n\n    // _result will be set once the parachute landed. How we wait on the result now depends on whether this is a scheduled or unscheduled function\n    // In unscheduled code we cannot wait, we would need to get some callback function in our arguments to notify our caller that it can continue.\n    // For simplicity we show the scheduled variant here, the unscheduled would be more complex\n\n    // Keep looping, until someone (Hopefully the Deleted eventhandler) wrote a result into our array\n    waitUntil { _result isNotEqualTo []; };\n\n    _result select 0; // We return the result, our user must have call'ed us to wait for us to finish and get the result\n};\n\n// The fnc_StartParadrop will wait, so we have to spawn a new script to not hold up everything else\n0 spawn {\n    private _dropPos = ParadropVehicle call fnc_StartParadrop; // This will wait until the vehicle has landed\n    \"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n};\n```\n\nAlso note how the waitUntil always runs.\nEven if we as the caller do not care for the paradrop to finish, we wouldn't easily have the option to tell the script that, without adding another parameter to it.\nAlso note that this function is not usable in unscheduled scripts, because it uses waitUntil to wait for the landing.\n\nWith promises, it can be solved like this:\n\n```sqf\nfnc_StartParadrop = {\n    params [\"_object\"];\n\n    private _parachute = createVehicle [\"B_Parachute_02_F\", [0, 0, 0], [], 0, \"CAN_COLLIDE\"];\n\n    // Put the parachute into the right position (setPos doesn't work on them)\n    _parachute attachTo [_object, [0, 0, 0]];\n    detach _parachute;\n\n    _object attachTo [_parachute, [0, 0, 0]];\n    // Now the object is hanging on parachute and gliding down\n    // But we want to wait for it to arrive at the bottom, the parachute will be deleted once it lands, so we can use that\n\n    // The parachute won't know about us, and we cannot get a value out of the eventhandler, so we will give the parachute a place to store the result\n    private _paradropHandle = spawn \"Paradrop\"; // We create new Promise, that we will use to return the result\n\n    _parachute setVariable [\"handle\", _paradropHandle];\n    _parachute addEventHandler [\"Deleted\", {\n        params [\"_entity\"];\n        (_entity getVariable \"handle\") terminate (getPos _entity); // Complete the promise and pass the landing position as result\n    }];\n    _paradropHandle // We return the promise, the caller can decide if they want to use it or not\n};\n\n// Note we do not need to spawn another script because we are not waiting for anything, this can fully be handled in unscheduled code now\n\n_paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\n_paradropHandle continueWith { \"SmokeshellGreen\" createVehicle _this; }; // We use a continuation, it will be triggered once terminate is called on the handle (Inside the \"Deleted\" eventhandler)\n```\n\nNote that the paradrop function can now also be used in scheduled scripts like so:\n\n```sqf\nprivate _paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\nprivate _dropPos = waitUntil _paradropHandle; // Wait for the promise to be completed and get its result\n\"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n```\n\nOr like so:\n\n```sqf\nprivate _paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\nprivate _dropPos = waitUntil [_paradropHandle, 60]; // Wait for the promise to be completed, but at most for 60 seconds, if it still has not landed yet, we will report it to the player\n\nif (isNil \"_dropPos\") then {\n    // The promise yielded no result. Either it was terminated without a result, or our timeout has elapsed\n    hint \"The Paradrop has failed!\";\n} else {\n    \"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n};\n```","sections":[{"heading":null,"level":1,"markdown":"A **Script Handle**, used to identify scripts in script operations called using spawn or execVM.\nIntroduced with Armed Assault, does not refer to Operation Flashpoint or Operation Flashpoint: Resistance.\n\nThis handle's status can be checked with scriptDone, it can be terminated with terminate.\n\n> [!NOTE]\n> **Arma 3:** In Arma 3:\n> - the handle's status can also be checked with isNull (A completed script will become null)\n> - the handle can be accessed from whithin itself using `_thisScript` (since Arma 3 v1.54)\n\n> [!NOTE]\n> For more information about scripts and scripting, see Scripting Topics and Introduction to Arma Scripting."},{"heading":"Promise Handles (Arma 3 v2.22)","level":3,"markdown":"Script handles can be used as [promises](https://en.wikipedia.org/wiki/Futures_and_promises).\n\nA Promise is either a Script Handle to a spawned or execVMed script, or an \"Empty Handle\" that does not hold a backing script.\nThe Handle can be used to wait for the a result to be available.\nIn case of a \"real\" handle that means the scheduled script returning a value, or in the case of a \"Empty Handle\" by using terminate to set a result value.\n\nA Promise can have continuations added onto it with continueWith, which is script code that will execute once the handle is completed.\n\nHandles can be used with waitUntil, continueWith, terminate, scriptDone, name."},{"heading":"Creating a Promise","level":4,"markdown":"Every handle returned by spawn or execVM is a promise that gets resolved once the script exits.\n\nIt's also possible to create a \"Empty Handle\" which does not hold any scheduled script, and can also be used in unscheduled code.\n\nA \"Empty Handle\" needs to be \"completed\" by calling terminate on it.\n\n```sqf\nprivate _emptyHandle = spawn \"HandleName\"; // does not contain an actual script, it's only a holder for name and potentially a value\nprivate _normalHandle = 0 spawn { scriptName \"HandleName\"; }; // contains an actual scheduled script that will execute and return a value at the end\n```"},{"heading":"Using Promises","level":4,"markdown":"Promises can be used to simplify asynchronous operations.\nFor example, when calling a function that takes some time to complete, and then wanting to execute code after it has completed.\n\nTo show it on an example, let's say we have a function that paradrops a vehicle.\nAnd we want to wait for the vehicle to touch the ground and then spawn a smoke grenade on it.\n\nPreviously, that could be solved like so:\n\n```sqf\nfnc_StartParadrop = {\n    params [\"_object\"];\n\n    private _parachute = createVehicle [\"B_Parachute_02_F\", [0, 0, 0], [], 0, \"CAN_COLLIDE\"];\n\n    // Put the parachute into the right position (setPos doesn't work on them)\n    _parachute attachTo [_object, [0, 0, 0]];\n    detach _parachute;\n\n    _object attachTo [_parachute, [0, 0, 0]];\n    // Now the object is hanging on parachute and gliding down\n    // But we want to wait for it to arrive at the bottom, the parachute will be deleted once it lands, so we can use that\n\n    // The parachute won't know about us, and we cannot get a value out of the eventhandler, so we will give the parachute a place to store the result\n    // Note this will not work across savegame save/load because the \"result\" reference will be lost.\n\n    private _result = [];\n    _parachute setVariable [\"result\", _result];\n    _parachute addEventHandler [\"Deleted\", {\n        params [\"_entity\"];\n        (_entity getVariable \"result\") set [0, getPos _entity]; // Store the landing position of the parachute\n    }];\n\n    // _result will be set once the parachute landed. How we wait on the result now depends on whether this is a scheduled or unscheduled function\n    // In unscheduled code we cannot wait, we would need to get some callback function in our arguments to notify our caller that it can continue.\n    // For simplicity we show the scheduled variant here, the unscheduled would be more complex\n\n    // Keep looping, until someone (Hopefully the Deleted eventhandler) wrote a result into our array\n    waitUntil { _result isNotEqualTo []; };\n\n    _result select 0; // We return the result, our user must have call'ed us to wait for us to finish and get the result\n};\n\n// The fnc_StartParadrop will wait, so we have to spawn a new script to not hold up everything else\n0 spawn {\n    private _dropPos = ParadropVehicle call fnc_StartParadrop; // This will wait until the vehicle has landed\n    \"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n};\n```\n\nAlso note how the waitUntil always runs.\nEven if we as the caller do not care for the paradrop to finish, we wouldn't easily have the option to tell the script that, without adding another parameter to it.\nAlso note that this function is not usable in unscheduled scripts, because it uses waitUntil to wait for the landing.\n\nWith promises, it can be solved like this:\n\n```sqf\nfnc_StartParadrop = {\n    params [\"_object\"];\n\n    private _parachute = createVehicle [\"B_Parachute_02_F\", [0, 0, 0], [], 0, \"CAN_COLLIDE\"];\n\n    // Put the parachute into the right position (setPos doesn't work on them)\n    _parachute attachTo [_object, [0, 0, 0]];\n    detach _parachute;\n\n    _object attachTo [_parachute, [0, 0, 0]];\n    // Now the object is hanging on parachute and gliding down\n    // But we want to wait for it to arrive at the bottom, the parachute will be deleted once it lands, so we can use that\n\n    // The parachute won't know about us, and we cannot get a value out of the eventhandler, so we will give the parachute a place to store the result\n    private _paradropHandle = spawn \"Paradrop\"; // We create new Promise, that we will use to return the result\n\n    _parachute setVariable [\"handle\", _paradropHandle];\n    _parachute addEventHandler [\"Deleted\", {\n        params [\"_entity\"];\n        (_entity getVariable \"handle\") terminate (getPos _entity); // Complete the promise and pass the landing position as result\n    }];\n    _paradropHandle // We return the promise, the caller can decide if they want to use it or not\n};\n\n// Note we do not need to spawn another script because we are not waiting for anything, this can fully be handled in unscheduled code now\n\n_paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\n_paradropHandle continueWith { \"SmokeshellGreen\" createVehicle _this; }; // We use a continuation, it will be triggered once terminate is called on the handle (Inside the \"Deleted\" eventhandler)\n```\n\nNote that the paradrop function can now also be used in scheduled scripts like so:\n\n```sqf\nprivate _paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\nprivate _dropPos = waitUntil _paradropHandle; // Wait for the promise to be completed and get its result\n\"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n```\n\nOr like so:\n\n```sqf\nprivate _paradropHandle = ParadropVehicle call fnc_StartParadrop; // This will start the paradrop, and return a handle that we can use to wait for it to land\nprivate _dropPos = waitUntil [_paradropHandle, 60]; // Wait for the promise to be completed, but at most for 60 seconds, if it still has not landed yet, we will report it to the player\n\nif (isNil \"_dropPos\") then {\n    // The promise yielded no result. Either it was terminated without a result, or our timeout has elapsed\n    hint \"The Paradrop has failed!\";\n} else {\n    \"SmokeshellGreen\" createVehicle _dropPos; // Spawn a smoke at the landing position\n};\n```"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Side","title":"Side","type":"topic","url":"https://community.bistudio.com/wiki/Side","revid":342100,"updated":"2023-07-09T12:26:36Z","aliases":[],"markdown":"| Id | Side | Description | Commands | Can<br>createCenter | String version | Present in |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|---|---|---|---|\n| Operation Flashpoint v1.00 | Operation Flashpoint: Resistance v1.75 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Arma 3 v0.50 | Take On Helicopters v1.00 |  |  |  |  |  |  |\n| 1 | BLUFOR | The BLUFOR (*Blue Forces*) side. | west, blufor | ✓ | \"WEST\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 0 | OPFOR | The [OPFOR](https://en.wikipedia.org/wiki/Opposing_force) (*Opposing Forces*) side. | east, opfor | ✓ | \"EAST\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 2 | Independent | The *Independent Forces*/*Guerilla* side. | resistance, independent | ✓ | \"GUER\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 3 | Civilian | The civilian side. | civilian | ✓ | \"CIV\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 9 | Ambient Life | Animals like fish, rabbits and snakes. | sideAmbientLife | ✗ | \"AMBIENT LIFE\" | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |\n| 8 | Empty | Empty buildings placed in the Eden Editor. | sideEmpty | ✗ | \"EMPTY\" | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |\n| 6 | Friendly | Friendly sides. | sideFriendly | ✗ | \"FRIENDLY\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 5 | Enemy | Enemy side. | sideEnemy | ✗ | \"ENEMY\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 4 | Unknown | Used when the side of a unit is unknown, e.g for spotted targets with insufficient information. | sideUnknown | ✗ | \"UNKNOWN\" | ✗ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ |\n| 7 | Logic | Side of Game Logics and Modules. | sideLogic | ✓ | \"LOGIC\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n\n### See Also\n\n- Side Relations\n- Factions\n- Command Group: Sides","sections":[{"heading":null,"level":1,"markdown":"| Id | Side | Description | Commands | Can<br>createCenter | String version | Present in |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|---|---|---|---|\n| Operation Flashpoint v1.00 | Operation Flashpoint: Resistance v1.75 | Armed Assault v1.00 | Arma 2 v1.00 | Arma 2: Operation Arrowhead v1.50 | Arma 3 v0.50 | Take On Helicopters v1.00 |  |  |  |  |  |  |\n| 1 | BLUFOR | The BLUFOR (*Blue Forces*) side. | west, blufor | ✓ | \"WEST\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 0 | OPFOR | The [OPFOR](https://en.wikipedia.org/wiki/Opposing_force) (*Opposing Forces*) side. | east, opfor | ✓ | \"EAST\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 2 | Independent | The *Independent Forces*/*Guerilla* side. | resistance, independent | ✓ | \"GUER\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 3 | Civilian | The civilian side. | civilian | ✓ | \"CIV\" | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 9 | Ambient Life | Animals like fish, rabbits and snakes. | sideAmbientLife | ✗ | \"AMBIENT LIFE\" | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |\n| 8 | Empty | Empty buildings placed in the Eden Editor. | sideEmpty | ✗ | \"EMPTY\" | ✗ | ✗ | ✗ | ✗ | ✗ | ✓ | ✗ |\n| 6 | Friendly | Friendly sides. | sideFriendly | ✗ | \"FRIENDLY\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 5 | Enemy | Enemy side. | sideEnemy | ✗ | \"ENEMY\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| 4 | Unknown | Used when the side of a unit is unknown, e.g for spotted targets with insufficient information. | sideUnknown | ✗ | \"UNKNOWN\" | ✗ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ |\n| 7 | Logic | Side of Game Logics and Modules. | sideLogic | ✓ | \"LOGIC\" | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |"},{"heading":"See Also","level":3,"markdown":"- Side Relations\n- Factions\n- Command Group: Sides"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"SQF Syntax","title":"SQF Syntax","type":"topic","url":"https://community.bistudio.com/wiki/SQF_Syntax","revid":363899,"updated":"2024-04-24T15:51:27Z","aliases":["*/","/*","/**/","//","SQF","SQF syntax","sqf"],"markdown":"**SQF** stands for **S**tatus **Q**uo **F**unction - a successor of **S**tatus **Q**uo **S**cript, which is deprecated since Armed Assault but could still be used in Arma 3.\nSQF was first introduced in Operation Flashpoint: Resistance together with the call operator in update 1.85.\n\n- \"Status Quo\" was a code name for [Operation Flashpoint](https://en.wikipedia.org/wiki/Operation_Flashpoint)\n- \"Combined Arms\" was a code name for [Arma](https://en.wikipedia.org/wiki/ARMA_(series))\n- \"Futura\" was a code name for [Arma 3](https://en.wikipedia.org/wiki/ARMA_3).\n\nThe SQF Language is fairly simple in how it is built.\nIn fact: there are barely any actual language structures at all.\n\nThe functionality is provided via so called *operators* (or more commonly known scripting commands).\nThose operators are one of the following types: Nular [sic], Unary, or Binary.\n\n### Terminating an expression\n\nAn SQF expression has to be terminated via either `;` (preferred by convention!) or `,`.\n\n```sqf\n_num = 10;\n_num = _num + 20; systemChat str _num;\n```\n\nIn the above example, there are three expressions:\n1. `_num = 10`\n1. `_num = _num + 20`\n1. `systemChat str _num`\nAll are separated by `;` and not the line return - they could all be inlined and it would not impact the code.\n\n### Brackets\n\n- `()` - Round brackets are used to override the default Order of Precedence or improve legibility.\n- `[]` - Square brackets define Arrays.\n- `{}` - Curly brackets enclose instances of the Code Data Type. They are also used in Control Structures.\n\n### Whitespaces\n\nWhitespace consists of tabs and/or space characters.\n\n For the\n  purposes of the\n    engine\n      The 'line' begins at the first non whitespace character.\n\nSimilarly, trailing whitespace at the end of a line or statement is also ignored.\n\n### Blank Lines\n\nBlank lines are lines containing nothing but whitespace and are therefore ignored by the engine.\n\n### Comments\n\nA comment is additional text that gets ignored when a script is parsed.\nThey serve as future reference and are often used to explain a specific part of the code.\n\nIn SQF, there are two kind of comments:\n\n```sqf\n// in-line comment that ends on new line\n\n/* block comment that can span above multiple lines\nand ends on the following character combination: */\n```\n\nA comment can occur anywhere but inside a string.\nFor example, the following would be valid:\n\n```sqf\n1 + /* some random comment in an expression */ 1\n```\n\nIt should be mentioned that there is a comment unary operator that should not be used as it will actually be executed (thus taking time to execute) but does nothing besides consuming a string.\nThere is no benefit in using it and the reason it exists is solely for backward compatibility.\nAnother way to make a *comment* that way, is to just place a string: `/* some code */ \"I can be considered as a comment but should not be used\"; /* some other code */`\n\n*Comments are removed during the preprocessing phase.* This is important to know as that prevents usage in e.g a string that gets compiled using the compile unary operator or when only using loadFile.\n\n### Nular Operators\n\nA nular [sic] operator is more or less a computed variable. Each time accessed, it will return the current state of something.\nIt is tempting to think of a nular [sic] operator as nothing more but a magic global variable, but it is important to differentiate!\n\nConsider following example in a mission with e.g. 5 units:\n\n```sqf\n// put the result of allUnits into a Variable\n_unitsArray = allUnits;\n\n// display the current Array size using systemChat\nsystemChat str count _unitsArray;\n\n// create a new unit in the player group\ngroup player createUnit [\"B_RangeMaster_F\", getPosATL player, [], 0, \"NONE\"];\n\n// output the Array size again\nsystemChat str count _unitsArray;\n\n// output the size of allUnits\nsystemChat str count allUnits;\n```\n\nNow, what would the output of this look like?\n System: 5\n System: 5\n System: 6\n\nAs you can see, `_unitsArray` was not automatically updated as it would have been if it was not generated each time. If allUnits was just a global variable with a reference to some internal managed array, our private variable should have had reflected the change as value types are passed by reference.\nThe reason for this is because allUnits and other nular [sic] operators just return the current state of something and do not return a reference to eg. an array containing all units.\nIt is generated each time, which is why some of theese operators are more expensive to run then *just* using a variable.\n\n### Unary Operators\n\nThe unary operators are operators that expect an argument on their right side (`unary <argument>`). They always will take the first argument that occurs.\n\nA common mistake would be the following:\n\n```sqf\n// create some Array containing three arrays\n_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];\n\n// wrongly use the select operator to get the count of the third array\ncount _arr select 2; // error\n```\n\nNow, what went wrong?\n\nLet's put some brackets in the right places to make the mistake understandable:\n\n```sqf\n(count _arr) select 2; // error\n```\n\nDue to the nature of unary operators, count instantly consumes our variable *_arr* and returns the number *3*.\nThe *3* then is passed to select which does not knows what to do with a number as left argument and thus errors out.\n\nTo do it correctly, one would have to put the `_arr select 2` in brackets.\nThe correct code thus would be:\n\n```sqf\n// create an array containing three Arrays\n_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];\n\n// use brackets to correctly get count of the third Array\ncount (_arr select 2); // good :) will evaluate to 2\n```\n\n### Binary Operators\n\nBinary operators expect two arguments (`<1st argument> binary <2nd argument>`) and are executed according to their #precedence. If their precedence is equal, they are executed left to right.\n\nAs example, we will look into the following expression:\n\n```sqf\n// create a nested Array with 5 levels\n_arr = [[[[[1]]]]];\n\n// receive the nested number with some random math expressions\n_arr select 0 select 1 - 1 select 15 / 3 - 5 select 0 select 10 * 10 + 4 * 0 - 100 // evaluates to 1\n```\n\nNow, let us analyze why this is happening for the first few expressions:\n1. _arr is loaded\n1. 0 is loaded\n1. select is executed with the result of 1. & 2.\n1. 1 is loaded\n1. 1 is loaded\n1. - is executed with the result of 4. & 5.\n1. select is executed with the result of 3. & 6.\n1. ...\n\nIf we now would put brackets at the correct spots, the expression will get clearer:\n\n```sqf\n((((_arr select 0) select (1 - 1)) select ((15 / 3) - 5)) select 0) select (((10 * 10) + (4 * 0)) - 100)\n```\n\nAs you can see the `*` and `/` are executed first which matches their precedence.\nAfterward, the `+` and `-` operators will get executed followed by our select operator, which are executed from the left to the right.","sections":[{"heading":null,"level":1,"markdown":"**SQF** stands for **S**tatus **Q**uo **F**unction - a successor of **S**tatus **Q**uo **S**cript, which is deprecated since Armed Assault but could still be used in Arma 3.\nSQF was first introduced in Operation Flashpoint: Resistance together with the call operator in update 1.85.\n\n- \"Status Quo\" was a code name for [Operation Flashpoint](https://en.wikipedia.org/wiki/Operation_Flashpoint)\n- \"Combined Arms\" was a code name for [Arma](https://en.wikipedia.org/wiki/ARMA_(series))\n- \"Futura\" was a code name for [Arma 3](https://en.wikipedia.org/wiki/ARMA_3).\n\nThe SQF Language is fairly simple in how it is built.\nIn fact: there are barely any actual language structures at all.\n\nThe functionality is provided via so called *operators* (or more commonly known scripting commands).\nThose operators are one of the following types: Nular [sic], Unary, or Binary."},{"heading":"Terminating an expression","level":3,"markdown":"An SQF expression has to be terminated via either `;` (preferred by convention!) or `,`.\n\n```sqf\n_num = 10;\n_num = _num + 20; systemChat str _num;\n```\n\nIn the above example, there are three expressions:\n1. `_num = 10`\n1. `_num = _num + 20`\n1. `systemChat str _num`\nAll are separated by `;` and not the line return - they could all be inlined and it would not impact the code."},{"heading":"Brackets","level":3,"markdown":"- `()` - Round brackets are used to override the default Order of Precedence or improve legibility.\n- `[]` - Square brackets define Arrays.\n- `{}` - Curly brackets enclose instances of the Code Data Type. They are also used in Control Structures."},{"heading":"Whitespaces","level":3,"markdown":"Whitespace consists of tabs and/or space characters.\n\n For the\n  purposes of the\n    engine\n      The 'line' begins at the first non whitespace character.\n\nSimilarly, trailing whitespace at the end of a line or statement is also ignored."},{"heading":"Blank Lines","level":3,"markdown":"Blank lines are lines containing nothing but whitespace and are therefore ignored by the engine."},{"heading":"Comments","level":3,"markdown":"A comment is additional text that gets ignored when a script is parsed.\nThey serve as future reference and are often used to explain a specific part of the code.\n\nIn SQF, there are two kind of comments:\n\n```sqf\n// in-line comment that ends on new line\n\n/* block comment that can span above multiple lines\nand ends on the following character combination: */\n```\n\nA comment can occur anywhere but inside a string.\nFor example, the following would be valid:\n\n```sqf\n1 + /* some random comment in an expression */ 1\n```\n\nIt should be mentioned that there is a comment unary operator that should not be used as it will actually be executed (thus taking time to execute) but does nothing besides consuming a string.\nThere is no benefit in using it and the reason it exists is solely for backward compatibility.\nAnother way to make a *comment* that way, is to just place a string: `/* some code */ \"I can be considered as a comment but should not be used\"; /* some other code */`\n\n*Comments are removed during the preprocessing phase.* This is important to know as that prevents usage in e.g a string that gets compiled using the compile unary operator or when only using loadFile."},{"heading":"Nular Operators","level":3,"markdown":"A nular [sic] operator is more or less a computed variable. Each time accessed, it will return the current state of something.\nIt is tempting to think of a nular [sic] operator as nothing more but a magic global variable, but it is important to differentiate!\n\nConsider following example in a mission with e.g. 5 units:\n\n```sqf\n// put the result of allUnits into a Variable\n_unitsArray = allUnits;\n\n// display the current Array size using systemChat\nsystemChat str count _unitsArray;\n\n// create a new unit in the player group\ngroup player createUnit [\"B_RangeMaster_F\", getPosATL player, [], 0, \"NONE\"];\n\n// output the Array size again\nsystemChat str count _unitsArray;\n\n// output the size of allUnits\nsystemChat str count allUnits;\n```\n\nNow, what would the output of this look like?\n System: 5\n System: 5\n System: 6\n\nAs you can see, `_unitsArray` was not automatically updated as it would have been if it was not generated each time. If allUnits was just a global variable with a reference to some internal managed array, our private variable should have had reflected the change as value types are passed by reference.\nThe reason for this is because allUnits and other nular [sic] operators just return the current state of something and do not return a reference to eg. an array containing all units.\nIt is generated each time, which is why some of theese operators are more expensive to run then *just* using a variable."},{"heading":"Unary Operators","level":3,"markdown":"The unary operators are operators that expect an argument on their right side (`unary <argument>`). They always will take the first argument that occurs.\n\nA common mistake would be the following:\n\n```sqf\n// create some Array containing three arrays\n_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];\n\n// wrongly use the select operator to get the count of the third array\ncount _arr select 2; // error\n```\n\nNow, what went wrong?\n\nLet's put some brackets in the right places to make the mistake understandable:\n\n```sqf\n(count _arr) select 2; // error\n```\n\nDue to the nature of unary operators, count instantly consumes our variable *_arr* and returns the number *3*.\nThe *3* then is passed to select which does not knows what to do with a number as left argument and thus errors out.\n\nTo do it correctly, one would have to put the `_arr select 2` in brackets.\nThe correct code thus would be:\n\n```sqf\n// create an array containing three Arrays\n_arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4], [1, 2]];\n\n// use brackets to correctly get count of the third Array\ncount (_arr select 2); // good :) will evaluate to 2\n```"},{"heading":"Binary Operators","level":3,"markdown":"Binary operators expect two arguments (`<1st argument> binary <2nd argument>`) and are executed according to their #precedence. If their precedence is equal, they are executed left to right.\n\nAs example, we will look into the following expression:\n\n```sqf\n// create a nested Array with 5 levels\n_arr = [[[[[1]]]]];\n\n// receive the nested number with some random math expressions\n_arr select 0 select 1 - 1 select 15 / 3 - 5 select 0 select 10 * 10 + 4 * 0 - 100 // evaluates to 1\n```\n\nNow, let us analyze why this is happening for the first few expressions:\n1. _arr is loaded\n1. 0 is loaded\n1. select is executed with the result of 1. & 2.\n1. 1 is loaded\n1. 1 is loaded\n1. - is executed with the result of 4. & 5.\n1. select is executed with the result of 3. & 6.\n1. ...\n\nIf we now would put brackets at the correct spots, the expression will get clearer:\n\n```sqf\n((((_arr select 0) select (1 - 1)) select ((15 / 3) - 5)) select 0) select (((10 * 10) + (4 * 0)) - 100)\n```\n\nAs you can see the `*` and `/` are executed first which matches their precedence.\nAfterward, the `+` and `-` operators will get executed followed by our select operator, which are executed from the left to the right."}],"categories":["Syntax"],"groups":["Scripting"]},{"name":"String","title":"String","type":"topic","url":"https://community.bistudio.com/wiki/String","revid":373361,"updated":"2025-04-28T08:59:37Z","aliases":["Strings"],"markdown":"A **string** is a variable type that contains text. Possible length and characters depend on the game and its version.\n\n> [!NOTE]\n> The encoding should be mostly transparent. The input files can be encoded both in UTF-16 or UTF-8, the toString and toArray functions always convert from/to UTF-16 representation.\n\n### Properties\n\n|  | OFP | ArmA | Arma 2 | Arma 2:OA | Take On Helicopters | Arma 3 (before v1.56) | Arma 3 (since v1.56) |\n|---|---|---|---|---|---|---|---|\n| Max length | 2056 | No set limit | 9,999,999 to 10,000,000<br>(same as Array length) |  |  |  |  |\n| Encoding | [ASCII](https://en.wikipedia.org/wiki/ASCII) | [Unicode](https://en.wikipedia.org/wiki/Unicode) |  |  |  |  |  |\n| [Code page](https://en.wikipedia.org/wiki/Code_page) | product language defined | [UTF-8](https://en.wikipedia.org/wiki/UTF-8) |  |  |  |  |  |\n| \"text\" | ✓ |  |  |  |  |  |  |\n| 'text' | ✗ | ✓ |  |  |  |  |  |\n| {text} | ✓ | ✗ |  |  |  |  |  |\n\n### Commands and Functions\n\n- String Scripting Commands\n- String Functions\n\n### Single quote limitation\n\nStrings can be written with both double quotes (\"text\") and single quotes ('text'). While they are identical, there are slightly differences in how they are treated:\n- Single quote strings are parsed by the preprocessor and may cause undesired results.\n- Single quote strings do not seem to support tabs:\n\n```sqf\n_string = \"    \n    \";\ncopyToClipboard _string;\ndiag_log format [\"%1 %2 %3 x%4x\", toArray _string, toArray copyFromClipboard, toArray (_string select [0]), _string];\n\n/*\n    return is good: \"[9,10,9] [9,10,9] [9,10,9] x    \n    x\"\n*/\n```\n\n```sqf\n_string = '    \n    ';\ncopyToClipboard _string;\ndiag_log format [\"%1 %2 %3 x%4x\", toArray _string, toArray copyFromClipboard, toArray (_string select [0]), _string];\n\n/*\n    return: \"[9,10] [9,10] [9,10] x    \nx\" - second tab vanished\n*/\n```\n\nExample courtesy of [Rydygier](http://forums.bistudio.com/member.php?81568-Rydygier)\n\n### Examples\n\n#### Quotes in Quotes\n\n```sqf\nprivate _string = \"my string \"\"with\"\" quotes\";\nprivate _string = 'my string \"with\" quotes';\nprivate _string = 'my string with quotes';\n```\n\n#### String Formats\n\n```sqf\n// Operation Flashpoint\n_string = \"Hello there\" // works\n_string = 'Hello there' // does NOT work\n_string = {Hello there} // works\n```\n\n```sqf\n// since Armed Assault\n_string = \"Hello there\" // works\n_string = 'Hello there' // works\n_string = {Hello there} // does NOT work\n```\n\n#### Operators\n\n```sqf\nprivate _finalString = \"Hello\" + \" \" + \"there\"; // outputs \"Hello there\" - the + sign concatenates strings\n```\n\nThe only basic operator to be used on strings is \"plus\". You can use \"plus\" to concatenate two strings.\n\n#### Conversion\n\n```sqf\nprivate _value = 42; // this is a Number\nhint _value; // error - hint takes a String, not a Number\nhint format [\"%1\", _value]; // ok\nhint str _value; // ok - since Armed Assault\n```","sections":[{"heading":null,"level":1,"markdown":"A **string** is a variable type that contains text. Possible length and characters depend on the game and its version.\n\n> [!NOTE]\n> The encoding should be mostly transparent. The input files can be encoded both in UTF-16 or UTF-8, the toString and toArray functions always convert from/to UTF-16 representation."},{"heading":"Properties","level":3,"markdown":"|  | OFP | ArmA | Arma 2 | Arma 2:OA | Take On Helicopters | Arma 3 (before v1.56) | Arma 3 (since v1.56) |\n|---|---|---|---|---|---|---|---|\n| Max length | 2056 | No set limit | 9,999,999 to 10,000,000<br>(same as Array length) |  |  |  |  |\n| Encoding | [ASCII](https://en.wikipedia.org/wiki/ASCII) | [Unicode](https://en.wikipedia.org/wiki/Unicode) |  |  |  |  |  |\n| [Code page](https://en.wikipedia.org/wiki/Code_page) | product language defined | [UTF-8](https://en.wikipedia.org/wiki/UTF-8) |  |  |  |  |  |\n| \"text\" | ✓ |  |  |  |  |  |  |\n| 'text' | ✗ | ✓ |  |  |  |  |  |\n| {text} | ✓ | ✗ |  |  |  |  |  |"},{"heading":"Commands and Functions","level":3,"markdown":"- String Scripting Commands\n- String Functions"},{"heading":"Single quote limitation","level":3,"markdown":"Strings can be written with both double quotes (\"text\") and single quotes ('text'). While they are identical, there are slightly differences in how they are treated:\n- Single quote strings are parsed by the preprocessor and may cause undesired results.\n- Single quote strings do not seem to support tabs:\n\n```sqf\n_string = \"    \n    \";\ncopyToClipboard _string;\ndiag_log format [\"%1 %2 %3 x%4x\", toArray _string, toArray copyFromClipboard, toArray (_string select [0]), _string];\n\n/*\n    return is good: \"[9,10,9] [9,10,9] [9,10,9] x    \n    x\"\n*/\n```\n\n```sqf\n_string = '    \n    ';\ncopyToClipboard _string;\ndiag_log format [\"%1 %2 %3 x%4x\", toArray _string, toArray copyFromClipboard, toArray (_string select [0]), _string];\n\n/*\n    return: \"[9,10] [9,10] [9,10] x    \nx\" - second tab vanished\n*/\n```\n\nExample courtesy of [Rydygier](http://forums.bistudio.com/member.php?81568-Rydygier)"},{"heading":"Examples","level":3,"markdown":""},{"heading":"Quotes in Quotes","level":4,"markdown":"```sqf\nprivate _string = \"my string \"\"with\"\" quotes\";\nprivate _string = 'my string \"with\" quotes';\nprivate _string = 'my string with quotes';\n```"},{"heading":"String Formats","level":4,"markdown":"```sqf\n// Operation Flashpoint\n_string = \"Hello there\" // works\n_string = 'Hello there' // does NOT work\n_string = {Hello there} // works\n```\n\n```sqf\n// since Armed Assault\n_string = \"Hello there\" // works\n_string = 'Hello there' // works\n_string = {Hello there} // does NOT work\n```"},{"heading":"Operators","level":4,"markdown":"```sqf\nprivate _finalString = \"Hello\" + \" \" + \"there\"; // outputs \"Hello there\" - the + sign concatenates strings\n```\n\nThe only basic operator to be used on strings is \"plus\". You can use \"plus\" to concatenate two strings."},{"heading":"Conversion","level":4,"markdown":"```sqf\nprivate _value = 42; // this is a Number\nhint _value; // error - hint takes a String, not a Number\nhint format [\"%1\", _value]; // ok\nhint str _value; // ok - since Armed Assault\n```"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Structured Text","title":"Structured Text","type":"topic","url":"https://community.bistudio.com/wiki/Structured_Text","revid":364507,"updated":"2024-05-16T20:42:02Z","aliases":["Text"],"markdown":"Structured Text is a Data Type that has been introduced with Armed Assault. It is a **rich text**, which is able to include images and formatting. It can be created using XML-like syntax, as seen below. However, using XML-like syntax alone is not going to turn a normal string into structured text, it should be converted to TEXT first.\n\n> [!IMPORTANT]\n> This type is not meant to be used with remote execution. Executing `[parseText \"test\"] remoteExec [\"hint\"];` will result in the following rpt message:\n>\n> `Performance warning: SimpleSerialization::Write 'params' is using type of ',TEXT' which is not optimized by simple serialization, falling back to generic serialization, use generic type or ask for optimizations for these types`\n>\n> Parse the text on the receiving client instead.\n\n### Commands\n\n- See Command Group: Structured Text for all related commands.\n\n### Markups\n\n#### Syntax\n\nAll attribute values should be encapsulated in double `\"...\"` or single `'...'` quotes. Both of the following are correct:\n\n```html\n<t size=\"2.0\">Large text</t>\n<t size='2.0'>Large text</t>\n```\n\n> [!WARNING]\n> The following will log an *.rpt* error `Unknown attribute .0` and only number 2 would be taken into account:\n>\n> ```html\n> <t size=2.0>Large text</t>\n> ```\n\n#### Text\n\nTexts could be created with the following markup:\n\n```html\n<t>Hello World!</t>\n```\n\nOr could also be inserted via the composeText / formatText and text commands.\n\n##### Special characters\n\nTo insert special characters, such as `<`, `>`, etc. you can use the [HTML representation](https://dev.w3.org/html5/html-author/charref) of that character, e.g.:\n\n| Character | HTML |\n|---|---|\n| < | `<` |\n| > | `>` |\n| non-breaking space |  |\n| ... | ... |\n\n> [!IMPORTANT]\n> Using a special character directly will result in it being displayed as \"?\" or, in the case of writing \"<TEXT>\", will result in an error in the RPT: `Wrong text element 'TEXT'`\n\n#### Line break\n\nLine breaks could be created with either of the following markups:\n\n```html\n<br/>\n<br />\n<br></br>\n```\n\nOr could also be inserted via the composeText / formatText and lineBreak commands.\n\n#### Image\n\nImages could be created with either of the following markups:\n\n```html\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa'/>\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa' />\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa'></img>\n```\n\nOr could also be inserted via the composeText / formatText and image commands.\n\n#### Hyperlink (Arma 3)\n\nClickable links, similar to HTML hyperlinks, could be created with the following markup:\n\n```html\n<a href='http://arma3.com'>Arma 3</a>\n```\n\nBy default the links are not underlined or have a different color to stand out. These attributes should be added separately.\n\nNote: *&* should be escaped by *&amp;*.\n\n```html\n<a href='https://arma3.com/?foo&bar'>Example URL A</a> <!-- will not work -->\n<a href='https://arma3.com/?foo&bar'>Example URL B</a> <!-- will work -->\n```\n\n### Attributes\n\nThe following inline attributes are supported:\n- `size`\n- `color`\n- `font`\n- `align`\n- `valign`\n- `underline`\n- `shadow`\n- `shadowColor`\n- `shadowOffset`\n- `colorLink`\n- `href`\n- `image`\n\n#### Size\n\nThe structured text `size` attribute is a multiplier for the value of control config property `size`. Default is 1, meaning that the height of letters will be equal to the value set in config. Setting this to 2 will make letters 2 times the size, 0.5 will make them half the size, etc. If the control is defined as follows:\n\n```cpp\nclass MyStructuredText : RscStructuredText \n{\n    ...\n    text = \"Hello!\";\n    size = 0.04;\n    ...\n};\n```\n\nThen the structured text:\n\n```sqf\n_control ctrlSetStructuredText parseText \"<t size='2'>Hello!</t>\";\n```\n\nWill result in a total text size of 0.04 * 2 = 0.08. Unfortunately, there is no script command to set or get the value of config `size` property dynamically.\n\n#### Color\n\nThe `color` attribute is similar to HTML hex color and could either have format [#RRGGBB](https://en.wikipedia.org/wiki/RGB) or [#AARRGGBB](https://en.wikipedia.org/wiki/ARGB).\n\n```html\n<t color='#ff0000'>Red text</t>\n<t color='#99ffffff'>Semi-transparent white text</t>\n```\n\n#### Font\n\nThe value for the `font` attribute could be found in `CfgFontFamilies` config. Some of the Arma 3 fonts:\n- `EtelkaMonospacePro`\n- `EtelkaMonospaceProBold`\n- `EtelkaNarrowMediumPro`\n- `LCD14`\n- `LucidaConsoleB`\n- `PuristaBold`\n- `PuristaLight`\n- `PuristaMedium`\n- `PuristaSemibold`\n- `RobotoCondensed`\n- `RobotoCondensedBold`\n- `RobotoCondensedLight`\n- `TahomaB`\n\n```html\n<t font='PuristaBold'>Bold Text</t>\n<t font='LCD14'>Wicked looking text</t>\n```\n\n#### Horizontal Alignment\n\nThe `align` attribute controls horizontal text alignment and could be one of the following:\n- `left`\n- `center`\n- `right`\n\n```html\n<t align='right'>Text displayed to the right</t>\n```\n\n#### Vertical Alignment\n\nThe `valign` attribute controls vertical text alignment and could be one of the following:\n- `top`\n- `middle`\n- `bottom`\n\n```html\n<t valign='bottom'>Text displayed at the bottom</t>\n```\n\n#### Underline\n\nThe `underline` attribute underlines each individual word in text. The normal spaces are not underlined.\n\n```html\n<t underline='1'>Underlined Text</t>\n```\n\n> [!NOTE]\n> If you would like to have a continuous underline between words, use non-breaking spaces. This could be achieved in several ways:\n> - Insertion from keyboard: [Alt+255](https://en.wikipedia.org/wiki/Non-breaking_space#Keyboard_entry_methods)\n> - Scripted method:\n>\n> ```sqf\n> hint parseText format [\"<t underline='1'>%1</t>\", \"Underlined Text\" splitString \" \" joinString toString [160]]\n> ```\n>\n> - Using HTML code:\n>\n> ```sqf\n> hint parseText \"<t underline='1'>Underlined&#160;Text</t>\";\n> ```\n\n#### Shadow\n\nThe `shadow` attribute controls the appearance of shadow/outline around text and could be one of the following:\n- `0` - normal text\n- `1` - classic shadow (text ghosting below and to the right)\n- `2` - outline (slight, always black, outline around characters)\n\n```html\n<t shadow='0'>Text with no shadow</t>\n<t shadow='1'>Text with default black shadow</t>\n<t shadow='2'>Text with default black outline</t>\n```\n\n#### Shadow Color\n\nThe `shadowColor` attribute controls the color of the shadow (not the outline, which is always black for some reason)\n\n```html\n<t shadow='1' shadowColor='#ff0000'>Text with red shadow</t>\n```\n\n#### Shadow Offset\n\nThe `shadowOffset` attribute controls how far is the shadow offset from the text source (has no effect on the outline)\n\n```html\n<t shadow='1' shadowColor='#ff0000' shadowOffset='0.5'>Text with red shadow, which is offset by half character size</t>\n```\n\n#### Link Color\n\nWill change the color of the text if the text is a link, otherwise the text color is unaffected.\n\n```html\n<t colorLink='#0000ff'><a href='http://www.arma3.com/'>Blue text</a></t>\n<a colorLink='#0000ff' href='http://www.arma3.com/'>Blue text too</a>\n<t colorLink='#0000ff'>Normal text color</t>\n```\n\n#### Hyperlink Reference\n\nThe `href` attribute is essential part of the `<a>` tag and should contain URL of the destination (See Hyperlink).\n\n#### Image Reference\n\nThe `image` attribute is essential part of the `<img>` tag and should contain filepath to the image (See Image).\n\n### SQF Code Examples\n\n`align` `valign` demo:\n\n```sqf\nhint parseText \"<t size='3'><t size='1' valign='top' align='right'>Top Right</t> <t size='1' valign='middle' align='center'>Middle Center</t> <t size='1' valign='bottom' align='left'>Bottom Left</t></t>\";\n```\n\n> [!NOTE]\n> Sometimes an extra space is required when outputting to hint. In the above example spaces between `<t>`s inside another `<t>` wrapper ensure that the hint will be 3 lines tall\n\nCreate clickable image:\n\n```sqf\n_ctrl = findDisplay 46 createDisplay \"RscDisplayEmpty\" ctrlCreate [\"RscStructuredText\", -1];\n_ctrl ctrlSetPosition [0,0,1,1];\n_ctrl ctrlCommit 0;\n_ctrl ctrlSetStructuredText parseText \"<a color='#00FF00' size='5' href='http://arma3.com'><img image='\\A3\\weapons_f\\ammoBoxes\\data\\ui\\map_AmmoBox_F_CA.paa' /></a>\";\n```\n\nThe use of composeText:\n\n```sqf\n_separator = parseText \"<br />------------------------<br />\";\n_image = \"\\a3\\Data_f\\Flags\\flag_Altis_co.paa\";\n_txt1 = text \"left\";\n_txt1 setAttributes [\"align\", \"left\"];\n_txt2 = text \"right\";\n_txt2 setAttributes [\"align\", \"right\"];\n_structuredText = composeText [image _image, lineBreak, lineBreak, text \"Heading Text\", _separator, _txt1, _txt2];\nhint _structuredText;\n```","sections":[{"heading":null,"level":1,"markdown":"Structured Text is a Data Type that has been introduced with Armed Assault. It is a **rich text**, which is able to include images and formatting. It can be created using XML-like syntax, as seen below. However, using XML-like syntax alone is not going to turn a normal string into structured text, it should be converted to TEXT first.\n\n> [!IMPORTANT]\n> This type is not meant to be used with remote execution. Executing `[parseText \"test\"] remoteExec [\"hint\"];` will result in the following rpt message:\n>\n> `Performance warning: SimpleSerialization::Write 'params' is using type of ',TEXT' which is not optimized by simple serialization, falling back to generic serialization, use generic type or ask for optimizations for these types`\n>\n> Parse the text on the receiving client instead."},{"heading":"Commands","level":3,"markdown":"- See Command Group: Structured Text for all related commands."},{"heading":"Markups","level":3,"markdown":""},{"heading":"Syntax","level":4,"markdown":"All attribute values should be encapsulated in double `\"...\"` or single `'...'` quotes. Both of the following are correct:\n\n```html\n<t size=\"2.0\">Large text</t>\n<t size='2.0'>Large text</t>\n```\n\n> [!WARNING]\n> The following will log an *.rpt* error `Unknown attribute .0` and only number 2 would be taken into account:\n>\n> ```html\n> <t size=2.0>Large text</t>\n> ```"},{"heading":"Text","level":4,"markdown":"Texts could be created with the following markup:\n\n```html\n<t>Hello World!</t>\n```\n\nOr could also be inserted via the composeText / formatText and text commands."},{"heading":"Special characters","level":5,"markdown":"To insert special characters, such as `<`, `>`, etc. you can use the [HTML representation](https://dev.w3.org/html5/html-author/charref) of that character, e.g.:\n\n| Character | HTML |\n|---|---|\n| < | `<` |\n| > | `>` |\n| non-breaking space |  |\n| ... | ... |\n\n> [!IMPORTANT]\n> Using a special character directly will result in it being displayed as \"?\" or, in the case of writing \"<TEXT>\", will result in an error in the RPT: `Wrong text element 'TEXT'`"},{"heading":"Line break","level":4,"markdown":"Line breaks could be created with either of the following markups:\n\n```html\n<br/>\n<br />\n<br></br>\n```\n\nOr could also be inserted via the composeText / formatText and lineBreak commands."},{"heading":"Image","level":4,"markdown":"Images could be created with either of the following markups:\n\n```html\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa'/>\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa' />\n<img image='\\a3\\Data_f\\Flags\\flag_Altis_co.paa'></img>\n```\n\nOr could also be inserted via the composeText / formatText and image commands."},{"heading":"Hyperlink (Arma 3)","level":4,"markdown":"Clickable links, similar to HTML hyperlinks, could be created with the following markup:\n\n```html\n<a href='http://arma3.com'>Arma 3</a>\n```\n\nBy default the links are not underlined or have a different color to stand out. These attributes should be added separately.\n\nNote: *&* should be escaped by *&amp;*.\n\n```html\n<a href='https://arma3.com/?foo&bar'>Example URL A</a> <!-- will not work -->\n<a href='https://arma3.com/?foo&bar'>Example URL B</a> <!-- will work -->\n```"},{"heading":"Attributes","level":3,"markdown":"The following inline attributes are supported:\n- `size`\n- `color`\n- `font`\n- `align`\n- `valign`\n- `underline`\n- `shadow`\n- `shadowColor`\n- `shadowOffset`\n- `colorLink`\n- `href`\n- `image`"},{"heading":"Size","level":4,"markdown":"The structured text `size` attribute is a multiplier for the value of control config property `size`. Default is 1, meaning that the height of letters will be equal to the value set in config. Setting this to 2 will make letters 2 times the size, 0.5 will make them half the size, etc. If the control is defined as follows:\n\n```cpp\nclass MyStructuredText : RscStructuredText \n{\n    ...\n    text = \"Hello!\";\n    size = 0.04;\n    ...\n};\n```\n\nThen the structured text:\n\n```sqf\n_control ctrlSetStructuredText parseText \"<t size='2'>Hello!</t>\";\n```\n\nWill result in a total text size of 0.04 * 2 = 0.08. Unfortunately, there is no script command to set or get the value of config `size` property dynamically."},{"heading":"Color","level":4,"markdown":"The `color` attribute is similar to HTML hex color and could either have format [#RRGGBB](https://en.wikipedia.org/wiki/RGB) or [#AARRGGBB](https://en.wikipedia.org/wiki/ARGB).\n\n```html\n<t color='#ff0000'>Red text</t>\n<t color='#99ffffff'>Semi-transparent white text</t>\n```"},{"heading":"Font","level":4,"markdown":"The value for the `font` attribute could be found in `CfgFontFamilies` config. Some of the Arma 3 fonts:\n- `EtelkaMonospacePro`\n- `EtelkaMonospaceProBold`\n- `EtelkaNarrowMediumPro`\n- `LCD14`\n- `LucidaConsoleB`\n- `PuristaBold`\n- `PuristaLight`\n- `PuristaMedium`\n- `PuristaSemibold`\n- `RobotoCondensed`\n- `RobotoCondensedBold`\n- `RobotoCondensedLight`\n- `TahomaB`\n\n```html\n<t font='PuristaBold'>Bold Text</t>\n<t font='LCD14'>Wicked looking text</t>\n```"},{"heading":"Horizontal Alignment","level":4,"markdown":"The `align` attribute controls horizontal text alignment and could be one of the following:\n- `left`\n- `center`\n- `right`\n\n```html\n<t align='right'>Text displayed to the right</t>\n```"},{"heading":"Vertical Alignment","level":4,"markdown":"The `valign` attribute controls vertical text alignment and could be one of the following:\n- `top`\n- `middle`\n- `bottom`\n\n```html\n<t valign='bottom'>Text displayed at the bottom</t>\n```"},{"heading":"Underline","level":4,"markdown":"The `underline` attribute underlines each individual word in text. The normal spaces are not underlined.\n\n```html\n<t underline='1'>Underlined Text</t>\n```\n\n> [!NOTE]\n> If you would like to have a continuous underline between words, use non-breaking spaces. This could be achieved in several ways:\n> - Insertion from keyboard: [Alt+255](https://en.wikipedia.org/wiki/Non-breaking_space#Keyboard_entry_methods)\n> - Scripted method:\n>\n> ```sqf\n> hint parseText format [\"<t underline='1'>%1</t>\", \"Underlined Text\" splitString \" \" joinString toString [160]]\n> ```\n>\n> - Using HTML code:\n>\n> ```sqf\n> hint parseText \"<t underline='1'>Underlined&#160;Text</t>\";\n> ```"},{"heading":"Shadow","level":4,"markdown":"The `shadow` attribute controls the appearance of shadow/outline around text and could be one of the following:\n- `0` - normal text\n- `1` - classic shadow (text ghosting below and to the right)\n- `2` - outline (slight, always black, outline around characters)\n\n```html\n<t shadow='0'>Text with no shadow</t>\n<t shadow='1'>Text with default black shadow</t>\n<t shadow='2'>Text with default black outline</t>\n```"},{"heading":"Shadow Color","level":4,"markdown":"The `shadowColor` attribute controls the color of the shadow (not the outline, which is always black for some reason)\n\n```html\n<t shadow='1' shadowColor='#ff0000'>Text with red shadow</t>\n```"},{"heading":"Shadow Offset","level":4,"markdown":"The `shadowOffset` attribute controls how far is the shadow offset from the text source (has no effect on the outline)\n\n```html\n<t shadow='1' shadowColor='#ff0000' shadowOffset='0.5'>Text with red shadow, which is offset by half character size</t>\n```"},{"heading":"Link Color","level":4,"markdown":"Will change the color of the text if the text is a link, otherwise the text color is unaffected.\n\n```html\n<t colorLink='#0000ff'><a href='http://www.arma3.com/'>Blue text</a></t>\n<a colorLink='#0000ff' href='http://www.arma3.com/'>Blue text too</a>\n<t colorLink='#0000ff'>Normal text color</t>\n```"},{"heading":"Hyperlink Reference","level":4,"markdown":"The `href` attribute is essential part of the `<a>` tag and should contain URL of the destination (See Hyperlink)."},{"heading":"Image Reference","level":4,"markdown":"The `image` attribute is essential part of the `<img>` tag and should contain filepath to the image (See Image)."},{"heading":"SQF Code Examples","level":3,"markdown":"`align` `valign` demo:\n\n```sqf\nhint parseText \"<t size='3'><t size='1' valign='top' align='right'>Top Right</t> <t size='1' valign='middle' align='center'>Middle Center</t> <t size='1' valign='bottom' align='left'>Bottom Left</t></t>\";\n```\n\n> [!NOTE]\n> Sometimes an extra space is required when outputting to hint. In the above example spaces between `<t>`s inside another `<t>` wrapper ensure that the hint will be 3 lines tall\n\nCreate clickable image:\n\n```sqf\n_ctrl = findDisplay 46 createDisplay \"RscDisplayEmpty\" ctrlCreate [\"RscStructuredText\", -1];\n_ctrl ctrlSetPosition [0,0,1,1];\n_ctrl ctrlCommit 0;\n_ctrl ctrlSetStructuredText parseText \"<a color='#00FF00' size='5' href='http://arma3.com'><img image='\\A3\\weapons_f\\ammoBoxes\\data\\ui\\map_AmmoBox_F_CA.paa' /></a>\";\n```\n\nThe use of composeText:\n\n```sqf\n_separator = parseText \"<br />------------------------<br />\";\n_image = \"\\a3\\Data_f\\Flags\\flag_Altis_co.paa\";\n_txt1 = text \"left\";\n_txt1 setAttributes [\"align\", \"left\"];\n_txt2 = text \"right\";\n_txt2 setAttributes [\"align\", \"right\"];\n_structuredText = composeText [image _image, lineBreak, lineBreak, text \"Heading Text\", _separator, _txt1, _txt2];\nhint _structuredText;\n```"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Switch Type","title":"Switch Type","type":"topic","url":"https://community.bistudio.com/wiki/Switch_Type","revid":259189,"updated":"2021-06-06T15:50:38Z","aliases":[],"markdown":"**Description:**\n\nA helper type used in switch constructs.\n\nIntroduced with Armed Assault, does not refer to Operation Flashpoint or Operation Flashpoint: Resistance.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\n\nA helper type used in switch constructs.\n\nIntroduced with Armed Assault, does not refer to Operation Flashpoint or Operation Flashpoint: Resistance."}],"categories":["Syntactical Helper Types"],"groups":["Data Types"]},{"name":"Task","title":"Task","type":"topic","url":"https://community.bistudio.com/wiki/Task","revid":179426,"updated":"2020-12-31T21:28:07Z","aliases":[],"markdown":"|  |  |  |\n|---|---|---|\n| + Possible values | Task Type | Task Icon (taskHint) |\n| \"Succeeded\" | \"taskDone\" |  |\n| \"Failed\" | \"taskFailed\" |  |\n| \"Canceled\" | \"taskFailed\" |  |\n| \"Created\" | \"taskNew\" |  |\n| \"Current\" | \"taskCurrent\" |  |\n\nA Task is a Data Type that contains a task's details, such as location, title and description.\n\nIt was introduced with Arma 2; before that, games used *objectives* defined in Briefing.html. A null task is of taskNull value.\n\n- For Arma 3 tasks, see Arma 3: Task Framework and its Tutorial.\n- For Arma 2 tasks, see Arma 2: Task Tutorial\n\n### See Also\n\n- Briefing","sections":[{"heading":null,"level":1,"markdown":"|  |  |  |\n|---|---|---|\n| + Possible values | Task Type | Task Icon (taskHint) |\n| \"Succeeded\" | \"taskDone\" |  |\n| \"Failed\" | \"taskFailed\" |  |\n| \"Canceled\" | \"taskFailed\" |  |\n| \"Created\" | \"taskNew\" |  |\n| \"Current\" | \"taskCurrent\" |  |\n\nA Task is a Data Type that contains a task's details, such as location, title and description.\n\nIt was introduced with Arma 2; before that, games used *objectives* defined in Briefing.html. A null task is of taskNull value.\n\n- For Arma 3 tasks, see Arma 3: Task Framework and its Tutorial.\n- For Arma 2 tasks, see Arma 2: Task Tutorial"},{"heading":"See Also","level":3,"markdown":"- Briefing"}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Team","title":"Team","type":"topic","url":"https://community.bistudio.com/wiki/Team","revid":281654,"updated":"2021-06-14T16:32:42Z","aliases":[],"markdown":"**Description:** : n/a\n\nIntroduced with Arma 2.\n\n> [!IMPORTANT]\n> **Not** related to teamSwitch or assignedTeam.\n\nSee Command Group: Teams for related commands.","sections":[{"heading":null,"level":1,"markdown":"**Description:** : n/a\n\nIntroduced with Arma 2.\n\n> [!IMPORTANT]\n> **Not** related to teamSwitch or assignedTeam.\n\nSee Command Group: Teams for related commands."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"Team Member","title":"Team Member","type":"topic","url":"https://community.bistudio.com/wiki/Team_Member","revid":340881,"updated":"2023-05-13T21:44:16Z","aliases":[],"markdown":"**Description:** n/a - see Command Group: Teams.\n\nIntroduced with Arma 2.","sections":[{"heading":null,"level":1,"markdown":"**Description:** n/a - see Command Group: Teams.\n\nIntroduced with Arma 2."}],"categories":["Data Types"],"groups":["Data Types"]},{"name":"User Interface Event Handlers","title":"User Interface Event Handlers","type":"topic","url":"https://community.bistudio.com/wiki/User_Interface_Event_Handlers","revid":378424,"updated":"2026-04-06T13:41:34Z","aliases":["Arma 3: Event Handlers/User Interface","Arma 3: User Interface Event Handlers","UIEH"],"markdown":"__NOEDITSECTION__\n\nUser Interface Event Handlers are used to execute code when events related to GUI components (i.e. Displays and Controls) occur.\n\n> [!WARNING]\n> About ctrlDelete in an Event Handler's script: ctrlDelete needs to be the last executed statement or Arma will crash.\n>\n> Alternatively, the code can also be spawned to circumvent this issue.\n>\n> ```cpp\n> onButtonClick = \"ctrlDelete (_this select 0); systemChat 'You will never see this';\";            // Crashes the game\n> onButtonClick = \"systemChat 'Bye bye button!'; ctrlDelete (_this select 0);\";                    // Works fine\n> onButtonClick = \"_this spawn { ctrlDelete (_this select 0); systemChat 'Bye bye button!'; };\";    // Works fine\n> ```\n\n### Reference List\n\n#### Generic Events\n\n##### onLoad\n\n- **Use on:** Display, Control\n- **Fired on:** Fires when UI container is created, but no action is taken. The `onLoad` event for display fires **after** the `onLoad` events for all controls it contains are fired.\n- **Returns:** Display or control, for controls it also returns the control's config (since Arma 3 v1.56).\n\n```sqf\nparams [\"_displayOrControl\", [\"_config\", configNull]];\n```\n\n> [!NOTE]\n> The order of initialisation is as follows:\n> 1. all controls, top to bottom.\n> 1. Display\n> This means that during the `onLoad` event of the upper controls the lower controls have yet to be created.\n\n##### onUnload\n\n- **Use on:** Display\n- **Fired on:** Display is closed, but no controls are destroyed yet.\n- **Returns:** Returns the display and exit code.\n\n```sqf\nparams [\"_display\", \"_exitCode\"];\n```\n\n> [!NOTE]\n> The `onUnload` event never fires for RscTitles displays created with cutRsc.\n\n> [!WARNING]\n> Code or function should be called, otherwise controls might be destroyed before spawned code is executed!\n\n##### onChildDestroyed\n\n- **Use on:** Display\n- **Fired on:** Child display is closed.\n- **Returns:** Returns the display, which child display was closed and exit code.\n\n```sqf\nparams [\"_display\", \"_closedChildDisplay\", \"_exitCode\"];\n```\n\n##### onCommitted (Arma 3 v2.14)\n\n- **Use on:** Control\n- **Fired on:** ctrlSetFade, ctrlSetScale, ctrlSetAngle and ctrlSetPosition in combination with ctrlCommit.\n- **Returns:** Returns the control, type of animation (`\"alpha\"`, `\"scale\"`, `\"rotation\"` or `\"position\"`) and the committed time.\n\n```sqf\nparams [\"_control\", \"_animType\", \"_animTime\"];\n```\n\n##### onEditChanged (Arma 3 v2.14)\n\n- **Use on:** Control\n- **Fired on:** Any changes to the CT_EDIT text field content.\n- **Returns:** Returns the control and the changed text.\n\n```sqf\nparams [\"_control\", \"_newText\"];\n```\n\n##### onMouseEnter\n\n- **Use on:** Control\n- **Fired on:** The mouse pointer enters the control area.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!NOTE]\n> The `onMouseEnter` event only fires on enabled buttons (see ctrlEnable).\n>\n> Arma 3 v2.18 This event handler type seems to only work on controls that can be interacted with. For example buttons, listboxes and so on.\n\n##### onMouseExit\n\n- **Use on:** Control\n- **Fired on:** The mouse pointer exits the control area.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!NOTE]\n> Arma 3 v2.18 This event handler type seems to only work on controls that can be interacted with. For example buttons, listboxes and so on.\n\n##### onSetFocus\n\n- **Use on:** Control\n- **Fired on:** Input focus is on control. It now begins to accept keyboard input.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onKillFocus\n\n- **Use on:** Control\n- **Fired on:** Input focus is no longer on control. It no longer accepts keyboard input.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onTimer\n\n- **Use on:** Control\n- **Fired on:** N/A.\n- **Returns:** N/A.\n\n> [!NOTE]\n> This feature has yet to be implemented.\n\n##### onKeyDown\n\n- **Use on:** Display, Control\n- **Fired on:** Pressing any keyboard key. Fired before the `onKeyUp` event.\n- **Returns:** Returns the display or control, the keyboard code and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_key\", \"_shift\", \"_ctrl\", \"_alt\"];\ntrue // Intercepts the default action, e.g. pressing Escape won't close the dialog.\n```\n\nIn Arma 3, in order to be able to intercept key events during gameplay, the Event Handler should be added to Display 46:\n\n```sqf\nfindDisplay 46 displayAddEventHandler [\"KeyDown\", {}];\n```\n\nIn general, one should never return true in the `onKeyDown` EH, especially if it's added to Display 46 - otherwise all input is overridden and there is no way to do anything in the game anymore.\n\n> [!WARNING]\n> Pressing and holding key triggers 'autorepeat' action on Windows, which in turn will make this EH fire repeatedly as well.\n\n##### onKeyUp\n\n- **Use on:** Display, Control\n- **Fired on:** Releasing any keyboard key. Fired after the onKeyDown event.\n- **Returns:** Returns the display or control, the keyboard code and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_key\", \"_shift\", \"_ctrl\", \"_alt\"];\n```\n\n##### onChar\n\n- **Use on:** Display, Control\n- **Fired on:** When some readable characters is recognised.\n- **Returns:** Returns the display or control and the [char code](https://www.ascii-code.com/).\n\n```sqf\nparams [\"_displayOrControl\", \"_charCode\"];\n```\n\n##### onIMEChar\n\n- **Use on:** Control\n- **Fired on:** When IME character is recognized (used in Korean and other eastern languages).\n- **Returns:** Returns the control and the char code.\n\n```sqf\nparams [\"_control\", \"_charCode\"];\n```\n\n##### onIMEComposition\n\n- **Use on:** Control\n- **Fired on:** When partial IME character is recognized (used in Korean and other eastern languages).\n- **Returns:** Returns the control and the char code.\n\n```sqf\nparams [\"_control\", \"_charCode\"];\n```\n\n##### onMouseButtonDown\n\n- **Use on:** Display, Control\n- **Fired on:** Pressing a mouse button. Followed by the `onMouseButtonUp` event.\n- **Returns:** Returns the display or control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```\n\n##### onMouseButtonUp\n\n- **Use on:** Display, Control\n- **Fired on:** Releasing a mouse button. Follows the `onMouseButtonDown` event.\n- **Returns:** Returns the display or control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```\n\n##### onMouseButtonClick\n\n- **Use on:** ListBox, ComboBox, TextBox, Button, ActiveText\n- **Fired on:** Pressing and releasing a mouse button.\n- **Returns:** Returns the control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_control\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```\n\n##### onMouseButtonDblClick\n\n- **Use on:** Control\n- **Fired on:** Pressing and releasing a mouse button twice within very short time.\n- **Returns:** Returns the control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_control\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```\n\n##### onMouseMoving\n\n- **Fired on:** Fires continuously while moving the mouse with a certain interval.\n\n---\n\n- **Use on:** Control, Display\n- **Returns:** Returns the control, the x and y coordinates relative to the controls parent and mouseOver.\nIf the controls parent is its display then x and y will be the same as getMousePosition else it will be relative to its parent control (for instance if inside a CT_CONTROLS_GROUP).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_mouseOver\"];\n```\n\n---\n\n- **Use on:** Display\n- **Returns:** Returns the display, and how much the mouse was moved since the last time the event fired in UI coordinates.\n\n```sqf\nparams [\"_display\", \"_xDeltaPos\", \"_yDeltaPos\"];\n```\n\n##### onMouseHolding\n\n- **Fired on:** Fires continuously with a specific interval while mouse is stationary.\n\n---\n\n- **Use on:** Control, Display\n- **Returns:** Returns the control, the x and y coordinates relative to the controls parent and mouseOver.\nIf the controls parent is its display then x and y will be the same as getMousePosition else it will be relative to its parent control (for instance if inside a CT_CONTROLS_GROUP).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_mouseOver\"];\n```\n\n---\n\n- **Use on:** Display\n- **Returns:** Returns the display, and *some kind of* x and y delta position.\n\n```sqf\nparams [\"_display\", \"_xPos\", \"_yPos\"];\n```\n\n##### onMouseZChanged\n\n- **Use on:** Display, Control\n- **Fired on:** Fires when mouse wheel position is changed. Only fires on enabled controls.\n- **Returns:** Returns the display or control and the change of the scrollwheel.\n\n```sqf\nparams [\"_displayOrControl\", \"_scroll\"];\n```\n\n##### onCanDestroy\n\n- **Use on:** Control\n- **Fired on:** Ask this control if dialog can be closed (used for validation of contained data).\n- **Returns:** Returns the control and exit code.\n\n```sqf\nparams [\"_control\", \"_exitCode\"];\n```\n\n##### onDestroy\n\n- **Use on:** Control\n- **Fired on:** Destroying control\n- **Returns:** Returns the control and exit code.\n\n```sqf\nparams [\"_control\", \"_exitCode\"];\n```\n\n#### Button Events\n\n##### onButtonClick\n\n- **Use on:** Button\n- **Fired on:** The attached button action is performed. When returned value is true, the engine behaviour is overridden.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onButtonDblClick (Arma 3 v1.00)\n\n- **Use on:** Button\n- **Fired on:** Button double clicked.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onButtonDown\n\n- **Use on:** Button\n- **Fired on:** The left mouse button is pressed over the button area or a key on the keyboard is pressed.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onButtonUp\n\n- **Use on:** Button\n- **Fired on:** When left mouse button is released outside the button area and the attached button action **went unexecuted**.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n#### Listbox Events\n\n##### onLBSelChanged\n\n- **Use on:** Listbox, Combobox, Table\n- **Fired on:** The selection in a listbox is changed. The left mouse button has been released and the new selection is fully made.\n\n> [!WARNING]\n> This EH will fire even if no new selection was made and the user clicked on existing selection\n\n> [!NOTE]\n> Since Arma 3 v2.11 controls with the LB_MULTI style pass an additional `_lbSelection` parameter to the EH script (see lbCurSel, lbSelection).\n\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_lbCurSel\", \"_lbSelection\"];\n```\n\n##### onLBListSelChanged\n\n- **Use on:** Combobox\n- **Fired on:** When selection in XCombo box changed (but value has yet to be stored).\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```\n\n##### onLBDblClick\n\n- **Use on:** Listbox\n- **Fired on:** Double click on some row in listbox.\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```\n\n##### onLBDrag\n\n- **Use on:** Listbox\n- **Fired on:** Drag & drop operation started.\n- **Returns:** Returns the control and an array of arrays of information on the dragged item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\nControl must have unique IDC and `canDrag` parameter enabled in its class in order to work.\n\n```sqf\nparams [\"_control\", \"_listboxInfo\"];\n// Get info of first item being dragged:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```\n\n##### onLBDragging\n\n- **Use on:** Listbox\n- **Fired on:** Drag & drop operation is in progress.\n- **Returns:** Returns the control, the x and y coordinates in screen space, listbox IDC where item(s) were dragged from and an array of arrays of information on the dragged item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_listboxIDC\", \"_listboxInfo\"];\n// Get info of first item being dragged:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```\n\n##### onLBDrop\n\n- **Use on:** Listbox, Combobox, Textbox, ActiveText, Button, ControlsGroup\n- **Fired on:** When a Drag & drop operation is finished.\n- **Returns:** Returns the control, the x and y coordinates in screen space, listbox IDC where item(s) were dragged from and an array of arrays of information on the dropped item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\nWhen the Listbox is inside a CT_CONTROLS_GROUP the Event Handler needs to be added to the CT_CONTROLS_GROUP.\nWill only work for a CT_CONTROLS_GROUP that is outside of any other group.\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_listboxIDC\", \"_listboxInfo\"];\n//Get info of first item being dropped:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```\n\n#### Tree Events\n\n##### onTreeSelChanged\n\n- **Use on:** Tree\n- **Fired on:** Changing the selection in a tree.\n- **Returns:** Returns the control and the new selection path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```\n\n##### onTreeLButtonDown\n\n- **Use on:** Tree\n- **Fired on:** Pressing and releasing left mouse button on a tree.\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onTreeDblClick\n\n- **Use on:** Tree\n- **Fired on:** Pressing and releasing twice on a tree entry.\n- **Returns:** Returns the control and the current selection path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```\n\n##### onTreeExpanded\n\n- **Use on:** Tree\n- **Fired on:** The tree folder structure has been expanded.\n- **Returns:** Returns the control and path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```\n\n##### onTreeCollapsed\n\n- **Use on:** Tree\n- **Fired on:** The tree folder structure has been collapsed.\n- **Returns:** Returns the control and path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```\n\n##### onTreeMouseMove\n\n- **Use on:** Tree\n- **Fired on:** Fires continuously while moving the mouse with a certain interval.\n- **Returns:** Returns the control. Also returns the path, probably since Eden Editor update.\n\n```sqf\nparams [\"_control\", \"_path\"];\n```\n\n##### onTreeMouseHold\n\n- **Use on:** Tree\n- **Fired on:** Fires continuously at a specific interval while mouse is still.\n- **Returns:** Returns the control. Also returns the path, probably since Eden Editor update.\n\n```sqf\nparams [\"_control\", \"_path\"];\n```\n\n##### onTreeMouseExit\n\n- **Use on:** Tree\n- **Fired on:** The mouse pointer exits the tree control area\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```\n\n##### onTreeFilterUpdated (Arma 3 v2.12)\n\n- **Use on:** Tree\n- **Fired on:** A search/filter done on the tree\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_treeControl\", \"_searchControl\", \"_searchString\"];\n```\n\n#### Checkbox Events\n\n##### onChecked (Arma 3 v1.00)\n\n- **Use on:** Checkbox (CT_CHECKBOX).\n- **Fired on:** N/A\n- **Returns:** N/A\n\n> [!NOTE]\n> This feature has yet to be implemented.\n\n##### onCheckedChanged (Arma 3 v1.00)\n\n- **Use on:** Checkbox (CT_CHECKBOX).\n- **Fired on:** Checked state of ctrlCheckBox / RscCheckBox changed.\n- **Returns:** Returns control and the checked state ( 0 for unchecked, 1 for checked ).\n\n```sqf\nparams [\"_control\", \"_checked\"];\n```\n\n##### onCheckBoxesSelChanged\n\n- **Use on:** Checkboxes (CT_CHECKBOXES).\n- **Fired on:** Changed the selection of checkboxes.\n- **Returns:** Returns the control, the selected element index and the current state.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\", \"_currentState\"];\n```\n\n#### Misc. Events\n\n##### onToolBoxSelChanged\n\n- **Use on:** Toolbox\n- **Fired on:** Changed the selection in a toolbox.\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```\n\n##### onHTMLLink\n\n- **Use on:** HTML\n- **Fired on:** Pressing and releasing a HTML link.\n- **Returns:** Returns the control and href.\n\n```sqf\nparams [\"_control\", \"_url\"];\n```\n\n##### onSliderPosChanged\n\n- **Use on:** Slider\n- **Fired on:** Changing the position of a slider.\n- **Returns:** Returns the control and the change.\n\n```sqf\nparams [\"_control\", \"_newValue\"];\n```\n\n##### onObjectMoved\n\n- **Use on:** Object\n- **Fired on:** Moving an object.\n- **Returns:** Returns the control and the offset on the x, y and z axes.\n\n```sqf\nparams [\"_control\", \"_offset\"];\n```\n\n##### onMenuSelected\n\n- **Use on:** Context menu\n- **Fired on:** Some item in context menu (used now only in new mission editor) was selected.\n- **Returns:** Returns the control and the command id.\n\n```sqf\nparams [\"_control\", \"_commandId\"];\n```\n\n##### onDraw\n\n- **Use on:** Map, Display (only on UIOnTexture Display Arma 3 v2.12)\n- **Fired on:** Fires when the map is drawn or the UI On Texture Display received a draw request (can occur more than once per second).\n- **Returns:** Returns the map control.\n\n> [!IMPORTANT]\n> This event handler gets destroyed when the mission it was executed in ends.\n\n```sqf\nparams [\"_controlOrDisplay\"];\n```\n\n##### onVideoStopped (Arma 2: Operation Arrowhead v1.56)\n\n- **Use on:** Control\n- **Fired on:** Activated every time the video ends (when looped, handler is executed after every finished loop).\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!WARNING]\n> When using the event names via GUI scripting commands (e.g ctrlAddEventHandler, displayAddEventHandler), the prefix \"on\" in the name **must be removed** (e.g. `ButtonDown` instead of `onButtonDown`)!\n\n### Event Parameters\n\nThe Event Handlers receive parameters through the magic variable `_this`. Each event passes a different set of parameters (listed above) in an array. The control or display that the event was assigned to is always found in `_this select 0`.\n\n### Scope\n\nArmed Assault v1.00 In Armed Assault, most control-specific events ONLY work for controls and never for displays. The two exceptions being: `onKeyDown` and `onKeyUp`.\n\nArma 2 v1.00 Since Arma 2, most control-specific events work for both displays and controls.\n\n### Defining Events\n\nUser Interface Event Handlers can be assigned in two ways: Via class property definitions or via scripting commands.\n\n#### Class-Defined Events\n\nEvents can be defined in the Dialog (display) or Control classes (in Config.cpp or Description.ext). The event property value (string) is executed as a line of code.\n\nAn example line (this would be found within a control or dialog class):\n\n```cpp\nonMouseButtonDown = \"hint str _this\";\n```\n\nFull Example:\n\n```cpp\nclass RscControlsGroup\n{\n    type    = 15;\n    idc        = -1;\n    style    =  0;\n    x = 0;\n    y = 0;\n    w = 1;\n    h = 1;\n\n    class VScrollbar\n    {\n        color[]                = { 1, 1, 1, 1 };\n        width                = 0.021;\n        autoScrollSpeed        = -1;\n        autoScrollDelay        = 5;\n        autoScrollRewind    = 0;\n    };\n\n    class HScrollbar\n    {\n        color[]    = { 1, 1, 1, 1 };\n        height    = 0.028;\n    };\n\n    class ScrollBar        // >= Arma 2\n    {\n        color[]            = { 1, 1, 1, 0.6 };\n        colorActive[]    = { 1, 1, 1, 1 };\n        colorDisabled[]    = { 1, 1, 1, 0.3 };\n        thumb            = \"#(argb,8,8,3)color(1,1,1,1)\";\n        arrowEmpty        = \"#(argb,8,8,3)color(1,1,1,1)\";\n        arrowFull        = \"#(argb,8,8,3)color(1,1,1,1)\";\n        border            = \"#(argb,8,8,3)color(1,1,1,1)\";\n    };\n\n    class Controls {};\n};\n\nclass MouseHandler : RscControlsGroup\n{\n    onMouseHolding        = \"[0, _this] call myEventFunction\";\n    onMouseButtonDown    = \"[1, _this] call myEventFunction\";\n    onMouseButtonUp        = \"[2, _this] call myEventFunction\";\n    onMouseZChanged        = \"[3, _this] call myEventFunction\";\n    onMouseEnter        = \"[4, _this] call myEventFunction\";\n    idc = 123;\n    x = 0.0;\n    y = 0.0;\n    w = 1.0;\n    h = 1.0;\n    colorBackground[] = { 0.2, 0.0, 0.0, 0.0 };\n};\n```\n\n#### Script-Defined Events\n\nThese events can also be given to dialogs and controls using the displayAddEventHandler and ctrlAddEventHandler commands. The control has to be enabled for the Event Handler in order for Event Handlers to fire (see ctrlEnable).\n\n```sqf\n// Add Event Handler:\n(findDisplay 46) displayAddEventHandler [\"KeyDown\", {\n    _this call functionName_keyDown;\n}];\n\n// Function definition:\nfunctionName_keyDown = {\n    params [\"_ctrl\", \"_dikCode\", \"_shift\", \"_ctrlKey\", \"_alt\"];\n    private _handled = false;\n\n    if (!_shift && !_ctrlKey && !_alt) then {\n        if (_dikCode in (actionKeys \"NetworkStats\")) then {\n            systemChat format [\"EH fired for %1\", _ctrl];\n            _handled = true;\n        };\n    };\n\n    _handled;\n};\n```","sections":[{"heading":null,"level":1,"markdown":"__NOEDITSECTION__\n\nUser Interface Event Handlers are used to execute code when events related to GUI components (i.e. Displays and Controls) occur.\n\n> [!WARNING]\n> About ctrlDelete in an Event Handler's script: ctrlDelete needs to be the last executed statement or Arma will crash.\n>\n> Alternatively, the code can also be spawned to circumvent this issue.\n>\n> ```cpp\n> onButtonClick = \"ctrlDelete (_this select 0); systemChat 'You will never see this';\";            // Crashes the game\n> onButtonClick = \"systemChat 'Bye bye button!'; ctrlDelete (_this select 0);\";                    // Works fine\n> onButtonClick = \"_this spawn { ctrlDelete (_this select 0); systemChat 'Bye bye button!'; };\";    // Works fine\n> ```"},{"heading":"Reference List","level":3,"markdown":""},{"heading":"Generic Events","level":4,"markdown":""},{"heading":"onLoad","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Fires when UI container is created, but no action is taken. The `onLoad` event for display fires **after** the `onLoad` events for all controls it contains are fired.\n- **Returns:** Display or control, for controls it also returns the control's config (since Arma 3 v1.56).\n\n```sqf\nparams [\"_displayOrControl\", [\"_config\", configNull]];\n```\n\n> [!NOTE]\n> The order of initialisation is as follows:\n> 1. all controls, top to bottom.\n> 1. Display\n> This means that during the `onLoad` event of the upper controls the lower controls have yet to be created."},{"heading":"onUnload","level":5,"markdown":"- **Use on:** Display\n- **Fired on:** Display is closed, but no controls are destroyed yet.\n- **Returns:** Returns the display and exit code.\n\n```sqf\nparams [\"_display\", \"_exitCode\"];\n```\n\n> [!NOTE]\n> The `onUnload` event never fires for RscTitles displays created with cutRsc.\n\n> [!WARNING]\n> Code or function should be called, otherwise controls might be destroyed before spawned code is executed!"},{"heading":"onChildDestroyed","level":5,"markdown":"- **Use on:** Display\n- **Fired on:** Child display is closed.\n- **Returns:** Returns the display, which child display was closed and exit code.\n\n```sqf\nparams [\"_display\", \"_closedChildDisplay\", \"_exitCode\"];\n```"},{"heading":"onCommitted (Arma 3 v2.14)","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** ctrlSetFade, ctrlSetScale, ctrlSetAngle and ctrlSetPosition in combination with ctrlCommit.\n- **Returns:** Returns the control, type of animation (`\"alpha\"`, `\"scale\"`, `\"rotation\"` or `\"position\"`) and the committed time.\n\n```sqf\nparams [\"_control\", \"_animType\", \"_animTime\"];\n```"},{"heading":"onEditChanged (Arma 3 v2.14)","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Any changes to the CT_EDIT text field content.\n- **Returns:** Returns the control and the changed text.\n\n```sqf\nparams [\"_control\", \"_newText\"];\n```"},{"heading":"onMouseEnter","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** The mouse pointer enters the control area.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!NOTE]\n> The `onMouseEnter` event only fires on enabled buttons (see ctrlEnable).\n>\n> Arma 3 v2.18 This event handler type seems to only work on controls that can be interacted with. For example buttons, listboxes and so on."},{"heading":"onMouseExit","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** The mouse pointer exits the control area.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!NOTE]\n> Arma 3 v2.18 This event handler type seems to only work on controls that can be interacted with. For example buttons, listboxes and so on."},{"heading":"onSetFocus","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Input focus is on control. It now begins to accept keyboard input.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onKillFocus","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Input focus is no longer on control. It no longer accepts keyboard input.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onTimer","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** N/A.\n- **Returns:** N/A.\n\n> [!NOTE]\n> This feature has yet to be implemented."},{"heading":"onKeyDown","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Pressing any keyboard key. Fired before the `onKeyUp` event.\n- **Returns:** Returns the display or control, the keyboard code and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_key\", \"_shift\", \"_ctrl\", \"_alt\"];\ntrue // Intercepts the default action, e.g. pressing Escape won't close the dialog.\n```\n\nIn Arma 3, in order to be able to intercept key events during gameplay, the Event Handler should be added to Display 46:\n\n```sqf\nfindDisplay 46 displayAddEventHandler [\"KeyDown\", {}];\n```\n\nIn general, one should never return true in the `onKeyDown` EH, especially if it's added to Display 46 - otherwise all input is overridden and there is no way to do anything in the game anymore.\n\n> [!WARNING]\n> Pressing and holding key triggers 'autorepeat' action on Windows, which in turn will make this EH fire repeatedly as well."},{"heading":"onKeyUp","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Releasing any keyboard key. Fired after the onKeyDown event.\n- **Returns:** Returns the display or control, the keyboard code and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_key\", \"_shift\", \"_ctrl\", \"_alt\"];\n```"},{"heading":"onChar","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** When some readable characters is recognised.\n- **Returns:** Returns the display or control and the [char code](https://www.ascii-code.com/).\n\n```sqf\nparams [\"_displayOrControl\", \"_charCode\"];\n```"},{"heading":"onIMEChar","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** When IME character is recognized (used in Korean and other eastern languages).\n- **Returns:** Returns the control and the char code.\n\n```sqf\nparams [\"_control\", \"_charCode\"];\n```"},{"heading":"onIMEComposition","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** When partial IME character is recognized (used in Korean and other eastern languages).\n- **Returns:** Returns the control and the char code.\n\n```sqf\nparams [\"_control\", \"_charCode\"];\n```"},{"heading":"onMouseButtonDown","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Pressing a mouse button. Followed by the `onMouseButtonUp` event.\n- **Returns:** Returns the display or control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```"},{"heading":"onMouseButtonUp","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Releasing a mouse button. Follows the `onMouseButtonDown` event.\n- **Returns:** Returns the display or control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_displayOrControl\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```"},{"heading":"onMouseButtonClick","level":5,"markdown":"- **Use on:** ListBox, ComboBox, TextBox, Button, ActiveText\n- **Fired on:** Pressing and releasing a mouse button.\n- **Returns:** Returns the control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_control\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```"},{"heading":"onMouseButtonDblClick","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Pressing and releasing a mouse button twice within very short time.\n- **Returns:** Returns the control, the pressed button, the x and y coordinates and the state of <kbd>Shift</kbd>, <kbd>Ctrl</kbd> and <kbd>Alt</kbd>.\n\n```sqf\nparams [\"_control\", \"_button\", \"_xPos\", \"_yPos\", \"_shift\", \"_ctrl\", \"_alt\"];\n```"},{"heading":"onMouseMoving","level":5,"markdown":"- **Fired on:** Fires continuously while moving the mouse with a certain interval.\n\n---\n\n- **Use on:** Control, Display\n- **Returns:** Returns the control, the x and y coordinates relative to the controls parent and mouseOver.\nIf the controls parent is its display then x and y will be the same as getMousePosition else it will be relative to its parent control (for instance if inside a CT_CONTROLS_GROUP).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_mouseOver\"];\n```\n\n---\n\n- **Use on:** Display\n- **Returns:** Returns the display, and how much the mouse was moved since the last time the event fired in UI coordinates.\n\n```sqf\nparams [\"_display\", \"_xDeltaPos\", \"_yDeltaPos\"];\n```"},{"heading":"onMouseHolding","level":5,"markdown":"- **Fired on:** Fires continuously with a specific interval while mouse is stationary.\n\n---\n\n- **Use on:** Control, Display\n- **Returns:** Returns the control, the x and y coordinates relative to the controls parent and mouseOver.\nIf the controls parent is its display then x and y will be the same as getMousePosition else it will be relative to its parent control (for instance if inside a CT_CONTROLS_GROUP).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_mouseOver\"];\n```\n\n---\n\n- **Use on:** Display\n- **Returns:** Returns the display, and *some kind of* x and y delta position.\n\n```sqf\nparams [\"_display\", \"_xPos\", \"_yPos\"];\n```"},{"heading":"onMouseZChanged","level":5,"markdown":"- **Use on:** Display, Control\n- **Fired on:** Fires when mouse wheel position is changed. Only fires on enabled controls.\n- **Returns:** Returns the display or control and the change of the scrollwheel.\n\n```sqf\nparams [\"_displayOrControl\", \"_scroll\"];\n```"},{"heading":"onCanDestroy","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Ask this control if dialog can be closed (used for validation of contained data).\n- **Returns:** Returns the control and exit code.\n\n```sqf\nparams [\"_control\", \"_exitCode\"];\n```"},{"heading":"onDestroy","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Destroying control\n- **Returns:** Returns the control and exit code.\n\n```sqf\nparams [\"_control\", \"_exitCode\"];\n```"},{"heading":"Button Events","level":4,"markdown":""},{"heading":"onButtonClick","level":5,"markdown":"- **Use on:** Button\n- **Fired on:** The attached button action is performed. When returned value is true, the engine behaviour is overridden.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onButtonDblClick (Arma 3 v1.00)","level":5,"markdown":"- **Use on:** Button\n- **Fired on:** Button double clicked.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onButtonDown","level":5,"markdown":"- **Use on:** Button\n- **Fired on:** The left mouse button is pressed over the button area or a key on the keyboard is pressed.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onButtonUp","level":5,"markdown":"- **Use on:** Button\n- **Fired on:** When left mouse button is released outside the button area and the attached button action **went unexecuted**.\n- **Returns:** Returns control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"Listbox Events","level":4,"markdown":""},{"heading":"onLBSelChanged","level":5,"markdown":"- **Use on:** Listbox, Combobox, Table\n- **Fired on:** The selection in a listbox is changed. The left mouse button has been released and the new selection is fully made.\n\n> [!WARNING]\n> This EH will fire even if no new selection was made and the user clicked on existing selection\n\n> [!NOTE]\n> Since Arma 3 v2.11 controls with the LB_MULTI style pass an additional `_lbSelection` parameter to the EH script (see lbCurSel, lbSelection).\n\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_lbCurSel\", \"_lbSelection\"];\n```"},{"heading":"onLBListSelChanged","level":5,"markdown":"- **Use on:** Combobox\n- **Fired on:** When selection in XCombo box changed (but value has yet to be stored).\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```"},{"heading":"onLBDblClick","level":5,"markdown":"- **Use on:** Listbox\n- **Fired on:** Double click on some row in listbox.\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```"},{"heading":"onLBDrag","level":5,"markdown":"- **Use on:** Listbox\n- **Fired on:** Drag & drop operation started.\n- **Returns:** Returns the control and an array of arrays of information on the dragged item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\nControl must have unique IDC and `canDrag` parameter enabled in its class in order to work.\n\n```sqf\nparams [\"_control\", \"_listboxInfo\"];\n// Get info of first item being dragged:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```"},{"heading":"onLBDragging","level":5,"markdown":"- **Use on:** Listbox\n- **Fired on:** Drag & drop operation is in progress.\n- **Returns:** Returns the control, the x and y coordinates in screen space, listbox IDC where item(s) were dragged from and an array of arrays of information on the dragged item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_listboxIDC\", \"_listboxInfo\"];\n// Get info of first item being dragged:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```"},{"heading":"onLBDrop","level":5,"markdown":"- **Use on:** Listbox, Combobox, Textbox, ActiveText, Button, ControlsGroup\n- **Fired on:** When a Drag & drop operation is finished.\n- **Returns:** Returns the control, the x and y coordinates in screen space, listbox IDC where item(s) were dragged from and an array of arrays of information on the dropped item(s) (if listbox is of style LB_MULTI then multiple items can be dragged and dropped at the same time).\nWhen the Listbox is inside a CT_CONTROLS_GROUP the Event Handler needs to be added to the CT_CONTROLS_GROUP.\nWill only work for a CT_CONTROLS_GROUP that is outside of any other group.\n\n```sqf\nparams [\"_control\", \"_xPos\", \"_yPos\", \"_listboxIDC\", \"_listboxInfo\"];\n//Get info of first item being dropped:\n(_listboxInfo select 0) params [\"_lbText\", \"_lbValue\", \"_lbData\"];\n```"},{"heading":"Tree Events","level":4,"markdown":""},{"heading":"onTreeSelChanged","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** Changing the selection in a tree.\n- **Returns:** Returns the control and the new selection path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```"},{"heading":"onTreeLButtonDown","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** Pressing and releasing left mouse button on a tree.\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onTreeDblClick","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** Pressing and releasing twice on a tree entry.\n- **Returns:** Returns the control and the current selection path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```"},{"heading":"onTreeExpanded","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** The tree folder structure has been expanded.\n- **Returns:** Returns the control and path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```"},{"heading":"onTreeCollapsed","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** The tree folder structure has been collapsed.\n- **Returns:** Returns the control and path.\n\n```sqf\nparams [\"_control\", \"_selectionPath\"];\n```"},{"heading":"onTreeMouseMove","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** Fires continuously while moving the mouse with a certain interval.\n- **Returns:** Returns the control. Also returns the path, probably since Eden Editor update.\n\n```sqf\nparams [\"_control\", \"_path\"];\n```"},{"heading":"onTreeMouseHold","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** Fires continuously at a specific interval while mouse is still.\n- **Returns:** Returns the control. Also returns the path, probably since Eden Editor update.\n\n```sqf\nparams [\"_control\", \"_path\"];\n```"},{"heading":"onTreeMouseExit","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** The mouse pointer exits the tree control area\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```"},{"heading":"onTreeFilterUpdated (Arma 3 v2.12)","level":5,"markdown":"- **Use on:** Tree\n- **Fired on:** A search/filter done on the tree\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_treeControl\", \"_searchControl\", \"_searchString\"];\n```"},{"heading":"Checkbox Events","level":4,"markdown":""},{"heading":"onChecked (Arma 3 v1.00)","level":5,"markdown":"- **Use on:** Checkbox (CT_CHECKBOX).\n- **Fired on:** N/A\n- **Returns:** N/A\n\n> [!NOTE]\n> This feature has yet to be implemented."},{"heading":"onCheckedChanged (Arma 3 v1.00)","level":5,"markdown":"- **Use on:** Checkbox (CT_CHECKBOX).\n- **Fired on:** Checked state of ctrlCheckBox / RscCheckBox changed.\n- **Returns:** Returns control and the checked state ( 0 for unchecked, 1 for checked ).\n\n```sqf\nparams [\"_control\", \"_checked\"];\n```"},{"heading":"onCheckBoxesSelChanged","level":5,"markdown":"- **Use on:** Checkboxes (CT_CHECKBOXES).\n- **Fired on:** Changed the selection of checkboxes.\n- **Returns:** Returns the control, the selected element index and the current state.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\", \"_currentState\"];\n```"},{"heading":"Misc. Events","level":4,"markdown":""},{"heading":"onToolBoxSelChanged","level":5,"markdown":"- **Use on:** Toolbox\n- **Fired on:** Changed the selection in a toolbox.\n- **Returns:** Returns the control and the selected element index.\n\n```sqf\nparams [\"_control\", \"_selectedIndex\"];\n```"},{"heading":"onHTMLLink","level":5,"markdown":"- **Use on:** HTML\n- **Fired on:** Pressing and releasing a HTML link.\n- **Returns:** Returns the control and href.\n\n```sqf\nparams [\"_control\", \"_url\"];\n```"},{"heading":"onSliderPosChanged","level":5,"markdown":"- **Use on:** Slider\n- **Fired on:** Changing the position of a slider.\n- **Returns:** Returns the control and the change.\n\n```sqf\nparams [\"_control\", \"_newValue\"];\n```"},{"heading":"onObjectMoved","level":5,"markdown":"- **Use on:** Object\n- **Fired on:** Moving an object.\n- **Returns:** Returns the control and the offset on the x, y and z axes.\n\n```sqf\nparams [\"_control\", \"_offset\"];\n```"},{"heading":"onMenuSelected","level":5,"markdown":"- **Use on:** Context menu\n- **Fired on:** Some item in context menu (used now only in new mission editor) was selected.\n- **Returns:** Returns the control and the command id.\n\n```sqf\nparams [\"_control\", \"_commandId\"];\n```"},{"heading":"onDraw","level":5,"markdown":"- **Use on:** Map, Display (only on UIOnTexture Display Arma 3 v2.12)\n- **Fired on:** Fires when the map is drawn or the UI On Texture Display received a draw request (can occur more than once per second).\n- **Returns:** Returns the map control.\n\n> [!IMPORTANT]\n> This event handler gets destroyed when the mission it was executed in ends.\n\n```sqf\nparams [\"_controlOrDisplay\"];\n```"},{"heading":"onVideoStopped (Arma 2: Operation Arrowhead v1.56)","level":5,"markdown":"- **Use on:** Control\n- **Fired on:** Activated every time the video ends (when looped, handler is executed after every finished loop).\n- **Returns:** Returns the control.\n\n```sqf\nparams [\"_control\"];\n```\n\n> [!WARNING]\n> When using the event names via GUI scripting commands (e.g ctrlAddEventHandler, displayAddEventHandler), the prefix \"on\" in the name **must be removed** (e.g. `ButtonDown` instead of `onButtonDown`)!"},{"heading":"Event Parameters","level":3,"markdown":"The Event Handlers receive parameters through the magic variable `_this`. Each event passes a different set of parameters (listed above) in an array. The control or display that the event was assigned to is always found in `_this select 0`."},{"heading":"Scope","level":3,"markdown":"Armed Assault v1.00 In Armed Assault, most control-specific events ONLY work for controls and never for displays. The two exceptions being: `onKeyDown` and `onKeyUp`.\n\nArma 2 v1.00 Since Arma 2, most control-specific events work for both displays and controls."},{"heading":"Defining Events","level":3,"markdown":"User Interface Event Handlers can be assigned in two ways: Via class property definitions or via scripting commands."},{"heading":"Class-Defined Events","level":4,"markdown":"Events can be defined in the Dialog (display) or Control classes (in Config.cpp or Description.ext). The event property value (string) is executed as a line of code.\n\nAn example line (this would be found within a control or dialog class):\n\n```cpp\nonMouseButtonDown = \"hint str _this\";\n```\n\nFull Example:\n\n```cpp\nclass RscControlsGroup\n{\n    type    = 15;\n    idc        = -1;\n    style    =  0;\n    x = 0;\n    y = 0;\n    w = 1;\n    h = 1;\n\n    class VScrollbar\n    {\n        color[]                = { 1, 1, 1, 1 };\n        width                = 0.021;\n        autoScrollSpeed        = -1;\n        autoScrollDelay        = 5;\n        autoScrollRewind    = 0;\n    };\n\n    class HScrollbar\n    {\n        color[]    = { 1, 1, 1, 1 };\n        height    = 0.028;\n    };\n\n    class ScrollBar        // >= Arma 2\n    {\n        color[]            = { 1, 1, 1, 0.6 };\n        colorActive[]    = { 1, 1, 1, 1 };\n        colorDisabled[]    = { 1, 1, 1, 0.3 };\n        thumb            = \"#(argb,8,8,3)color(1,1,1,1)\";\n        arrowEmpty        = \"#(argb,8,8,3)color(1,1,1,1)\";\n        arrowFull        = \"#(argb,8,8,3)color(1,1,1,1)\";\n        border            = \"#(argb,8,8,3)color(1,1,1,1)\";\n    };\n\n    class Controls {};\n};\n\nclass MouseHandler : RscControlsGroup\n{\n    onMouseHolding        = \"[0, _this] call myEventFunction\";\n    onMouseButtonDown    = \"[1, _this] call myEventFunction\";\n    onMouseButtonUp        = \"[2, _this] call myEventFunction\";\n    onMouseZChanged        = \"[3, _this] call myEventFunction\";\n    onMouseEnter        = \"[4, _this] call myEventFunction\";\n    idc = 123;\n    x = 0.0;\n    y = 0.0;\n    w = 1.0;\n    h = 1.0;\n    colorBackground[] = { 0.2, 0.0, 0.0, 0.0 };\n};\n```"},{"heading":"Script-Defined Events","level":4,"markdown":"These events can also be given to dialogs and controls using the displayAddEventHandler and ctrlAddEventHandler commands. The control has to be enabled for the Event Handler in order for Event Handlers to fire (see ctrlEnable).\n\n```sqf\n// Add Event Handler:\n(findDisplay 46) displayAddEventHandler [\"KeyDown\", {\n    _this call functionName_keyDown;\n}];\n\n// Function definition:\nfunctionName_keyDown = {\n    params [\"_ctrl\", \"_dikCode\", \"_shift\", \"_ctrlKey\", \"_alt\"];\n    private _handled = false;\n\n    if (!_shift && !_ctrlKey && !_alt) then {\n        if (_dikCode in (actionKeys \"NetworkStats\")) then {\n            systemChat format [\"EH fired for %1\", _ctrl];\n            _handled = true;\n        };\n    };\n\n    _handled;\n};\n```"}],"categories":["Event Handlers","GUI Topics"],"groups":["Event Handlers"]},{"name":"Variables","title":"Variables","type":"topic","url":"https://community.bistudio.com/wiki/Variables","revid":376701,"updated":"2025-11-07T23:34:36Z","aliases":[],"markdown":"A variable is a \"storage container\" or \"named placeholder\" for data. You can read and modify the data once this container is created.\n\nIts \"name\" is referenced as Identifier.\n\n### Requirements\n\nThe following links guide to the basics to understand this article:\n\n- Introduction to Arma Scripting\n- Identifier\n\n### Initialisation\n\nThe first thing to do to create a variable is to find its name, also called identifier; this name must be speaking to the reader - keep in mind that code is meant to be read by *human beings* (see Code Best Practices - Variable format).\n\nOnce a proper name is found, it can be used to **declare** (or **initialise**) the variable:\n\n```sqf\nmyVariable = 0;\n```\n\nBefore Arma 2, querying undefined (or uninitialised) variables returns nil (undefined value); from Arma 2 and later, it returns an \"Error Undefined variable in expression\" error.\n\n> [!NOTE]\n> An undefined (nil) variable converted to String with str will return scalar bool array string 0xe0ffffef (in Armed Assault) and scalar bool array string 0xfcffffef (in Operation Flashpoint).\n>\n> Unless trying to emulate isNil, **always** declare your variable before trying to access it.\n\n### Deletion\n\nOnce created, variables take up space in the computer's memory.\n\nThis is not drastic for small variables, but if a big number of very large variables is used, it is recommended to undefine the unneeded ones in order to free up memory.\n\nVariable deletion is done by setting its value to nil:\n\n```sqf\nHugeVariable = nil;\n```\n\n> [!NOTE]\n> Local variables are automatically freed (deleted from memory) when their scope is exited, avoiding the need to manually deallocate them.\n\n### Scopes\n\nVariables are only visible in certain scopes of the game. This prevents name conflicts between different variables in different scripts.\n\nThere are two main scopes:\n\n#### Global Scope\n\nA global variable is visible from all scripts on the computer on which it was defined.\nNames given to units in the Mission Editor are also global variables pointing to those units, which may not be redefined or modified.\n\n> [!IMPORTANT]\n> a global variable can be different from one machine to another! To ensure the global variable's proper broadcast, see publicVariable, publicVariableServer and publicVariableClient.\n> If the value changes, the broadcast must be reapplied. e.g:\n>\n> ```sqf\n> GlobalVariable = 33;\n> publicVariable \"GlobalVariable\";\n>\n> GlobalVariable = 42;                // GlobalVariable is now 42 on the current machine but still 33 on the others\n> publicVariable \"GlobalVariable\";    // updates the value to 42 for everyone\n> ```\n\n#### Local Scope\n\nA local variable is only visible in the Script, Function or Control Structure in which it was defined.\n\n> [!NOTE]\n> A local variable cannot be broadcast. In order to broadcast a local variable's *value*, it must be assigned to a global variable first:\n>\n> ```sqf\n> private _myLocalVariable = 33;\n> publicVariable \"_myLocalVariable\";    // incorrect\n>\n> GlobalVariable = _myLocalVariable;\n> publicVariable \"GlobalVariable\";    // correct\n> ```\n\n#### Local Variables Scope\n\n> [!WARNING]\n> Local variables in callable code (e.g Functions) should be scoped using the private/privateAll commands,\n> otherwise you may modify local variables of the calling script that are visible in the function.\n\n```sqf\n// Since Arma 3 v1.54\nprivate _myLocalVariable = 0;\n\n// From Arma 2 until Arma 3 v1.54\nlocal _myLocalVariable = 0;\n\n// Before Arma 2\nprivate \"_myLocalVariable\";\n_myLocalVariable = 0;\n\n// Alternative method to private multiple local variables at the same time\nprivate [\"_myLocalVariable1\", \"_myLocalVariable2\"];\n_myLocalVariable1 = 1;\n_myLocalVariable2 = 2;\n```\n\nIf a private variable is initialised within a Control Structure (i.e. if, for, switch, while),\nits existence will be limited to it and its sub-structures - the variable does not exist outside of the structure and will be seen as undefined.\n\n| Variables<br>lifespan | Code |  |  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|---|\n|  |  |  |  |  |  |  |  |  | **BEGINNING OF FILE** - e.g `execVM \"script.sqf\";` |\n|  |  |  |  |  |  |  |  |  | **TAG_GlobalVariable** = \"Global variable\"; `// Global variable is accessible from any scope` |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  |  | private **_myVariable** = 0; |  |  |  |  |  |  |\n|  |  | if (**_condition**) then |  |  |  |  |  |  |  |\n|  |  | { |  |  |  |  |  |  |  |\n|  |  | **_myVariable** = 1; |  |  |  |  |  |  |  |\n|  |  |  | private **_myVariable** = 2; |  |  |  |  |  |  |\n|  |  | **_myVariable** = 3; |  |  |  |  |  |  |  |\n|  |  |  | } else { |  |  |  |  |  |  |\n|  |  | **_myVariable** = 4; |  |  |  |  |  |  |  |\n|  |  | private **_anotherVariable** = 10; |  |  |  |  |  |  |  |\n|  |  | }; |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | hint str **_myVariable**;\t\t\t`// if **_condition** is true,  **_myVariable**'s value is **1**;` |  |  |  |  |  |  |  |\n|  |  | `// if **_condition** is false, **_myVariable**'s value is **4**.` |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | 0 call { |  |  |  |  |  |  |  |\n|  |  | hint str **_myVariable**;\t\t`// works, as called code runs in the same scope` |  |  |  |  |  |  |  |\n|  |  | }; |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | [**_myVariable**] spawn { |  |  |  |  |  |  |  |\n|  |  |  | hint **TAG_GlobalVariable**;\t`// works` |  |  |  |  |  |  |\n|  |  |  | hint str _myVariable;\t\t`// throws an \"undefined variable\" error,` |  |  |  |  |  |  |\n|  |  |  | `// as **_myVariable** does **not** exist in this new script` |  |  |  |  |  |  |\n|  |  |  | }; |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | `// trying to use **_anotherVariable** here would result in an \"undefined variable\" error,` |  |  |  |  |  |  |  |\n|  |  | `// **_anotherVariable** being only scoped in the else block.` |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  | **END OF FILE** - **TAG_GlobalVariable** keeps on living in missionNamespace |  |\n\n| Correct | Incorrect |\n|---|---|\n| ```sqf<br>private _living = false;<br>if (alive player) then<br>{<br>    _living = true;<br>};<br>hint format [\"%1\", _living]; // returns true<br>``` | ```sqf<br>// -<br>if (alive player) then<br>{<br>    private _living = true;<br>};<br>// throws an error since the private variable was<br>// not initialised outside of the if control structure.<br>hint format [\"%1\", _living];<br>``` |\n\n### Data Types\n\nVariables may store values of a certain Data Types (String, Number, etc). The kind of the value specifies the *type* of the variable.\nDifferent operators and commands require variables to be of different types.\n\nA variable is not strongly typed and changes its type according to the new data:\n\n```sqf\nprivate \"_myVariable\";    // nil\n_myVariable = 1;        // 1 (Number)\n_myVariable = \"test\";    // \"test\" (String)\n```\n\n### Multiplayer Considerations\n\nStoring functions (or any callable code) into global variables without securing them with compileFinal (since Arma 3) is a **very** bad practice in multiplayer.\nThe biggest security risk would be to see it being overridden by a malicious usage of publicVariable, setting potentially dangerous code in it.\n\nThe best option is to declare your function in CfgFunctions so the engine secures it for you.\n\nIf you want to manually create a global function anyway, the best practice is the following:\n\n```sqf\nTAG_MyGlobalVariableFunction = compileFinal preprocessFileLineNumbers \"functionFile.sqf\";\n```\n\n> [!NOTE]\n> You should ideally run this code locally on every machine.\n> Using publicVariable  on a \"final\" global function (created with compileFinal) will indeed broadcast the variable **and** make it final on other clients as well, but the network can quickly become saturated from sending big pieces of code.\n\n### See also\n\n- Introduction to Arma Scripting\n- Identifier\n- Data Types\n- Control Structures\n- Magic Variables\n- private/privateAll (Arma 3)\n- local (Arma 2)","sections":[{"heading":null,"level":1,"markdown":"A variable is a \"storage container\" or \"named placeholder\" for data. You can read and modify the data once this container is created.\n\nIts \"name\" is referenced as Identifier."},{"heading":"Requirements","level":3,"markdown":"The following links guide to the basics to understand this article:\n\n- Introduction to Arma Scripting\n- Identifier"},{"heading":"Initialisation","level":3,"markdown":"The first thing to do to create a variable is to find its name, also called identifier; this name must be speaking to the reader - keep in mind that code is meant to be read by *human beings* (see Code Best Practices - Variable format).\n\nOnce a proper name is found, it can be used to **declare** (or **initialise**) the variable:\n\n```sqf\nmyVariable = 0;\n```\n\nBefore Arma 2, querying undefined (or uninitialised) variables returns nil (undefined value); from Arma 2 and later, it returns an \"Error Undefined variable in expression\" error.\n\n> [!NOTE]\n> An undefined (nil) variable converted to String with str will return scalar bool array string 0xe0ffffef (in Armed Assault) and scalar bool array string 0xfcffffef (in Operation Flashpoint).\n>\n> Unless trying to emulate isNil, **always** declare your variable before trying to access it."},{"heading":"Deletion","level":3,"markdown":"Once created, variables take up space in the computer's memory.\n\nThis is not drastic for small variables, but if a big number of very large variables is used, it is recommended to undefine the unneeded ones in order to free up memory.\n\nVariable deletion is done by setting its value to nil:\n\n```sqf\nHugeVariable = nil;\n```\n\n> [!NOTE]\n> Local variables are automatically freed (deleted from memory) when their scope is exited, avoiding the need to manually deallocate them."},{"heading":"Scopes","level":3,"markdown":"Variables are only visible in certain scopes of the game. This prevents name conflicts between different variables in different scripts.\n\nThere are two main scopes:"},{"heading":"Global Scope","level":4,"markdown":"A global variable is visible from all scripts on the computer on which it was defined.\nNames given to units in the Mission Editor are also global variables pointing to those units, which may not be redefined or modified.\n\n> [!IMPORTANT]\n> a global variable can be different from one machine to another! To ensure the global variable's proper broadcast, see publicVariable, publicVariableServer and publicVariableClient.\n> If the value changes, the broadcast must be reapplied. e.g:\n>\n> ```sqf\n> GlobalVariable = 33;\n> publicVariable \"GlobalVariable\";\n>\n> GlobalVariable = 42;                // GlobalVariable is now 42 on the current machine but still 33 on the others\n> publicVariable \"GlobalVariable\";    // updates the value to 42 for everyone\n> ```"},{"heading":"Local Scope","level":4,"markdown":"A local variable is only visible in the Script, Function or Control Structure in which it was defined.\n\n> [!NOTE]\n> A local variable cannot be broadcast. In order to broadcast a local variable's *value*, it must be assigned to a global variable first:\n>\n> ```sqf\n> private _myLocalVariable = 33;\n> publicVariable \"_myLocalVariable\";    // incorrect\n>\n> GlobalVariable = _myLocalVariable;\n> publicVariable \"GlobalVariable\";    // correct\n> ```"},{"heading":"Local Variables Scope","level":4,"markdown":"> [!WARNING]\n> Local variables in callable code (e.g Functions) should be scoped using the private/privateAll commands,\n> otherwise you may modify local variables of the calling script that are visible in the function.\n\n```sqf\n// Since Arma 3 v1.54\nprivate _myLocalVariable = 0;\n\n// From Arma 2 until Arma 3 v1.54\nlocal _myLocalVariable = 0;\n\n// Before Arma 2\nprivate \"_myLocalVariable\";\n_myLocalVariable = 0;\n\n// Alternative method to private multiple local variables at the same time\nprivate [\"_myLocalVariable1\", \"_myLocalVariable2\"];\n_myLocalVariable1 = 1;\n_myLocalVariable2 = 2;\n```\n\nIf a private variable is initialised within a Control Structure (i.e. if, for, switch, while),\nits existence will be limited to it and its sub-structures - the variable does not exist outside of the structure and will be seen as undefined.\n\n| Variables<br>lifespan | Code |  |  |  |  |  |  |  |  |\n|---|---|---|---|---|---|---|---|---|---|\n|  |  |  |  |  |  |  |  |  | **BEGINNING OF FILE** - e.g `execVM \"script.sqf\";` |\n|  |  |  |  |  |  |  |  |  | **TAG_GlobalVariable** = \"Global variable\"; `// Global variable is accessible from any scope` |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  |  | private **_myVariable** = 0; |  |  |  |  |  |  |\n|  |  | if (**_condition**) then |  |  |  |  |  |  |  |\n|  |  | { |  |  |  |  |  |  |  |\n|  |  | **_myVariable** = 1; |  |  |  |  |  |  |  |\n|  |  |  | private **_myVariable** = 2; |  |  |  |  |  |  |\n|  |  | **_myVariable** = 3; |  |  |  |  |  |  |  |\n|  |  |  | } else { |  |  |  |  |  |  |\n|  |  | **_myVariable** = 4; |  |  |  |  |  |  |  |\n|  |  | private **_anotherVariable** = 10; |  |  |  |  |  |  |  |\n|  |  | }; |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | hint str **_myVariable**;\t\t\t`// if **_condition** is true,  **_myVariable**'s value is **1**;` |  |  |  |  |  |  |  |\n|  |  | `// if **_condition** is false, **_myVariable**'s value is **4**.` |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | 0 call { |  |  |  |  |  |  |  |\n|  |  | hint str **_myVariable**;\t\t`// works, as called code runs in the same scope` |  |  |  |  |  |  |  |\n|  |  | }; |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | [**_myVariable**] spawn { |  |  |  |  |  |  |  |\n|  |  |  | hint **TAG_GlobalVariable**;\t`// works` |  |  |  |  |  |  |\n|  |  |  | hint str _myVariable;\t\t`// throws an \"undefined variable\" error,` |  |  |  |  |  |  |\n|  |  |  | `// as **_myVariable** does **not** exist in this new script` |  |  |  |  |  |  |\n|  |  |  | }; |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  |  |  |\n|  |  | `// trying to use **_anotherVariable** here would result in an \"undefined variable\" error,` |  |  |  |  |  |  |  |\n|  |  | `// **_anotherVariable** being only scoped in the else block.` |  |  |  |  |  |  |  |\n|  |  |  |  |  |  |  |  | **END OF FILE** - **TAG_GlobalVariable** keeps on living in missionNamespace |  |\n\n| Correct | Incorrect |\n|---|---|\n| ```sqf<br>private _living = false;<br>if (alive player) then<br>{<br>    _living = true;<br>};<br>hint format [\"%1\", _living]; // returns true<br>``` | ```sqf<br>// -<br>if (alive player) then<br>{<br>    private _living = true;<br>};<br>// throws an error since the private variable was<br>// not initialised outside of the if control structure.<br>hint format [\"%1\", _living];<br>``` |"},{"heading":"Data Types","level":3,"markdown":"Variables may store values of a certain Data Types (String, Number, etc). The kind of the value specifies the *type* of the variable.\nDifferent operators and commands require variables to be of different types.\n\nA variable is not strongly typed and changes its type according to the new data:\n\n```sqf\nprivate \"_myVariable\";    // nil\n_myVariable = 1;        // 1 (Number)\n_myVariable = \"test\";    // \"test\" (String)\n```"},{"heading":"Multiplayer Considerations","level":3,"markdown":"Storing functions (or any callable code) into global variables without securing them with compileFinal (since Arma 3) is a **very** bad practice in multiplayer.\nThe biggest security risk would be to see it being overridden by a malicious usage of publicVariable, setting potentially dangerous code in it.\n\nThe best option is to declare your function in CfgFunctions so the engine secures it for you.\n\nIf you want to manually create a global function anyway, the best practice is the following:\n\n```sqf\nTAG_MyGlobalVariableFunction = compileFinal preprocessFileLineNumbers \"functionFile.sqf\";\n```\n\n> [!NOTE]\n> You should ideally run this code locally on every machine.\n> Using publicVariable  on a \"final\" global function (created with compileFinal) will indeed broadcast the variable **and** make it final on other clients as well, but the network can quickly become saturated from sending big pieces of code."},{"heading":"See also","level":3,"markdown":"- Introduction to Arma Scripting\n- Identifier\n- Data Types\n- Control Structures\n- Magic Variables\n- private/privateAll (Arma 3)\n- local (Arma 2)"}],"categories":["Scripting Topics"],"groups":["Scripting"]},{"name":"Vector3D","title":"Vector3D","type":"topic","url":"https://community.bistudio.com/wiki/Vector3D","revid":377906,"updated":"2026-01-06T14:47:33Z","aliases":["Vector"],"markdown":"*See also Vector2D.*\n**Format:**\n\n[x, y, z] where x, y and z are Numbers\n\n**Description:**\n\nRepresents a 3-dimensional vector in space.\n\nA **normalised** vector means that each value is within range -1..+1.\n\nThe return array can be processed-converted into degrees as follows:\n\n```sqf\n_vDir = player weaponDirection primaryWeapon player;\n_aDir = _vDir # 0 atan2 _vDir # 1;\n```","sections":[{"heading":null,"level":1,"markdown":"*See also Vector2D.*\n**Format:**\n\n[x, y, z] where x, y and z are Numbers\n\n**Description:**\n\nRepresents a 3-dimensional vector in space.\n\nA **normalised** vector means that each value is within range -1..+1.\n\nThe return array can be processed-converted into degrees as follows:\n\n```sqf\n_vDir = player weaponDirection primaryWeapon player;\n_aDir = _vDir # 0 atan2 _vDir # 1;\n```"}],"categories":["Arrays"],"groups":["Scripting"]},{"name":"Void","title":"Void","type":"topic","url":"https://community.bistudio.com/wiki/Void","revid":330443,"updated":"2022-09-15T21:30:58Z","aliases":[],"markdown":"A variable of type **Void** is an **undefined variable**.\n\n### Undefining Variables\n\nnil can be used to undefine variables.\n\n```sqf\nmyVar = 1;\n// ...\nmyVar = nil;\n// myVar is undefined\n```\n\n### String Representation\n\nThe String representation of an undefined variable depends on its inferred type:\n\n| Data Type | String |\n|---|---|\n| Anything | scalar bool array string 0xfcffffef (OFP)<br>scalar bool array string 0xe0ffffef (ArmA) |\n| Nothing | scalar bool array string nothing 0xfcffffef |\n| Number | scalar |\n| Boolean | bool |\n| Array | array |\n\n### Comparisons\n\nNo comparison with any variables will work.\n\n**Example:**\n\n```sqf\n// error\nif (undefinedVar == definedVar) then { /* ... */ };\n```\n\n```sqf\n// error\nif (undefinedVar == undefinedVar) then { /* ... */ };\n```\n\n### Detect an Undefined Variable\n\nThe isNil command, introduced in Armed Assault, allows to detect if a variable exists or not:\n\n```sqf\nHelloThere = 42;\nisNil \"HelloThere\"; // false\n\nHelloThere = nil;\nisNil \"HelloThere\"; // true\n```\n\n#### isNil Workaround 1 (Operation Flashpoint v1.00)\n\nSQS Syntax:\n\n```sqs\n_nil = format [\"%1\", _undefinedVariable]\n? (format [\"%1\", variableToTest] == _nil) : hint \"variableToTest is nil\"\n```\n\nSQF Syntax:\n\n```sqf\n_nil = format [\"%1\", _undefinedVariable];\nif (format [\"%1\", variableToTest] == _nil) then { hint \"variableToTest is nil\" };\n```\n\n#### isNil Workaround 2 (Operation Flashpoint v1.00)\n\n> [!CAUTION]\n> This information is **obsolete**. Armed Assault introduced isNil, and Arma 2 forbade undefined variables usage in script - see ArmA: Editing#Forward Compatibility.\n\nThe alternative way to check if a variable is undefined before isNil existence is that it silently fails any expression evaluations on it:\n\n```sqf\ndefined = false;\nif (var == var) then\n{\n    defined = true;\n};\nif (var != var) then\n{\n    defined = true;\n};\nif (!defined) then\n{\n    // we know var is undefined here\n};\n```\n\n### Type Inference\n\nSuppose the variable **a** is undefined, and we set the variable **b** like so:\n\n```sqf\nb = a + [];\n```\n\nThe inferred type of b is now array - since b was the product result of an array add operation with a definite array ([]) and an unknown type (a)\n\n**b**'s string representation will now be \"array\", and b wil be considered an undefined array.","sections":[{"heading":null,"level":1,"markdown":"A variable of type **Void** is an **undefined variable**."},{"heading":"Undefining Variables","level":3,"markdown":"nil can be used to undefine variables.\n\n```sqf\nmyVar = 1;\n// ...\nmyVar = nil;\n// myVar is undefined\n```"},{"heading":"String Representation","level":3,"markdown":"The String representation of an undefined variable depends on its inferred type:\n\n| Data Type | String |\n|---|---|\n| Anything | scalar bool array string 0xfcffffef (OFP)<br>scalar bool array string 0xe0ffffef (ArmA) |\n| Nothing | scalar bool array string nothing 0xfcffffef |\n| Number | scalar |\n| Boolean | bool |\n| Array | array |"},{"heading":"Comparisons","level":3,"markdown":"No comparison with any variables will work.\n\n**Example:**\n\n```sqf\n// error\nif (undefinedVar == definedVar) then { /* ... */ };\n```\n\n```sqf\n// error\nif (undefinedVar == undefinedVar) then { /* ... */ };\n```"},{"heading":"Detect an Undefined Variable","level":3,"markdown":"The isNil command, introduced in Armed Assault, allows to detect if a variable exists or not:\n\n```sqf\nHelloThere = 42;\nisNil \"HelloThere\"; // false\n\nHelloThere = nil;\nisNil \"HelloThere\"; // true\n```"},{"heading":"isNil Workaround 1 (Operation Flashpoint v1.00)","level":4,"markdown":"SQS Syntax:\n\n```sqs\n_nil = format [\"%1\", _undefinedVariable]\n? (format [\"%1\", variableToTest] == _nil) : hint \"variableToTest is nil\"\n```\n\nSQF Syntax:\n\n```sqf\n_nil = format [\"%1\", _undefinedVariable];\nif (format [\"%1\", variableToTest] == _nil) then { hint \"variableToTest is nil\" };\n```"},{"heading":"isNil Workaround 2 (Operation Flashpoint v1.00)","level":4,"markdown":"> [!CAUTION]\n> This information is **obsolete**. Armed Assault introduced isNil, and Arma 2 forbade undefined variables usage in script - see ArmA: Editing#Forward Compatibility.\n\nThe alternative way to check if a variable is undefined before isNil existence is that it silently fails any expression evaluations on it:\n\n```sqf\ndefined = false;\nif (var == var) then\n{\n    defined = true;\n};\nif (var != var) then\n{\n    defined = true;\n};\nif (!defined) then\n{\n    // we know var is undefined here\n};\n```"},{"heading":"Type Inference","level":3,"markdown":"Suppose the variable **a** is undefined, and we set the variable **b** like so:\n\n```sqf\nb = a + [];\n```\n\nThe inferred type of b is now array - since b was the product result of an array add operation with a definite array ([]) and an unknown type (a)\n\n**b**'s string representation will now be \"array\", and b wil be considered an undefined array."}],"categories":["Magic Types"],"groups":["Data Types"]},{"name":"While Type","title":"While Type","type":"topic","url":"https://community.bistudio.com/wiki/While_Type","revid":245279,"updated":"2021-02-10T14:23:54Z","aliases":[],"markdown":"**Description:**\nHelper type used in while...do construct.\n\n### See Also\n\nControl Structures","sections":[{"heading":null,"level":1,"markdown":"**Description:**\nHelper type used in while...do construct."},{"heading":"See Also","level":3,"markdown":"Control Structures"}],"categories":["Syntactical Helper Types"],"groups":["Data Types"]},{"name":"With Type","title":"With Type","type":"topic","url":"https://community.bistudio.com/wiki/With_Type","revid":245278,"updated":"2021-02-10T14:23:37Z","aliases":[],"markdown":"**Description:**\n\nA helper type created by the operator with and used in do constructs.","sections":[{"heading":null,"level":1,"markdown":"**Description:**\n\nA helper type created by the operator with and used in do constructs."}],"categories":["Syntactical Helper Types"],"groups":["Data Types"]}]}