HomeALiVE 3Docs
Menu
Donate

ALiVE.OS · ALiVE 3 Development

Event Reference

The events ALiVE raises while a mission runs, and how to listen for them from your own scripts.

Scripting reference · ALiVE 3

ALiVE 3 is in active development. This briefing describes work in progress, and the behaviour it covers is subject to change as testing continues. Check the changelog at the foot of the page for what has moved recently.

On this page

Overview

Listening to ALiVE

ALiVE runs an internal event log. Every time a commander confirms an operation, a task is created, a resupply lands or a profiled unit is killed, ALiVE raises an event describing it. Your mission can register a listener against the event types it cares about and be called back whenever one of them fires, which lets mission scripts react to what ALiVE is doing without polling or reading its internals.

This page lists every event type ALiVE currently raises, along with the data each one carries, taken directly from the code that raises them. It is a reference for mission makers writing their own scripts. Nothing here is required to play or to build a mission in the editor.

How it works

Four things to know

  1. Your listener is a hash carrying a class key that holds the name of your own function.
  2. You register it against a list of event type names, and only those types reach you. Put "ALL" in the list to hear every event.
  3. When a matching event fires, ALiVE calls your function with the operation handleEvent and the event itself. It runs in a scheduled thread of its own, one event at a time and in order, a moment after the event was raised.
  4. Read the event with hashGet: type gives you the event name, data gives you the array described in the tables below, and message gives you the outcome on the replies that carry one.

Getting started

Registering a listener

// in initServer.sqf, after ALiVE has finished starting up
[] spawn {
    waitUntil {!isNil "ALiVE_REQUIRE_INITIALISED"};

    MyMission_fnc_opcomListener = compile preprocessFileLineNumbers "opcomListener.sqf";
    myListener = [nil, "create", ["MyMission_fnc_opcomListener"]] call MyMission_fnc_opcomListener;
};

And the listener itself:

// opcomListener.sqf
params ["_logic", "_operation", "_args"];
private "_result";

switch (_operation) do {

    case "create": {
        _args params ["_functionName"];

        private _logic = [[["class", _functionName]]] call ALiVE_fnc_hashCreate;

        private _listenerID = [
            ALiVE_eventLog,
            "addListener",
            [_logic, ["OPCOM_CAPTURE", "TACOM_ORDER_COMPLETE"]]
        ] call ALiVE_fnc_eventLog;

        [_logic, "listenerID", _listenerID] call ALiVE_fnc_hashSet;
        _result = _logic;
    };

    case "handleEvent": {
        private _event = _args;

        private _type = [_event, "type"] call ALiVE_fnc_hashGet;
        private _data = [_event, "data"] call ALiVE_fnc_hashGet;

        switch (_type) do {

            case "OPCOM_CAPTURE": {
                _data params ["_side", "_objective"];
                private _pos = [_objective, "center"] call ALiVE_fnc_hashGet;
                // react here
            };

            case "TACOM_ORDER_COMPLETE": {
                _data params ["_opcomID", "_objective", "_tacomState", "_side", "_factions", "_success"];
                // react here
            };
        };
    };
};

if (!isNil "_result") then {_result} else {nil};

Worked example

Pairing sector modules with ALiVE objectives

A common request. The commander events describe intent and orders rather than an objective quietly changing hands, so for ownership this reads control directly and keeps each sector in step with its nearest objective.

// Pairing Arma's Sector modules with ALiVE objectives.
// Place your sector modules in the editor and name them. For each sector this
// finds every commander's nearest objective, then hands the sector to the
// side whose commander holds its objective there. Run it on the server.

[] spawn {
    waitUntil {!isNil "ALiVE_REQUIRE_INITIALISED"};
    waitUntil {!isNil "OPCOM_instances" && {count OPCOM_instances > 0}};

    private _sectors = [sector1, sector2, sector3];   // your editor-placed modules
    private _pairs = [];

    // once: for each sector, each commander's closest objective
    {
        private _sector = _x;
        private _candidates = [];

        {
            private _side = [_x, "side", ""] call ALiVE_fnc_hashGet;
            private _objectives = [_x, "objectives", []] call ALiVE_fnc_hashGet;
            private _best = [];
            private _bestDist = 1e9;

            {
                private _centre = [_x, "center"] call ALiVE_fnc_hashGet;

                if (!isNil "_centre" && {count _centre > 1}) then {
                    private _d = _sector distance2D _centre;
                    if (_d < _bestDist) then {_bestDist = _d; _best = _x};
                };
            } forEach _objectives;

            // only an objective that is really at this sector
            if (_best isNotEqualTo [] && {_bestDist < 300}) then {_candidates pushBack [_side, _best]};

        } forEach OPCOM_instances;

        if (_candidates isNotEqualTo []) then {_pairs pushBack [_sector, _candidates]};

    } forEach _sectors;

    // then keep them in step
    while {true} do {

        {
            _x params ["_sector", "_candidates"];

            private _owner = sideUnknown;

            {
                _x params ["_side", "_objective"];
                if ([_objective, _side, 300, false] call ALiVE_fnc_isHeldObjective) exitWith {
                    _owner = [_side] call ALiVE_fnc_sideTextToObject;
                };
            } forEach _candidates;

            if (_owner isNotEqualTo sideUnknown) then {
                // hand _owner to your sector here
            };

        } forEach _pairs;

        sleep 30;
    };
};

Reference

Every event, and what it carries

46 event types, grouped by the module that raises them. The data column is the array you get back from the event's data key.

mil_opcom

Commander

These describe what the AI commander intends and what its subordinate orders did. They do not fire on an objective silently changing hands, so if you want to mirror ownership onto something else, poll instead. See the note below the tables.

EventDataRaised when
OPCOM_ORDER_CONFIRMED[opcomID, objective, operation, side, factions]The commander has settled on an operation for an objective.
TACOM_ORDER_ISSUED[opcomID, objective, operation, side, factions, args]The order has gone out to the groups that will carry it out.
TACOM_ORDER_COMPLETE[opcomID, objective, tacomState, side, factions, success, args]An order finished. The success flag says whether it achieved its aim.
OPCOM_CAPTURE[side, objective]An objective has moved into the capture state for that side.
OPCOM_DEFEND[side, objective]An objective has moved into the defend state.
OPCOM_RECON[side, objective]An objective has moved into the recon state.
OPCOM_RESERVE[side, objective]An objective is being held as a reserve.
OPCOM_TERRORIZE[side, objective]Asymmetric commanders only. An objective is being targeted for intimidation.
ASYMM_INSTALLATION_DESTROYED[installationType, building, killer]An insurgent installation has been destroyed. It also goes out as a CBA event of the same name on every machine, so ["ASYMM_INSTALLATION_DESTROYED", {...}] call CBA_fnc_addEventHandler hears it on clients too.
mil_c2istar

Tasks

The task engine raises these as tasks are requested, created, changed and finished. TASK_GENERATE is the request channel other modules use to ask for a task; TASK_CREATE is the task actually existing.

EventDataRaised when
TASK_GENERATE[requestID, playerID, side, faction, type, location, destination, players, enemyFaction, current, apply, ...]Something has asked for a task to be generated. playerID is a player's ID for a player's request, otherwise the module asking: CP, ARTY, OPCOM, LOGCOM, ATO or C2ISTAR. Some task types add more after apply, most often a list of targets.
TASK_CREATE[requestID, playerID, side, destination, faction, title, description, players, state, apply, current, parent, source, editingDisabled, rev, id]A task has been created.
TASK_UPDATE[taskID, playerID, side, destination, faction, title, description, players, state, apply, current, parent, source, editingDisabled, rev, id]An existing task has changed. The layout matches TASK_CREATE, except that it starts with the task's ID rather than the request's.
TASK_DELETE[taskID, playerID, side]A task has been removed, by C2ISTAR, by a commander clearing its own task, or by a player's order replacing an earlier one.
TASK_SUCCEEDED[taskDialog, side, faction, rewardData]A task was completed successfully and a reward is being handed out.
TASKS_AUTO_GENERATE[requestID, playerID, side, faction, enemyFaction, autoGenerate]Automatic task generation settings for a side have been applied.
TASKS_UPDATE["", playerID, side]A refresh of the task list has been asked for.
TASKS_UPDATED[playerID, [sideTasks, autoGenerateSide]]The task list has been rebuilt and is being pushed out.
TASKS_SYNC[playerID, groupID]A joining player needs the current task list.
mil_logistics

Logistics

The replies carry their outcome in the event's message key: [_event, "message"] call ALiVE_fnc_hashGet. LOGCOM_RESPONSE sends ACKNOWLEDGED, REQUEST_INSERTION, REQUEST_ENROUTE, REQUEST_ARRIVED, REQUEST_DELIVERED, REQUEST_LOST, CANCEL_OK, CANCEL_FAILED, STATUS, DENIED_WAITING_INIT, DENIED_FACTION_HANDLER_NOT_FOUND, DENIED_FORCEPOOL, DENIED_FORCE_CREATION and DENIED_NOT_AVAILABLE. With STATUS, the answer itself is the third element of data.

EventDataRaised when
LOGCOM_REQUEST[position, faction, side, forceMakeup, deliveryType, (playerID)]Reinforcements or supplies have been requested, by a commander, a player, C2ISTAR, the air commander or a Start From Ship wave. deliveryType is STANDARD, AIRDROP, HELI_INSERT, HELI_PARADROP or SEA_INSERT.
LOGCOM_RESPONSE[requestID, playerID, (response)]The logistics commander has answered a request; read the message key for the outcome. STATUS and the cancel replies add the response, and REQUEST_DELIVERED carries [requestID, playerID, destination, delivered]. The air commander also answers an air cancel this way.
LOGCOM_STATUS_REQUEST[faction, side, requestID, playerID]Someone has asked for the state of an outstanding request.
LOGCOM_CANCEL_REQUEST[faction, side, requestID, playerID, selectedRequestID]A request is being cancelled.
LOGCOM_RESUPPLY[position, side, assetType, callsign, source, [needsAmmo, needsFuel, needsRepair], vehicle]A resupply run has been asked for, by a Combat Support asset or by an aircraft the air commander has brought home.
LOGISTICS_INSERTION[position, faction, side, eventID, eventType]A delivery has begun its insertion.
LOGISTICS_DESTINATION[position, faction, side, eventID, eventType]A delivery is heading for its destination.
LOGISTICS_COMPLETE[destination, faction, side, eventID, eventType, (deliveredByAir)]A delivery has finished.
FORCEPOOL_UPDATED[faction, forcePool]A faction's available force pool has changed.
LOGCOM_FOB_RESUPPLY[position, side, "FOB", name, fobID]A Player FOB is running low on supply and asks Military Logistics for a truck.
LOGCOM_FOB_RESUPPLY_ARRIVED[fobID, side]That truck reached the FOB. The FOB takes the supply only if it still belongs to that side.
mil_ato

Air

ATO_RESPONSE carries its outcome in the message key too, for example DENIED_ATO_UNAVAILABLE, or STATUS with the answer as the third element of data. It only answers requests made by players.

EventDataRaised when
ATO_REQUEST[type, side, faction, position, args, (requestID, playerID)]An air mission has been requested. Type is the mission kind, for example Strike, Recce or OCA. The trailing pair is only present when a player raised the request.
ATO_RESPONSE[requestID, playerID, (response)]The air commander has answered a player's request; read the message key for the outcome. The response is only there when it has something in it.
ATO_STATUS_REQUEST[faction, side, requestID, playerID]Not raised by ALiVE. The air commander listens for it, so a mission can raise it, and answers with an ATO_RESPONSE whose message is STATUS and whose response lists [missionType, requestID, state, positions].
ATO_CANCEL_REQUEST[faction, side, requestID, playerID, selectedRequestID]Not raised by ALiVE. The air commander listens for it, so a mission can raise it, and answers with a LOGCOM_RESPONSE whose message is CANCEL_OK or CANCEL_FAILED.
ATO_DESTINATION[position, faction, side, eventID]Not raised. Nothing in the mod fires this event any more, so a handler registered on it never runs.
ATO_RETURN[position, faction, side, eventID]Not raised. Nothing in the mod fires this event any more, so a handler registered on it never runs.
ATO_SEAD_ON_STATION[sortieID, zone, positions]A suppression (SEAD) sortie reached its area. positions are the targets it was sent against.
mil_artillery

Artillery

EventDataRaised when
ARTY_REQUEST[contactID, position, contacts, side, faction, asymmetric]A fire mission has been requested.
ARTY_RESUPPLY_REQUEST[position, side, "ARTY", callsign, entityID]A gun has run low and asked for more rounds.
ARTY_RESUPPLY_ARRIVED[entityID]The resupply reached the gun.
sys_profile, amb_civ_population

Units and profiles

These fire for virtualised profiles as well as spawned units, so they cover things happening far away from any player.

EventDataRaised when
PROFILE_KILLED[position, faction, side, killerSide, profile, killerProfile, victimProfileID, victimObjectType]A profiled unit or vehicle was killed, spawned or virtual, including by artillery. killerProfile is nil when the killer had no profile, a player for example.
PROFILE_ATTACK_START[attackID, attackerID, targets, position, attackerSide, maxRange, cyclesLeft]A virtual engagement has begun.
PROFILE_ATTACK_END[attackID, attackerID, targetsLeft, targetsKilled, position, attackerSide, timeStarted, maxRange, cyclesLeft]A virtual engagement has finished.
AGENT_KILLED[position, faction, side, killerSide]A civilian agent was killed.
sup_group_manager

Player groups

EventDataRaised when
GROUP_JOIN[requestID, playerID, unit, group]A player joined a group through the group manager.
GROUP_LEAVE[requestID, playerID, unit]A player left a group.
GROUPS_UPDATED[playerID, []]The group list has been rebuilt.

Worth knowing

Before you build on this

  • Events are raised on the server. Register your listener on the server, and remote execute to clients yourself if they need to know.
  • Register after ALiVE has started. Waiting on ALiVE_REQUIRE_INITIALISED before registering avoids the case where your listener attaches before the event log exists.
  • If you want to mirror objective ownership onto something else, such as a sector module, polling suits it better than events. The commander events describe intent and orders rather than an objective quietly changing hands. The polling example above asks each commander about its own objectives.
  • Two complete working listeners ship inside ALiVE, as opcomEventListener.sqf in the Hue Defence and Operation Cobra scenario missions. They are the same shape as the example above and are kept working alongside the code.

Something here wrong or missing? Please raise it on the ALiVE issue tracker on GitHub. This list is written from the code that raises the events, so it should stay accurate, but the data an event carries can change between development builds.

Alternative

Reading control without events

// Run on the server: OPCOM_instances only exists there.
// isHeldObjective asks whether an objective is still held and not overrun,
// from the side you name. It doesn't check who owns the objective, so ask it
// with the side of the commander the objective belongs to.
// The final false skips the stricter reserve-only test.

{
    private _side = [_x, "side", ""] call ALiVE_fnc_hashGet;
    private _objectives = [_x, "objectives", []] call ALiVE_fnc_hashGet;

    {
        if ([_x, _side, 300, false] call ALiVE_fnc_isHeldObjective) then {
            // this commander's side holds this objective right now
        };
    } forEach _objectives;

} forEach OPCOM_instances;

Changelog

Updates to this page

  • 2026-10-27
    Checked against the current code. The polling and sector examples now ask each commander about its own objectives, since isHeldObjective doesn't check who owns one. Also corrected: the replies' outcome is in the message key, with every value listed; ATO_STATUS_REQUEST and ATO_CANCEL_REQUEST are listened for but not raised; TASK_UPDATE starts with the task's ID; listeners can take ALL and run one event at a time.
  • 2026-08-12
    Every event ALiVE raises during a mission is now documented here, with the data each one carries, a listener you can copy, and a worked example for keeping sector modules in step with ALiVE objectives.