Jump to content

Recommended Posts

Hi,

 

For those who don't know, Arma has a framework to check for an event on each frame of the game (similar to the sleep/sleepUI commands but unscheduled, so higher priority).  Currently, there's no easy way to make it consider objects (or indeed any other data) that does not have a global name.

 

This basic framework can let you add events easily based on time (it uses diag_tickTime fyi).  Also, you can pass custom functions to it not based on time and write out the outcomes yourself (bit more advanced).  

 

  • If you specify a timeout parameter (in seconds), it will only execute your code once the timeout is up.
  • Without a timeout specified, it will execute your code on each frame.

 

FORMAT

 

This is the format for using it:

 

_thisEventHandler = [arguments,code,timeout (optional)] call horde_fnc_addMissionEventHandler;

 

The rules are that the arguments you pass to it must be in an array.  So these are ok:

 

[[player],myFunction,10] call horde_fnc_addMissionEventHandler;
[["string"],myFunction,10] call horde_fnc_addMissionEventHandler;
[[player,"string"],myFunction,10] call horde_fnc_addMissionEventHandler;

 

Using a single argument is NOT ok:

[player,myFunction,10] call horde_fnc_addMissionEventHandler; // bad
["string",myFunction,10] call horde_fnc_addMissionEventHandler; // bad

 

There's no error checking currently* so as long as you stick to the format, then you're ok.

 

EXAMPLES

 

ein)

_fnc = {
    player sideChat format ["%1",_this select 0]
};
[["hello"],_fnc,2] call horde_fnc_addMissionEventHandler;
[["poopy"],_fnc,3] call horde_fnc_addMissionEventHandler;
[["fluffy paws"],_fnc,4] call horde_fnc_addMissionEventHandler;

 

Prints "hello" on screen after 2 seconds, then "poopy" a second later, then "fluffy paws" a second after that.

 

drei)

_fnc = {
    missionNamespace getVariable ("horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0)) params ["_unit","_moving","_notMoving"];
    if (vectorMagnitude velocity vehicle _unit > 1) then {
        systemChat format ["%1 is %2",_unit,_moving]
    } else {
        systemChat format ["%1 %2",_unit,_notMoving]
    }
};
TAG_movingIndicatorID = [[player,"moving","not moving"],_fnc] call horde_fnc_addMissionEventHandler;

 

Infinite loop informing player if he/she is moving or not by systemChat. Note that we no not define the timeout (3rd parameter in the arguments).

 

You can stop it in this example by using the return (TAG_movingIndicatorID)

 

TAG_movingIndicatorID call horde_fnc_removeMissionEventHandler; // stops the sideChat

 

zwei)

 

 

_fnc = {
    missionNamespace getVariable ("horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0)) params ["_unit","_moving"];
    if (vectorMagnitude velocity vehicle _unit > 1) then {
        systemChat format ["%1 is %2 - deleting EventHandler",_unit,_moving];
        _thisEventHandler call horde_fnc_removeMissionEventHandler
    }
};
[[player,"moving"],_fnc] call horde_fnc_addMissionEventHandler;

 

This is a function that is not dependent on time so the 3rd parameter of the arguments does not need to be defined.  If the unit passed to it moves, then it prints a message and then quits.  Note that the deletion is specified in the function.

 

CBA

 

I just wanted to mention cba as they have a great system for this sort of thing, but if you want to use it, then you have to be comfortable with mod dependencies.  This is a poor man's system that lets you manage an unscheduled event system without mods.

 

ALWAYS DO BETTER

 

If you can write something faster/better than this then please comment and post your code in here so we can all benefit.  My code's not great but works ok I think.  I'm sure there's better ways of doing it but I can't think of them right now.

 

FUNCTIONS

horde_fnc_addMissionEventHandler = {
    params ["_args","_code","_timeout"];
    private _thisEventHandler = -1;
    if (isNil "_timeout") then {
        _thisEventHandler = addMissionEventHandler [
            'EachFrame',
            _code
        ];
    } else {
        _thisEventHandler = addMissionEventHandler [
            'EachFrame',
            horde_fnc_missionEventHandlerTimeout
        ];
        _args pushBack [_code,diag_tickTime + _timeout]
    };
    missionNamespace setVariable ["horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0),_args];
    _thisEventHandler
};
horde_fnc_missionEventHandlerTimeout = {
    private _args = missionNamespace getVariable ("horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0));
    _args select (count _args - 1) params ["_code","_timeout"];
    if (diag_tickTime > _timeout) then {
        _args deleteAt (count _args - 1);
        _args call _code;
        removeMissionEventHandler ["EachFrame",_thisEventHandler];
        missionNamespace setVariable ["horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0),nil];
    };
    true
};
horde_fnc_removeMissionEventHandler = {
    removeMissionEventHandler ["EachFrame",_this];
    missionNamespace setVariable ["horde_gv_eachFrameArgs_" + (_this toFixed 0),nil];
    true
};

 

Ta

 

* = I could put this in if required but it will slow the execution down a bit

  • Like 3

Share this post


Link to post
Share on other sites

Interesting, but I'm not sure to understand all aspects. In fact, I don't understand how it's working.

 

On my mind, as we are in an "each framed" context, your variables are updated. Like allUnits or vehicles. So a simple condition if () then {} can do the trick to sort what you need. You call call/spawn an external function:  fnc_thisFunction = {code}; directly inside the MEH, without declaring it as parameter. I'm using MEH like this.


Is your script a way for adding an MEH for each new function? I understand the added value of time out and I note your smart way to remove the MEH, declaring nil the variable container. I don't know why this is not included in the removeMissionEventHandler command.

Share this post


Link to post
Share on other sites

The idea is to be able to access variables out of scope, that aren't global ones like "allUnits" or "vehicles".  So you can have some local variables and pass them to the EH, then run your code (which can also be declared locally and doesn't need to be a global function).

 

So instead of this:

// scheduled
_unit =  selectRandom _someMen; // doesn't matter for this example
_timeout = time + 10;
_ID = [_unit,_timeout] spawn {
    params ["_unit","_timeout"];
    if (time > _timeout) then {
        systemChat format ["Timeout: %1",_unit]
    }
};

You can do this:

// unscheduled
_unit =  selectRandom _someMen;
_ID = [[_unit],{
        systemChat format ["Timeout: %1",_this select 0];
    },
    10
}] call horde_fnc_addMissionEventHandler;

 

Or instead of this:

// scheduled
_unit =  selectRandom _someMen;
_anim = "AmovPknlMstpSrasWrflDnon";
_ID = [_unit,_anim] spawn {
    params ["_unit","_anim"];
    while {alive _unit} do {
        if (animationState _unit == _anim) then {
            systemChat format ["Time: %1: %2 is kneeling down with rifle raised: %3",time,_unit,_anim]
        } else {
            systemChat ""
        }
    }
};

You can do this:

// unscheduled
_unit =  selectRandom _someMen;
_anim = "AmovPknlMstpSrasWrflDnon";
_ID = [[_unit,_anim],{
    missionNamespace getVariable ("horde_gv_eachFrameArgs_" + (_thisEventHandler toFixed 0)) params ["_unit","_anim"];
    if (alive _unit) then {
        if (animationState _unit == _anim) then {
            systemChat format ["Time: %1: %2 is kneeling down with rifle raised: %3",time,_unit,_anim]
        } else {
            systemChat ""
        }
    } else {
        _thisEventHandler call horde_fnc_removeMissionEventHandler
    }
}] call horde_fnc_addMissionEventHandler;

 

As I say, if it helps then use it - or if you can write something better then please do.  It's useful for what I want to do and I thought I'd share.

  • Like 1

Share this post


Link to post
Share on other sites

Interesting, I will keep all of this in mind. 

 

Thank You,

Booker

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×