b3lx 161 Posted July 19, 2018 I made a script that choreographs an execution sequence (yeah its pretty grim). For it to work there is constant meddling in AI behaviour settings. The problem is that some enemy might suddenly appear and try to stop it, so AI must react accordingly and return to its normal settings if that happens. To do this I put a check for enemies before each block in the execution sequence. It works but it seems an overcomplicated way of achieving this. I read about exitwith {} and breakout but they seem to be of use inside control structures or loops and not for interrupting a single sequence. To stop a script from continue and do something else instead is a pretty useful thing even in other situations so I was wondering: anybody have a solution for this? //execution script //place a group of soldiers in front of a group of prisioners. name each group "executioners" and "prisioners" and launch this script; other soldiers can also be around and they won't engage the prisioners. //systemchat "start"; private _exec = units executioners; private _pris = units prisioners; private _officer = leader executioners; private _all = []; private _squad = _exec - [_officer]; //put all friendly units to executioners side in a radius of 300 in an array { if (((_x distance (getpos _officer)) < 300) && (side _x == side executioners)) then { _all pushback _x; }; } forEach allunits; //make all of them pacifists { _x setbehaviour "careless"; _x setcombatMode "blue"; } forEach _all; //take note of each units voice to give them back later, also officers weapons private _voicesquad = []; private _voicepris = []; {_voicesquad pushback (speaker _x)} forEach _squad; {_voicepris pushback (speaker _x)} forEach _pris; private _officervoice = speaker _officer; private _weapon = primaryweapon (_squad select 0); private _mags = (magazines (_squad select 0)) select 0; //executioners and prisioners stand up, shut up and stay put { _x disableAI "path"; _x setunitPos "UP"; _x setSpeaker "NoVoice" } forEach (_exec + _pris); //remove stuff from prisioners { private _unit = _x; _unit setcaptive true; removeallweapons _unit; removeAllAssignedItems _unit; {_unit removeMagazine _x} forEach magazines _unit; } forEach _pris; //create directions for facing private _dir = (_officer getdir (_exec select 1)) - 90; private _front = _officer getpos [300,_dir]; private _right = _officer getpos [300,_dir + 90]; private _back = _officer getpos [300,_dir + 180]; private _left = _officer getpos [300,_dir - 90]; private _pos = getpos _officer; removeallweapons _officer; removeAllAssignedItems _officer; //make groups face each other {_x doWatch _front} forEach _squad; {_x doWatch _back} forEach _pris; //STOP SCRIPT CONDITION--------------------------------------------- //if an enemy comes the execution sequence should interrupt and the menace dealt with. private _execution = true; _reset = { { _x setbehaviour "safe"; _x enableAI "path"; _x enableAI "target"; _x setcombatmode "YELLOW"; _x forceWalk false; } forEach _all; { _x setSpeaker (_voicesquad select _forEachIndex); } forEach _squad; { _x setSpeaker (_voicepris select _forEachIndex); _x setcaptive false; } forEach _pris; _officer setSpeaker _officervoice; _officer addmagazines [_mags,4]; _officer addweapon _weapon; _execution = false; }; //the above reset function will be called if an enemy (with the exeception of the prisioner group) closer than 400 is detected. the enemy detection function will be called before every step in the execution sequence private _enemypresent = false; _checkenemies = { private _enemy = []; { if (((_x distance _pos) < 400) && (side _x != side executioners)) then { _enemy pushback _x; }; } forEach allunits; _enemy = _enemy - _pris; { if ((side executioners) knowsAbout _x > 1.5) then {_enemypresent = true}; } forEach _enemy; if _enemypresent then {call _reset}; }; sleep 5; //systemchat "aim"; //AIM------------------------------------------------- call _checkenemies; if _execution then { executioners setBehaviour "aware"; {_x setCaptive false} forEach _pris; {_x doTarget (leader prisioners)} forEach _squad; _officer doWatch _right; sleep 5; }; //systemchat "fire"; //FIRE------------------------------------------------- _officer setspeaker _officervoice; executioners setcombatmode "red"; //wait until all prisioners are dead waituntil {{alive _x} count _pris == 0}; //systemchat "lower weapons"; //LOWERWEAPONS---------------------------------------- call _checkenemies; if _execution then { { _x disableAI 'TARGET'; } forEach _squad; executioners setbehaviour "careless"; _officer doWatch _right; _officer setspeaker "noVoice"; sleep 5; }; //systemchat "turn"; //TURN------------------------------------------------ call _checkenemies; if _execution then { {_x dowatch _back} forEach _squad; sleep 5; }; //systemchat "move"; //MOVE------------------------------------------------- call _checkenemies; if _execution then { { _x enableAI "path"; _x enableAI 'TARGET'; _x forceWalk true; _x doMove _back; } forEach _squad; sleep 10; }; //AT EASE----------------------------------------------- call _checkenemies; if _execution then { {_x doWatch _right} forEach _exec; _officer enableAI "path"; _squad doFollow _officer; //return weapon to officer _officer addmagazines [_mags,4]; _officer addweapon _weapon; _officer setspeaker _officervoice; sleep 2; }; //GARRISON------------------------------------------------- call _checkenemies; if _execution then { {_x setbehaviour "safe"} forEach _all; private _defendpos = getpos (nearestbuilding _pos); if (_defendpos isEqualTo [0,0,0]) then {_defendpos = _pos}; [executioners,_defendpos,100,3,0,0.5] call CBA_fnc_taskDefend; sleep 2; }; //RETURN TO NORMAL----------------------------------------- call _reset; 1 Share this post Link to post Share on other sites
M1ke_SK 230 Posted July 19, 2018 https://community.bistudio.com/wiki/exitWith If the current scope is the main body of a script, it will exit the script. 3 Share this post Link to post Share on other sites
b3lx 161 Posted July 19, 2018 Yes I saw that some people say it's not reliable for exiting scripts but even assuming it works still I would have to put before each block something like: if _enemypresent then exitwith {_reset}; Is there a way to make it like a loop running parallel to the main script that checks continuously if _enemypresent is true and then make the main body to exit? Share this post Link to post Share on other sites
bad benson 1733 Posted July 19, 2018 i mean if you want it to be a loop, you could store all the code sequences in an array and then loop through them via foreach or count and inside that you would only need to put one single exitwith check...i think. so if you don't want to copy paste it between every sequence, just create the needed structure to avoid that more generally speaking. _execution = [ { params ["_units", "_args"]; ///actual stuff systemchat "sequence 1"; }, { params ["_units", "_args"]; ///actual stuff systemchat "sequence 2"; }, { params ["_units", "_args"]; ///actual stuff systemchat "sequence 3"; } ]; { if _enemyclose exitwith {systemchat "execution aborted"}; [_units, [_arg1, _arg2]] call _x } foreach _execution; this is semi pseudo code. not tested. but to illustrate what i meant. 2 Share this post Link to post Share on other sites
stanhope 409 Posted July 19, 2018 Create a trigger (enemy faction present & detected by friendly faction), add in the on-activation of the trigger the following code: _nil = [] call resetFunction; terminate _scripthandle; You'll have to make the reset function global to be able to do this. 2 1 Share this post Link to post Share on other sites
b3lx 161 Posted July 19, 2018 They are good ideas for the next time I need this. Thanks a lot! It also hit me based on stanhope's suggestion, that if I don't want to use a trigger I could start another script that would be running parallel in loop, checking the condition and terminate the main script via scripthandle. Share this post Link to post Share on other sites
bad benson 1733 Posted July 19, 2018 oh yea i didn't notice you used sleep that extensively. terminate makes a lot more sense in that case. Share this post Link to post Share on other sites
HazJ 1288 Posted July 20, 2018 You can also assign a global handle to it if needed outside. someHandle = ... termiante someHandle; Also keep in mind: Note: The given script will not terminate immediately upon terminate command execution, it will do so the next time the script is processed by the scheduler. 1 Share this post Link to post Share on other sites