pierremgi 4875 Posted July 15, 2017 AI REVIVE/HEAL SP/MP Last update 26th/11/2018 Hi all, Here is a script to allow AIs reviving and healing bros, according to parameters. This works in SP or MP. Compatible so far with AI RESPAWN script (see tag) Don't override the respawn system (MP) Incapacitation: This script relies on incapacitated status for players or AIs. This status is created when not existing (SP, or MP Ais) to allow revive scenario. parameters: REACT / HEAL DELAY / AI CAN REVIVE / KIT NEEDED / NEED MEDIC / AI CAN HEAL EXTRA GRP / BROS / WHITE FLAG ON MEDIC IN ACTION Parameters can be added to description.ext, class Params, just add what you want in classes: "react" "bleedOut" "noReviveForAI" "AiKit" "AiMedic" "bros" "whiteflag". So you can choose them while in lobby. Anyway, if you pass parameters calling the function, these params will override the lobby ones (except for bros class, see below). Spoiler [ <REACT: number, seconds (max) to choose the best healer>, // example: 15 (optional) default: 120 During this time, the script tries to find the best healer according to some priorities: not in combat, not targeting, a medic, any bro within 200 m (if any according to other parameters) <HEAL DELAY: number, seconds (max) to heal action, remaining bleedout>, // example: 60 (optional) default: 120 This amount of time is added to the first one. So, healer found or not, this is the remaining time before death unless be revived. <AI CAN REVIVE, boolean>, // example: true (optional) default: true In SP/MP, if false, the AI can't revive but can heal the player (incapacitated). Note that AIs playable units can respawn in MP (Arma engine) <KIT: number, what kind of kit is needed to revive someone>, // example: 0 (optional) default: 0 0: no kit needed, no limit for revive 1: need a first aid kit (FAK) , 1 FAK is removed per reviving action 2: need a medic kit (mediKit) , 1 FAK is removed per reviving action, can heal even if no more FAK <NEED MEDIC: boolean, Medic trait mandatory> // example: true (optional) default: false When true, this limits drastically the chance to be revived. <AI CAN HEAL EXTRA GROUP: AI can heal other groups of bros: number from 0 to 2> // example: 2 (optional) default: 1 0: AIs can heal only Bros belonging to the same group 1: as above + AIs can heal any players in Bros 2: AIs can heal any bro (that means some of your guys can quit the formation for assisting some other groups, then be back). <BROS: side, or array of units>, // example: west (optional) default: playableUnits + switchableUnits Just decide who can be healed and revive. The default param works in SP/MP some custom arrays are working fine also: [blu1,blu2,indep1,indep2] or allUnits select {_x inArea some trigger && side _x == WEST} You can mix several sides but it's weird to make enemies as bros, with never ending shoot/heal loops! See notes at end. <WHITE FLAG: boolean, all medics in healing action> // example: true (optional) default: false When true, all medics, moving to a wounded bro or healing him, carry a white flag. ] Code must run on all PCs. So, init.sqf, (trigger, non-repeatable, condition true)... Spoiler MGI_fn_EHDamage = compileFinal " params ['_unit']; _unit removeAllEventHandlers 'handleDamage'; _unit addEventHandler ['handleDamage', { params ['_unit','','_dam']; if (local _unit) then { if (side _unit != sideEnemy) then { private _veh = objectParent _unit; if (!isnull _veh && isNil {_veh getVariable 'incVeh'} && (damage _veh > 0.7 or (!canfire _veh && !canMove _veh) or _dam > 0.7)) then { _veh setVariable ['incVeh',true,true]; _crew = +(crew _veh); call { if (_dam > 0.7 && {objectParent _unit isKindOf 'air'} && {getPosATL _veh select 2 > 30}) exitWith { [_unit,_veh] spawn { params ['_unit','_veh']; waitUntil {isTouchingGround _veh}; [_unit,_veh] call MGI_fn_BailOut; }; }; if (damage _veh > 0.7 or (!canMove _veh && !canFire _veh)) exitWith { { [_x,_veh] spawn MGI_fn_BailOut } forEach _crew; }; if (_dam >0.7) then { [_unit,_veh] spawn MGI_fn_BailOut; }; }; }; if (isNull objectParent _unit && {(count allPlayers == 1 && isPlayer _unit) or MGI_AiRevive}) then { if !(_unit getVariable ['uncsious',false]) then { _unit setVariable ['uncsious',true,true]; _unit spawn MGI_fn_unconscious; }; }; if (!isPlayer _unit or !isMultiplayer) then {_dam min 0.86} else {_dam}; }; }; }]; "; addMissionEventHandler ["entityRespawned",{ params ["_unit", "_corpse"]; _unit setVariable ["uncsious",nil,true]; _unit setVariable ["myMedic",nil,true]; _unit setVariable ["MedicDelay",nil,true]; _unit setVariable ["MGIIncapTimer",nil,true]; _unit setVariable ["passedBros",nil,true]; _unit setVariable ["myPatient",nil,true]; _corpse setVariable ["passedBros",nil,true]; comment "_unit call MGI_fn_EHDamage"; }]; MGI_fn_BailOut = compileFinal " params ['_unit','_veh']; moveOut _unit; _unit setCaptive true; if (!(backpack _unit isKindOf 'B_parachute') && (ASLToAGL getPosASL _veh select 2) > 30) then { uiSleep random 0.5; _p = createVehicle ['Steerable_Parachute_F', (ASLToAGL getPosASL _unit) vectorAdd [0,0,2],[],0,'none']; uiSleep 0.1; _unit moveInDriver _p; _unit setBehaviour 'combat'; uiSleep 1; if (isnull driver _p) then { deleteVehicle _p; if (!isplayer _unit) then { _unit setDamage 1}; }; } else { uiSleep 3; if (isnull objectParent _unit && !isTouchingGround _unit && !surfaceIsWater getpos _unit) then {_unit setDamage 1}; }; uiSleep 3; if (!isNil {_veh getVariable 'incVeh'}) then {_veh setVariable ['incVeh',nil,true]}; if (_unit getVariable ['uncsious',false]) then { _unit setVariable ['uncsious',false,true]; _unit setVariable ['MGIIncapTimer',nil,true]; }; uisleep 4; if (local _unit) then { _unit setCaptive false } else { [_unit,false] remoteExec ['setCaptive',_unit] }; "; MGI_fn_unconscious = compileFinal " params ['_unit']; waituntil {sleep 0.5; (lifeState _unit == 'incapacitated' or damage _unit == 1 or (!(_unit call BIS_fnc_reviveEnabled) && damage _unit >=0.86))}; if (['medic',animationState _unit] call bis_fnc_inString) then { [_unit,''] remoteExec ['switchMove'] }; if (!(_unit call BIS_fnc_reviveEnabled)) then { if (local _unit) then { _unit setUnconscious true } else { [_unit,true] remoteExec ['setUnconscious',_unit] }; }; if (lifeState _unit == 'incapacitated') then { if (local _unit) then { _unit setCaptive true } else { [_unit,true] remoteExec ['setCaptive',_unit] }; if (!isNil {_unit getVariable 'myPatient'}) then { _unit call MGI_fn_medicRelease }; if (!isPlayer _unit) then { isNil { [_unit,'Heal Bros','\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_reviveMedic_ca.paa','\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_reviveMedic_ca.paa', '_this distance2D _target < 3 && lifeState _target == ""INCAPACITATED""','_caller distance _target < 3', { call { if (stance _caller == 'PRONE') exitWith { _caller playMove 'ainvppnemstpslaywrfldnon_medicother'; }; _caller playMove 'ainvpknlmstpslaywrfldnon_medicother'; }; }, { if ((diag_tickTime > (_this select 3 select 0) + MGI_react + MGI_BleedOut) && lifeState _target == 'incapacitated') then { (_target getVariable ['myMedic',objNull]) call MGI_fn_medicRelease; _target call MGI_fn_death; } }, { if (_target call BIS_fnc_reviveEnabled) then { if (local _target) then { ['#rev',1,_target] call BIS_fnc_reviveOnState; _target setCaptive true } else { [['#rev',1,_target],BIS_fnc_reviveOnState] remoteExec ['call',_target]; [_target,true] remoteExec ['setCaptive',_target] }; } else { _target setDamage 0; if (local _target) then { _target setUnconscious false } else { [_target,false] remoteExec ['setUnconscious',_target] }; }; if (_target getVariable ['uncsious',false]) then { _target setVariable ['uncsious',false,true]; _target setVariable ['MGIIncapTimer',nil,true]; }; (_target getVariable ['myMedic',objNull]) spawn MGI_fn_medicRelease; _target spawn { _target = _this; uiSleep 12; if (local _target) then { _target setCaptive false } else { [_target,false] remoteExec ['setCaptive',_target] }; }; }, { [_caller,''] remoteExec ['switchMove'] }, [diag_tickTime],5,12,true,false] remoteExec ['BIS_fnc_holdActionAdd']; }; }; }; if (isNil {_unit getVariable 'MGIIncapTimer'}) then { _unit setVariable ['MGIIncapTimer',diag_tickTime,true]; }; _timer = _unit getVariable 'MGIIncapTimer'; while {lifeState _unit == 'incapacitated' && diag_tickTime <= _timer + MGI_react + MGI_BleedOut} do { if (local _unit) then { _unit setCaptive true } else { [_unit,true] remoteExec ['setCaptive',_unit] }; if (isnil {_unit getVariable 'myMedic'}) then { _medic = _unit call MGI_fn_medic; if (!isNull _medic) then { [_unit,_medic,_timer] call MGI_fn_911 }; }; uiSleep 2; }; if (lifeState _unit == 'incapacitated' && diag_tickTime > _timer + MGI_react + MGI_BleedOut) exitWith { (_unit getVariable ['myMedic',objNull]) call MGI_fn_medicRelease; _unit call MGI_fn_death; }; (_unit getVariable ['myMedic',objNull]) call MGI_fn_medicRelease; if (_unit getVariable ['uncsious',false]) then { _unit setVariable ['uncsious',false,true]; _unit setVariable ['MGIIncapTimer',nil,true]; }; "; MGI_fn_medic = compileFinal " _wnded = _this; private '_medic'; _wnded setVariable ['myMedic',objNull,true]; if (isNull _wnded) exitWith {_medic = objNull}; private _medics = MGI_potentialMedic select { _x distanceSqr _wnded < 40000 && !isPlayer _x && _x != _wnded && alive _x && lifeState _x != 'incapacitated' && isNil {_x getVariable 'myPatient'} && (isnull objectParent _x or isTouchingGround objectParent _x) && [group _x == group _wnded,group _x == group _wnded or isPlayer _wnded,true] select MGI_canHealExtraGrp }; call { if (isPlayer _wnded) exitWith { _wnded setVariable ['MedicDelay',0,true]; _medics }; if ({behaviour _x != 'COMBAT'} count _medics > 0) exitWith { _wnded setVariable ['MedicDelay',MGI_react/8,true]; _medics = _medics select {behaviour _x != 'COMBAT'}; }; if ({(_x targets [true, 300]) isEqualTo []} count _medics > 0) exitWith { _wnded setVariable ['MedicDelay',MGI_react/4],true; _medics = _medics select {(_x targets [true, 300]) isEqualTo []}; }; if ({{_x == 'MediKit'} count (items _x) > 0} count _medics > 0) exitWith { _wnded setVariable ['MedicDelay',MGI_react/2,true]; _medics = _medics select {{_x == 'MediKit'} count (items _x) > 0}; }; _wnded setVariable ['MedicDelay',MGI_react,true]; _medics; }; if (count _medics == 0) exitWith { _wnded setVariable ['myMedic',nil,true]; _medic = objNull; _medic }; _medics = +_medics apply {[str(leader _x == _x or !isNull objectParent _x or (group _x != group _wnded)),_x distance _wnded, _x]}; _medics sort true; _medic = _medics select 0 select 2; _medic setVariable ['myPatient',_wnded,true]; _medic setHitPointDamage ['hitLegs',0]; _wnded setVariable ['myMedic',_medic,true]; _medic setVariable ['MGI_AIgrp',group _medic,true]; _medic setVariable ['flee',_medic skill 'courage',true]; _medic "; MGI_fn_medicRelease = compileFinal " _medic = _this; if (MGI_whiteFlag) then {_medic forceFlagTexture ''}; if (isNull _medic) exitWith {}; if (!isNil {_medic getVariable 'myPatient'}) then { (_medic getVariable 'myPatient') setVariable ['myMedic',nil,true]}; _medic setVariable ['myPatient',nil,true]; _medic allowFleeing (1 - (_medic getVariable ['flee',0.5])); {_medic enableAI _x} count ['target','autotarget','autocombat','suppression']; _medic setBehaviour 'AWARE'; _grp = _medic getVariable ['MGI_AIgrp',grpNull]; [_medic] joinSilent _grp; if ({isplayer _x} count units _grp >0 && count waypoints _grp > 1) then { _currWpt = currentWaypoint _grp; _cntwpt = count waypoints _grp; while {count waypoints _grp > (_cntwpt - _currWpt)} do {deleteWaypoint [_grp,0]}; }; if (_medic != leader _medic) then { if (local _medic) then { _medic doFollow leader _medic } else { [_medic,leader _medic] remoteExec ['doFollow',_medic] } }; _medic spawn { _medic = _this; uiSleep 12; if (!isNull _medic && lifeState _medic != 'incapacitated' && isNil {_medic getVariable 'myPatient'}) then { if (MGI_whiteFlag) then {_medic forceFlagTexture ''}; if (local _medic) then { _medic setCaptive false } else { [_medic,false] remoteExec ['setCaptive',_medic] }; }; }; "; MGI_fn_sortie = compileFinal " params ['_wnded','_medic','_timer']; call { if (lifeState _wnded == 'incapacitated' && diag_tickTime < _timer + MGI_BleedOut) exitWith { _azimuth = _medic getDir _wnded; _medic setDir _azimuth; _medic removeitem 'FirstAidKit'; call { if (stance _medic == 'PRONE') exitWith { if (local _medic) then { _medic playMoveNow 'ainvppnemstpslaywrfldnon_medicother'; } else { [_medic,'ainvppnemstpslaywrfldnon_medicother'] remoteExec ['playMoveNow',_medic]; }; }; if (local _medic) then { _medic playMoveNow 'ainvpknlmstpslaywrfldnon_medicother'; } else { [_medic,'ainvpknlmstpslaywrfldnon_medicother'] remoteExec ['playMoveNow',_medic]; }; }; uiSleep 5; if (lifeState _medic != 'incapacitated' && alive _medic) then { if (_wnded call BIS_fnc_reviveEnabled) then { if (local _wnded) then { ['#rev',1,_wnded] call BIS_fnc_reviveOnState; uisleep 0.5; _wnded setCaptive true; } else { [['#rev',1,_wnded],BIS_fnc_reviveOnState] remoteExec ['call',_wnded]; uisleep 0.5; [_wnded,true] remoteExec ['setCaptive', _wnded]; }; } else { _wnded setDamage 0; if (local _wnded) then { _wnded setUnconscious false } else { [_wnded,false] remoteExec ['setUnconscious',_wnded] }; }; {if (['Heal Bros',(_wnded actionParams _x) select 0] call bis_fnc_inString) then {[ _wnded,_x] call BIS_fnc_holdActionRemove}} count (actionIDs _wnded); _wnded setVariable ['uncsious',false,true]; _wnded setVariable ['MGIIncapTimer',nil,true]; }; uiSleep 2; _medic call MGI_fn_medicRelease; if (_wnded getVariable ['uncsious',false]) then { _wnded setVariable ['uncsious',false,true]; _wnded setVariable ['MGIIncapTimer',nil,true]; }; {_x setDamage 1} forEach (( _wnded nearEntities ['CAManBase',20]) select {side _x getFriend side _wnded < 0.6 && side _x != civilian}); uiSleep 10; if (local _wnded) then { _wnded setCaptive false } else { [_wnded,false] remoteExec ['setCaptive', _wnded] }; }; if (lifeState _wnded == 'incapacitated' && diag_tickTime > _timer + MGI_BleedOut) exitWith {}; if (_wnded getVariable ['uncsious',false]) then { _wnded setVariable ['uncsious',false,true]; _wnded setVariable ['MGIIncapTimer',nil,true]; }; }; "; MGI_fn_checkMedic = compileFinal " params ['_wnded','_medic','_timer']; uiSleep 2; private _counter = 0; while {lifeState _wnded == 'incapacitated' && diag_tickTime < _timer + MGI_BleedOut} do { uiSleep 1; call { if (lifeState _medic == 'incapacitated') exitWith { _medic call MGI_fn_medicRelease; _wnded call MGI_fn_unconscious; }; if (isnil {_wnded getVariable 'myMedic'}) exitWith { _wnded call MGI_fn_medic; }; if (isNull _medic or isnull (_wnded getVariable 'myMedic')) exitWith { uisleep (_wnded getVariable ['MedicDelay',0]); }; if (currentWaypoint group _medic == count waypoints group _medic && _wnded distance2D _medic >4 && _counter < 3) exitWith { _counter = _counter + 1; while {count waypoints group _medic > 0} do {deleteWaypoint [group _medic,0]}; _wp = group _medic addwaypoint [getPos _wnded,0]; _wp setWaypointType 'MOVE'; _wp showWaypoint 'NEVER'; if (!isnull objectParent _medic) then { unassignVehicle _medic; doGetOut _medic; }; uisleep 3; }; if (currentWaypoint group _medic == count waypoints group _medic or _wnded distance2D _medic <4) exitWith { if (currentWaypoint group _medic != count waypoints group _medic) then { uiSleep 2; }; if (!isNull _wnded && !isNull _medic) then { [_wnded,_medic,_timer] call MGI_fn_sortie }; }; if (_wnded distance2D _medic < 3 && _wnded distanceSqr _medic > 5) then { uisleep 10; if (currentWaypoint group _medic == count waypoints group _medic) exitWith { if (!isNull _wnded && !isNull _medic) then { [_wnded,_medic,_timer] call MGI_fn_sortie }; }; }; }; }; _medic call MGI_fn_medicRelease; if (_wnded getVariable ['uncsious',false]) then { _wnded setVariable ['uncsious',false,true]; _wnded setVariable ['MGIIncapTimer',nil,true]; }; "; MGI_fn_911 = compileFinal " params ['_wnded','_medic','_timer']; [_wnded,_medic,_timer] spawn MGI_fn_checkMedic; if (!isnull _medic) then { [_medic] joinSilent grpNull; uisleep (_medic getVariable ['MedicDelay',0.3]); if (lifeState _medic != 'incapacitated' && alive _medic) then { if (MGI_whiteFlag) then { _medic forceFlagTexture '\A3\Data_F\Flags\Flag_white_CO.paa'; }; _medic setCaptive true; {_medic disableAI _x} count ['target','autotarget','autocombat','suppression']; group _medic setBehaviour 'CARELESS'; _medic allowFleeing 0; _offset = [[0,0],[15, _wnded getRelDir _medic]] select (!isNull objectParent _medic); if (!isnull objectParent _medic) then { _medic setVariable ['veh',objectParent _medic,true]; if (!isPlayer driver objectParent _medic && _medic != assignedGunner objectParent _medic) then { unassignVehicle _medic; doGetOut _medic}; }; _wp = group _medic addwaypoint [_wnded getpos _offset,0]; _wp setWaypointType 'MOVE'; uiSleep 0.5; if (isnull objectParent _medic) then { [_wp,'FULL'] remoteExec ['setWaypointSpeed',2]; } else { [_wp,'LIMITED'] remoteExec ['setWaypointSpeed',2]; }; _wp showWaypoint 'NEVER'; uiSleep 3; waitUntil {Sleep 0.5; (currentWaypoint group _medic == count waypoints group _medic && canMove vehicle _medic) or (driver vehicle _medic != _medic) or (diag_tickTime > _timer + MGI_BleedOut && lifeState _wnded == 'incapacitated')}; if ((diag_tickTime > _timer + MGI_BleedOut) && lifeState _wnded == 'incapacitated') exitWith {}; if (driver vehicle _medic != _medic or !canMove vehicle _medic) then { unassignVehicle _medic; doGetOut _medic; }; _wp = group _medic addwaypoint [getPosATL _wnded,0]; _wp setWaypointType 'MOVE'; [_wp,'FULL'] remoteExec ['setWaypointSpeed',2]; _wp showWaypoint 'NEVER'; }; }; waitUntil {uiSleep 1; currentWaypoint group _medic == count waypoints group _medic or {diag_tickTime > _timer + MGI_BleedOut && lifeState _wnded == 'incapacitated'}}; if ((diag_tickTime > _timer + MGI_BleedOut) && lifeState _wnded == 'incapacitated') exitWith {}; if (isNull _medic or lifeState _medic == 'incapacitated' or !alive _medic) then { if (!isNull _medic) then {_medic call MGI_fn_medicRelease}; _wnded spawn MGI_fn_unconscious; }; "; MGI_fn_death = compileFinal " params ['_wnded']; if (_wnded getVariable ['uncsious',false]) then { _wnded setVariable ['uncsious',false,true]; _wnded setVariable ['MGIIncapTimer',nil,true]; }; if (!isnil {_wnded getVariable 'myMedic'}) then { (_wnded getVariable 'myMedic') setVariable ['myPatient',nil,true]; _wnded setVariable ['myMedic',nil,true]; }; comment "" if (local _wnded) then { _wnded playMoveNow '' } else { [_wnded,''] remoteExec ['playMoveNow',_wnded] } ""; if (!(_wnded call BIS_fnc_reviveEnabled)) then { [_wnded,false] remoteExec ['setUnconscious',_wnded]; }; if (!isMultiplayer && isplayer _wnded) then { _wnded setDamage 0; uiSleep 12; _wnded setCaptive false; } else { _wnded setDamage 1; }; "; MGI_fn_Revive = { MGI_react = "react" call BIS_fnc_getParamValue; MGI_BleedOut = "bleedOut" call BIS_fnc_getParamValue; MGI_AiRevive = "NoReviveforAi" call BIS_fnc_getParamValue; MGI_AIKit = "AIKit" call BIS_fnc_getParamValue; MGI_AIMedicTrait = "AIMedicTrait" call BIS_fnc_getParamValue; MGI_canHealExtraGrp = "canHealExtraGrp" call BIS_fnc_getParamValue; MGI_bros = ["bros",-1] call BIS_fnc_getParamValue; MGI_whiteFlag = "whiteFlag" call BIS_fnc_getParamValue; if (MGI_react == 0) then {MGI_react = 20}; if (MGI_BleedOut == 0) then {MGI_BleedOut = 120}; MGI_AiRevive = if (MGI_AiRevive == 0) then [{true},{false}]; MGI_AIMedicTrait = if (MGI_AIMedicTrait == 0) then [{false},{true}]; if (MGI_canHealExtraGrp == 0) then {MGI_canHealExtraGrp = 1}; if (MGI_bros == -1 or !isMultiplayer) then {MGI_bros = switchableUnits+playableUnits}; if (MGI_whiteFlag == 0) then {MGI_whiteFlag = false}; params [["_react",MGI_react,[0]],["_bleedOut",MGI_BleedOut,[0]],["_AiRevive",MGI_AiRevive,[true]],["_kit",MGI_AIKit,[0]],["_AIMedicTrait",MGI_AIMedicTrait,[true]],["_canHealExtraGrp",MGI_canHealExtraGrp,[0]],["_MGI_bros",MGI_bros,[[],WEST,objNull,grpNull]],["_white_flag",false,[true]]]; MGI_react = _react; MGI_BleedOut = _bleedOut; MGI_AiRevive = _AiRevive; MGI_AIKit = _kit; MGI_AIMedicTrait = _AIMedicTrait; MGI_canHealExtraGrp = _canHealExtraGrp; if (MGI_bros isEqualType 0) then { MGI_bros = [switchableUnits+playableUnits,WEST] select ("bros" call BIS_fnc_getParamValue); } else { MGI_bros = _MGI_bros }; MGI_whiteFlag = _white_flag; [] spawn { params ["_bros","_side"]; private _isEvolving = 0; while {isServer} do { call { if (MGI_bros isEqualType WEST or _isEvolving == 1) exitWith { if (_isEvolving == 0) then {_side = MGI_bros}; _isEvolving = 1; {_x setVariable ["passedBros",true,true]} forEach (allUnits select {(side _x == _side) && isnil {_x getVariable "passedBros"} && _x != (missionNamespace getVariable [format ["BIS_SUPP_HQ_%1",MGI_bros],objNull]) && _x isKindOf "CAManBase"}); }; if ( _isEvolving == 2 or {MGI_bros isEqualTo (switchableUnits + playableUnits)}) exitWith { _isEvolving = 2; {_x setVariable ["passedBros",true,true]} forEach ((switchableUnits + playableUnits) select {isnil {_x getVariable "passedBros"}}); }; if (MGI_bros isEqualType objNull or MGI_bros isEqualType grpNull) exitWith { {_x setVariable ["passedBros",true,true]} forEach (units MGI_bros select {isNil {_x getVariable "passedBros"}}); }; if (MGI_bros isEqualTypeAll objNull) then { {_x setVariable ["passedBros",true,true]} forEach (MGI_bros select {isnil {_x getVariable "passedBros"}}); }; }; _bros = allUnits select {(_x getVariable "passedBros")}; MGI_bros = +_bros; publicVariable "MGI_bros"; if (isNil "MGI_HealWarning" && {time > 120 && count MGI_bros <2}) then { MGI_HealWarning = true; systemChat "Not enough unit to heal each other here!"; systemChat "if bro is just an unique unit, this unit can respawn (SP/MP)"; systemChat "For any other aim, check your parameters!"; }; MGI_potentialMedic = MGI_bros select { [true,{_x == "FirstAidKit"} count (items _x) >0,{_x == "MediKit"} count (items _x) >0] select MGI_AIKit && [true,_x getUnitTrait "Medic"] select MGI_AIMedicTrait }; publicVariable "MGI_potentialMedic"; { if (isnil {_x getVariable "passEH"}) then { _x setVariable ["passEH",true,true]; [_x,MGI_fn_EHDamage] remoteExec ["call",0,true]; }; if (lifeState _x != "incapacitated" && animationState _x in ["unconsciousfaceup","unconsciousfacedown"]) then {[_x,""] remoteExec ["switchMove"]}; if (lifeState _x == "incapacitated" && !(["uncon",animationState _x] call bis_fnc_inString)) then { [_x,"Acts_InjuredCoughRifle02"] remoteExec ["switchMove"] }; } forEach _bros; {_check = _x; if (!isnil {_check getVariable "myPatient"} && {_x getVariable "myMedic" == _check} count MGI_bros == 0) then { _check setVariable ["myPatient",nil,true]; if (MGI_whiteFlag) then {_check forceFlagTexture ""}; } } forEach MGI_potentialMedic; uiSleep 5; }; }; }; [20,120,true,0,false,1,west,true] call MGI_fn_Revive; /* example in last line Totally reworked (see below). EDITED: version with added parameter (see spoiler above. Should work fine in MP. Feedback welcome. Added possibility for multiple call lines. Last version with waypoints instead of domove + added parameter "white flag". Added one check more for distance form medic to wounded. What's a bro? - A bro is a unit (AI or player) who can be revived while unconscious, if some conditions are met (hard coded like within 200 m of another bro, or configured). In case of several healer candidates, the closer is elected. - That's also a unit able to heal unconscious unit (SP/MP) under the same conditions. But here, player(s) are not engaged in the process. They can heal but if an AI meet the conditions, this one will start the process. So, healer/healed is the same family: Bros. In which, the players are free to heal or not. How bros work (7th param or description.ext param class: bro ) - in SP, bros are switchable units by default. You can override this, passing a 7th param when calling MGI_fn_Revive, as shown in example (last code line). - in MP, * if bros class is present in description.ext, you can't override it; You have to choose one of the two settings: playable units or side player. Your description.ext should look like this (specifically for bros class): Spoiler class Params { class react { title = "reaction delay for providing assistance"; texts[] = {"0","10","20","30","60","120"}; values[] = {0,10,20,30,60,120}; default = 20; isGlobal = 1; }; class bleedout { title = "duration of unconsciousness before death/respawn (non including reaction delay above)"; texts[] = {"30","60","120","180","300","600"}; values[] = {30,60,120,180,300,600}; default = 120; isGlobal = 1; }; class NoReviveforAi { title = "friendly AI units (bros) can be healed while unconscious"; texts[] = {"no","yes"}; values[] = {1,0}; default = 0; isGlobal = 1; }; class AIKit { title = "Mandatory kit to heal"; texts[] = {"none","First aid kit","Medic kit"}; values[] = {0,1,2}; default = 0; isGlobal = 1; }; class AIMedicTrait { title = "Medic trait mandatory"; texts[] = {"no","yes"}; values[] = {0,1}; default = 0; isGlobal = 1; }; class canHealExtraGrp { title = "Ai bro can heal some other bros not belonging to player's group"; texts[] = {"no, heal his own group only","his group, and other players only","sure! all possible Bros"}; values[] = {0,1,2}; default = 1; isGlobal = 1; }; class bros { title = "Who are bros?"; texts[] = {"all players","WEST"}; values[] = {0,1}; default = 0; isGlobal = 1; }; class whiteFlag { title = "White flag on the healing bros"; texts[] = {"no","yes"}; values[] = {0,1}; default = 0; isGlobal = 1; }; }; Bros = all players as default parameter means you can have different side and bros can heal anywhere.. if conditions are met. Keep on mind that disabled AI (slots) in lobby don't have existence and playableUnits = allPlayers (all playing guys), and not all playable units as in editor. So, each time you can let the slot as AI enabled, it's better. The list is updated anyway. The other possible parameter is set as WEST here. * if these parameters are not fine for your scenario, you can modify the bros class but you have to change the working line referring to your values: In the main function MGI_fn_Revive, look for: if (MGI_bros isEqualType 0) then { MGI_bros = [switchableUnits+playableUnits, WEST] select ("bros" call BIS_fnc_getParamValue); <<<<< THIS LINE CAN BE MODIFIED: [<your default array of bros>,<another choice>] select ("bros" call BIS_fnc_getParamValue) } else { MGI_bros = _MGI_bros }; * You can also delete the bros class in description.ext, and sets the 7th parameter as shown in the following example: [nil,nil,nil,nil,nil,nil,east] call MGI_fn_Revive; This way, here EAST will take place of the missing (and non over-writable) bros class. The other parameters are set to nil, for not overriding the other existing classes. * Don't forget, there is nothing mandatory, neither description.ext parameters, nor function parameters (See default above). You can add any unit in "bros" team, just setting a variable: yourUnit (or cursorTarget) setVariable ["passedBros",true,true]; Extra Examples: call MGI_fn_Revive // parameters are default ones, or defined by your description.ext: standard usage in MP (allowing parameters in description.ext) [nil,nil,nil,nil,nil,nil,east] call MGI_fn_Revive; // MP reworked/added side , class bros removed, other classes in description.ext [30,60,true,0,false,1,independent] call MGI_fn_Revive; // this will override the mission MP parameters in lobby, except the independent if bros class exist! Better usage for SP or even, in MP: [nil,nil,nil,nil,nil,nil,west,false] call MGI_fn_Revive; sleep 2; [nil,nil,nil,nil,nil,nil,east,false] call MGI_fn_Revive; Don't forget! bros class must be inactive/deleted in description.ext 17 3 Share this post Link to post Share on other sites
Mokka 29 Posted July 15, 2017 Ohhhh, this looks promising! I'll play around with this once I get some time c: Thanks for sharing, pierre Share this post Link to post Share on other sites
Leopard20 813 Posted July 17, 2017 On 7/16/2017 at 0:31 AM, pierremgi said: AI REVIVE/HEAL SP/MP Hi all, Here is a script to allow AIs reviving and healing bros, according to parameters. This works in SP or MP. Compatible so far with AI RESPAWN script (see tag) Don't override the respawn system (MP) Incapacitation: This script relies on incapacitated status for players or AIs. This status is created when not existing (SP, or MP Ais) to allow revive scenario. parameters: REACT DELAY / HEAL DELAY / AI CAN REVIVE / KIT NEEDED / NEED MEDIC / BROS Parameters can be added to description.ext, class Params, just add what you want in classes: "react" "bleedOut" "noReviveForAI" "AiKit" "AiMedic" "bros". So you can choose them while in lobby. Anyway, if you pass parameters calling the function, these params will override the lobby ones. Reveal hidden contents [ <number, seconds (max) to choose the best healer>, // example: 15 (optional) default: 120 During this time, the script tries to find the best healer according to some priorities: not in combat, not targeting, a medic, any bro within 200 m (if any according to other parameters) <number, seconds (max) to heal action, remaining bleedout>, // example: 60 (optional) default: 120 This amount of time is added to the first one. So, healer found or not, this is the remaining time before death unless be revived. <boolean, AI CAN REVIVE>, // example: true (optional) default: true In SP/MP, if false, the AI can't revive but can heal the player (incapacitated). Note that AIs playable units can respawn in MP (Arma engine) <number, what kind of kit is needed to revive someone>, // example: 0 (optional) default: 0 0: not kit needed, no limit for revive 1: need a first aid kit (FAK) , 1 FAK is removed per reviving action 2: need a medic kit (mediKit) , 1 FAK is removed per reviving action, can heal even if no more FAK <boolean, Medic trait mandatory> // example: true (optional) default: false When true, this limits drastically the chance to be revived. <side or array of units>, // example: west (optional) default: playableUnits + switchableUnits Just decide who can be healed and revive. The default param works in SP/MP some custom arrays are working fine also: [blu1,blu2,indep1,indep2] or allUnits select {_x inArea some trigger && side _x == WEST} You can mix several sides but it's weird to make enemies as bros, with never ending shoot/heal loops! ] Examples: call MGI_fnc_AICareandRevive // parameters are default ones, or defined by your description.ext [30,60,true,0,false,west] call MGI_fnc_AICareandRevive; // this will override the MP parameters chosen in lobby! Better usage for SP Code to be run on server, but already server only oriented. So, init.sqf, (trigger, non-repeatable, condition true) or initServer.sqf... Reveal hidden contents fn_medicRelease = { _medic = _this; _medic setVariable ["MGImedic",false]; [_medic] joinSilent (_medic getVariable ["grp",grpNull]); _medic doFollow leader _medic; _medic setSpeedMode (speedMode group _medic); {_medic enableAI _x} count ["target","autotarget","autocombat","suppression"]; _medic allowFleeing (1 - (_medic getVariable ["flee",0.5])); }; MGI_fnc_AICareandRevive = { if (isServer) then { MGI_react = "react" call BIS_fnc_getParamValue; MGI_BleedOut = "bleedOut" call BIS_fnc_getParamValue; MGI_AiRevive = "NoReviveforAi" call BIS_fnc_getParamValue; MGI_AIKit = "AIKit" call BIS_fnc_getParamValue; MGI_AIMedic = "AIMedic" call BIS_fnc_getParamValue; MGI_bros = "bros" call BIS_fnc_getParamValue; if (MGI_react == 0) then {MGI_react = 120}; if (MGI_BleedOut == 0) then {MGI_BleedOut = 120}; if (MGI_AiRevive == 0) then {MGI_AiRevive = true}; if (MGI_AIMedic == 0) then {MGI_AIMedic = false}; if (MGI_bros == 0) then {MGI_bros = switchableUnits+playableUnits}; params [["_react",MGI_react,[0]],["_bleedOut",MGI_BleedOut,[0]],["_AiRevive",MGI_AiRevive,[true]],["_kit",MGI_AIKit,[0]],["_AiMedic",MGI_AIMedic,[true]],["_MGI_bros",MGI_bros,[[],WEST]]]; MGI_react = _react; MGI_BleedOut = _bleedOut; MGI_AiRevive = _AiRevive; MGI_AIKit = _kit; MGI_AIMedic = _AiMedic; if (_MGI_bros isEqualType WEST) then {_bros = allUnits select {side _x == _MGI_bros}; _MGI_bros = +_bros}; MGI_bros = _MGI_bros; { _unit = _x; _unit addEventHandler ["HandleDamage", { _wnded = _this select 0; _dam = _this select 2; if (side _wnded != sideEnemy && _dam > 0.85) then { if (((!isMultiplayer or !isPlayer _wnded) && MGI_AiRevive) or (!isMultiplayer && isPlayer _wnded && !MGI_AiRevive)) then { _wnded setUnconscious true; if (!isNull objectParent _wnded) then { _wnded setPos getpos vehicle _wnded }; }; _wnded spawn { _wnded = _this; _timerUnc = diag_tickTime; waitUntil {sleep 0.5; lifeState _wnded == "incapacitated" or diag_tickTime > _timerUnc + 2}; if (lifeState _wnded == "incapacitated" && !(_wnded getVariable ["treat",false])) then { _wnded setVariable ["treat",true]; _wnded setCaptive true; private _fellows = (MGI_bros select { _x isKindOf "CAManBase" && _x distanceSqr _wnded < 40000 && alive _x && lifeState _x != "incapacitated" && !(_x getVariable ["MGImedic",false])}) - [_wnded]; _fellows = _fellows select { [true,{_x == "FirstAidKit"} count (items _x) >0,{_x == "MediKit"} count (items _x) >0] select MGI_AIKit && [true,_x getUnitTrait "Medic"] select MGI_AIMedic }; call { if ({behaviour _x != "COMBAT"} count _fellows > 0) exitWith { uiSleep (MGI_react/4); _fellows = _fellows select {behaviour _x != "COMBAT"}}; if ({(_x targets [true, 300]) isEqualTo []} count _fellows > 0) exitWith { uiSleep (MGI_react/2); _fellows = _fellows select {(_x targets [true, 300]) isEqualTo []}}; if ({{_x == "MediKit"} count (items _x) > 0} count _fellows > 0) exitWith { uiSleep MGI_react;_fellows = _fellows select {{_x == "MediKit"} count (items _x) > 0}}; _fellows; }; if (count _fellows > 0) then { _fellows = _fellows apply {[_x distance _wnded, _x]}; _fellows sort true; _medic = _fellows select 0 select 1; _medic setVariable ["MGImedic",true]; _medic setCaptive true; _medic setVariable ["flee",_medic skill "courage"]; _medic setVariable ["grp", group _medic]; [_medic] joinSilent grpNull; {_medic disableAI _x} count ["target","autotarget","autocombat","suppression"]; group _medic setBehaviour "AWARE"; _medic allowFleeing 0; _offset = [[0,0],[15, _wnded getRelDir _medic]] select (!isNull objectParent _medic); if (!isnull objectParent _medic) then { _medic setVariable ["veh",vehicle _medic]; if (assignedDriver vehicle _medic != _medic) then { unassignVehicle _medic; doGetOut _medic; }; }; _medic doMove (_wnded getpos _offset); sleep 1; if (isnull objectParent _medic) then { group _medic setSpeedMode "FULL" } else { group _medic setSpeedMode "LIMITED" }; [_medic,_wnded] spawn { params ["_medic","_wnded"]; _timerTreat = diag_tickTime; vehicle _medic disableCollisionWith _wnded; uisleep 1; waitUntil {sleep 0.5; unitReady vehicle _medic or !alive _wnded or diag_tickTime > _timerTreat + MGI_BleedOut or (unitReady vehicle _medic && canmove vehicle _medic && !isnull objectParent _medic)}; if ((diag_tickTime > _timerTreat + MGI_BleedOut) or !alive _wnded) then { if (alive _wnded) then { _wnded setUnconscious false; _wnded setDamage 1 }; _medic call fn_medicRelease; _wnded setVariable ["treat",false]; sleep 10; _wnded setCaptive false; _medic setCaptive false; } else { doStop _medic; if (!isnull objectParent _medic) then { unassignVehicle _medic; doGetOut _medic; }; _medic doMove getpos _wnded; group _medic setSpeedMode "FULL"; Sleep 1; waitUntil {sleep 0.5; unitReady _medic or !alive _wnded or diag_tickTime > _timerTreat + MGI_BleedOut}; if (alive _wnded && diag_tickTime < _timerTreat + MGI_BleedOut) then { _azimuth = _medic getDir _wnded; _medic setDir _azimuth; _medic removeitem "FirstAidKit"; call { if (!isPlayer _wnded) exitWith { call { if (unitPos _medic == "DOWN") exitWith { _medic playMove "ainvppnemstpslaywrfldnon_medicother"; }; _medic playMove "ainvpknlmstpslaywrfldnon_medicother"; }; Sleep 4; _wnded setUnconscious false; _wnded setDamage 0; }; _medic action ["HealSoldier", _wnded]; sleep 4; [_wnded,{ _wnded = _this; BIS_oldLifeState == "HEALTY"; _wnded setVariable ["#rev_state",0]; _wnded setVariable ["#rev_blood",1]; _wnded setVariable ["bis_revive_incapacitated",false]; _wnded setVariable ["#rev",0]; _wnded setVariable ["#revl",-1], {inGameUISetEventHandler [_x, ""]} forEach ["PrevAction", "NextAction"]; _wnded setUnconscious false; _wnded setDamage 0; }] remoteExec ["call",_wnded]; }; _wnded setVariable ["treat",false]; _medic call fn_medicRelease; if (!isnil {_medic getVariable "veh"}) then { _medic assignAsDriver (_medic getVariable "veh"); }; sleep 10; vehicle _medic enableCollisionWith _wnded; _wnded setCaptive false; _medic setCaptive false; }; }; }; } else { _timerTreat = diag_tickTime; waitUntil {sleep 0.5; !alive _wnded or diag_tickTime > _timerTreat + MGI_BleedOut}; if (alive _wnded) then { _wnded setUnconscious false; _wnded setDamage 1 }; }; }; }; if ((((!isMultiplayer or !isPlayer _wnded) && MGI_AiRevive) or (!isMultiplayer && !MGI_AiRevive && isPlayer _wnded)) && !(_wnded getVariable ["treat",false])) then {_dam min 0.95} else {_dam}; }; }] } forEach _MGI_bros; }; }; [30,60,true,0,false,west] call MGI_fnc_AICareandRevive; Nice. Can you make an addon version too? Share this post Link to post Share on other sites
pierremgi 4875 Posted July 17, 2017 Yes. Planned but not immediately. I'm looking for some feedback. My addons are usually "player oriented" (HUD, fatigue...) This code is for server. I can imagine what to do on a hosted one. Hosting player must have it. On the other hand, i'm lookng for the best way to make it for any server. In other words, how to install an addon on a dedicated one. Share this post Link to post Share on other sites
C.Hall 3 Posted July 26, 2017 Hello, and thank you for the script. I am having an issue with testing this. As soon as one of my team is injured or incapacitated by enemy AI, I lose leadership of the team. Thoughts? Also, as the player, when I get shot, I do not become disabled, I just die. Share this post Link to post Share on other sites
pierremgi 4875 Posted July 26, 2017 Probably because you're the nearest available "medic" (according to parameters). So, medic quits the group for healing then regroup after action. corrected For your own player death, no problem on SP. You'll be incapacitated if damage > 0.85 (like for MP Arma engine). For MP, don't forget to allow the revive settings in mission parameters. Without MP revive, the engine kill you. I'm not overriding these settings, just adding some behavior for AI units. With revive settings, players can heal each others. If mono multiplayer, the player will be healed: - if not too badly hurt (according to revive options) - an AI is free to be healer. In harsh combat, there are some cases, nobody will come. :( Share this post Link to post Share on other sites
launchpadmcquack 10 Posted July 29, 2017 I just started making my own missions do you have a template with this? Share this post Link to post Share on other sites
pierremgi 4875 Posted July 29, 2017 1 hour ago, launchpadmcquack said: I just started making my own missions do you have a template with this? What for? Just make your mission. Add a trigger (or write an sqf called (execVM) somewhere), If trigger (no area): condition: true (instead of this), on activation, copy/paste the code, last line, change parameters as you want. (see spoiler). Share this post Link to post Share on other sites
Jnr4817 215 Posted August 31, 2017 I am wondering if I can add this to the default tanoa ghost mission without to much trouble. Ghost Missions Any advice would be greatful. We were using ins_revive and ai_revive, but they aren't supported anymore and giving lots of errors. Thanks Share this post Link to post Share on other sites
pierremgi 4875 Posted August 31, 2017 If there is no double revive feature (for AIs), i guess this could work. Share this post Link to post Share on other sites
Jnr4817 215 Posted August 31, 2017 I added a MGI_fnc_AICareandRevive.sqf to mission folder in a scripts folder then added //SA AI Revive //parameters are default ones execVM "sa\scripts\MGI_fnc_AICareandRevive.sqf" To init.server No issues so far. The description.ext espawn = "BASE"; respawnDelay = 5; respawnTemplates[] = {"MenuPosition","Ghst_recover_gear"};//,"menuInventory" respawnOnStart = -1; ReviveMode = 1; //0: disabled, 1: enabled, 2: controlled by player attributes ReviveUnconsciousStateMode = 0; //0: basic, 1: advanced, 2: realistic ReviveRequiredTrait = 0; //0: none, 1: medic trait is required ReviveRequiredItems = 2; //0: none, 1: medkit, 2: medkit or first aid kit ReviveRequiredItemsFakConsumed = 1; //0: first aid kit is not consumed upon revive, 1: first aid kit is consumed ReviveDelay = 6; //time needed to revive someone (in secs) ReviveMedicSpeedMultiplier = 2; //speed multiplier for revive performed by medic ReviveForceRespawnDelay = 5; //time needed to perform force respawn (in secs) ReviveBleedOutDelay = 180; //unconscious state duration (in secs) disabledAI = 1; corpseManagerMode = 1; //Type of removed bodies: 0 - none, 1 - all, 2 - only respawnable, 3 - only non-respawnable corpseLimit = 20; //Max number of bodies which can be available at the same time. When exceeded, start deleting immediately. corpseRemovalMinTime = 120; //Minimal time in seconds a body stays in the scene (can't be removed sooner). corpseRemovalMaxTime = 240; //Maximal time in seconds after which a dead body is removed (can't stay longer) wreckManagerMode = 1; //Type of removed wrecks: 0 - none, 1 - all, 2 - only respawnable, 3 - only non-respawnable wreckLimit = 20; //Max number of wrecks which can be available at the same time. When exceeded, start deleting immediately. wreckRemovalMinTime = 120; //Minimal time in seconds a wreck stays in the scene (can't be removed sooner). wreckRemovalMaxTime = 240; //Maximal time in seconds after which a wreck is removed (can't stay longer) Im sure your scipt is overriding some of these parameters in the .ext, I was just hoping your script improved how the AI revived each other and the players. Thanks Share this post Link to post Share on other sites
pierremgi 4875 Posted August 31, 2017 The script is compatible with your description.ext parameters. There are 6 parameters for that. The way AIs must be revived is the same parameter as Arma's engine for players (damage > 0.85) . If you want more chances to have unconscious guys decrease this value. A second shot on an unconscious guy can kill him. Share this post Link to post Share on other sites
reaper lok 82 Posted September 8, 2017 On 8/31/2017 at 2:22 PM, pierremgi said: The script is compatible with your description.ext parameters. There are 6 parameters for that. The way AIs must be revived is the same parameter as Arma's engine for players (damage > 0.85) . If you want more chances to have unconscious guys decrease this value. A second shot on an unconscious guy can kill him. Will this work if I am running ACE3? It would be great to have my AI teammate use an Epi-pin on me to wake me up or bandage me if wounded etc. Share this post Link to post Share on other sites
pierremgi 4875 Posted September 8, 2017 22 minutes ago, reaper lok said: Will this work if I am running ACE3? It would be great to have my AI teammate use an Epi-pin on me to wake me up or bandage me if wounded etc. I don't know. Probably. Share this post Link to post Share on other sites
Bajomundo 1 Posted September 11, 2017 Hi, good job man =) i'm new in Arma 3 and a noob with scripts but it works really great to me. I found a situation, 4 soldiers, 1 of them is a medic and he is the only one with FAKs (what is needed to revive according to my settings), when i shoot at two of them the medic leave the group to go there and revive both at the same time, not rlly bad, but when he finish, he doesn´t regroup =/ . Any idea how can i fix that without a zone trigger?? Ty =D On 7/9/2017 at 10:10 PM, reaper lok said: Will this work if I am running ACE3? It would be great to have my AI teammate use an Epi-pin on me to wake me up or bandage me if wounded etc. I read a loot and unfortunatly ACE mod is more for MP so AI can't heal you with the advanced system..what i did? Remove some medic files from ACE folder and then the Vanilla medic system is working again, and works really good with this script. 1 Share this post Link to post Share on other sites
Dewaine_870 1 Posted September 15, 2017 I cant open the reveal contents to get the code. What have I done wrong? Share this post Link to post Share on other sites
pierremgi 4875 Posted September 15, 2017 22 minutes ago, Dewaine_870 said: I cant open the reveal contents to get the code. What have I done wrong? Works for me. I don't know. Any problem with some other ones? Share this post Link to post Share on other sites
Dewaine_870 1 Posted September 15, 2017 11 minutes ago, pierremgi said: Works for me. I don't know. Any problem with some other ones? *Fixed* Was using chrome didn't work. Tried Firefox and it worked. 1 Share this post Link to post Share on other sites
Jnr4817 215 Posted January 8, 2018 When using this, is there a way to have a High command function for the player with an AI medic in his group to select the AI medic and then "Heal Brothers" The "Heal Brothers" command would then make the AI medic or any AI with a medkit or firstaid kit heal any down player or AI that are down around them. For example, I join the server. I recruit a 4 man team. One person is a medic, but all will have firstaid kits. I give the command for the AI medic to heal any down brother when needed via HC. We get engaged and I the player and leader of group gets hit and goes down. The medic then heals me or another ai with first aid kit, whoever is closer. Auto_Revive is the best way to explain it. Currently, we are still using the INS_Revive Script by Naong and a custom AI Revive by Duda from our team. Spoiler SA_fnc_moveGroupLocal = { private ["_target", "_group"]; _group = [_this,0] call BIS_fnc_param; _target = [_this,1] call BIS_fnc_param; if(vehicle (leader _group) != (leader _group)) then { _group leaveVehicle vehicle (leader _group); }; _group move (getPos _target); _group allowFleeing 0; }; SA_fnc_doReviveLocal = { private ["_medic", "_unit"]; _medic = [_this,0] call BIS_fnc_param; _unit = [_this,1] call BIS_fnc_param; [_unit,_medic] execVM 'INS_revive\revive\act_revive.sqf'; }; SA_fnc_isRevivable = { private ["_unit"]; _unit = [_this,0] call BIS_fnc_param; if( _unit getVariable ["INS_REV_PVAR_is_unconscious",false] && isNil {_unit getVariable "INS_REV_PVAR_who_taking_care_of_injured"} && alive _unit && vehicle _unit == _unit ) then { true; } else { false; }; }; SA_fnc_restoreGroupLeaderLocal = { private ["_group"]; _group = [_this,0] call BIS_fnc_param; _currentLeader = leader _group; _newLeader = _currentLeader; _newLeaderId = [_currentLeader] call SA_fnc_getUnitGroupId; { _id = [_x] call SA_fnc_getUnitGroupId; if( (_id < _newLeaderId || !isPlayer _newLeader) && isPlayer _x ) then { _newLeader = _x; _newLeaderId = _id; }; } forEach (units _group); _group selectLeader _newLeader; waitUntil { leader _group == _newLeader }; ((units _group)-[_newLeader]) joinSilent _group; }; SA_fnc_getUnitGroupId = { private ["_i", "_unit", "_ret","_group"]; _ret = false; _unit = [_this,0] call BIS_fnc_param; _group = group _unit; _i = 0; while {!_ret AND _i <= 32} do { _i = _i + 1; if (format ["%1",_unit] == format["%1:%2", _group, _i]) then {_ret = true;}; if (_unit == player) then {if(format ["%1",_unit] == format["%1:%2 (%3)", _group, _i, name _unit]) then {_ret = true;};}; }; _i }; if(!isDedicated) then { player addEventHandler ["Respawn", {[[group player],"SA_fnc_restoreGroupLeaderLocal",group player] spawn BIS_fnc_MP}]; }; if(isServer) then { SA_fnc_availableAiMedics = { private ["_unit", "_group", "_medic_requested","_nearUnits","_availableAiMedicsWithMedkits","_possibleMedic"]; _unit = [_this,0] call BIS_fnc_param; _group = group _unit; _availableAiMedics = []; { { _possibleMedic = _x; //diag_log format ["Possible Medic: %1, %2, %3, %4", !isPlayer _possibleMedic, alive _possibleMedic, !(_possibleMedic getVariable "INS_REV_PVAR_is_unconscious"), _possibleMedic isKindOf "Man"]; if( !isPlayer _possibleMedic && alive _possibleMedic && (_possibleMedic getVariable ["SA_auto_revive",false] || !isPlayer (leader _possibleMedic) || leader _possibleMedic == _unit ) && ((_possibleMedic getVariable ["SA_auto_revive_count",0]) > 0 || !isPlayer (leader _possibleMedic) || leader _possibleMedic == _unit ) && !(_possibleMedic getVariable ["INS_REV_PVAR_is_unconscious",false]) && _possibleMedic isKindOf "Man" ) then { if( not (_possibleMedic in _availableAiMedics) ) then { if( leader _possibleMedic == _possibleMedic || driver (vehicle _possibleMedic) == _possibleMedic || commander (vehicle _possibleMedic) == _possibleMedic ) then { _availableAiMedics = [_availableAiMedics, [_possibleMedic]] call BIS_fnc_arrayPushStack; } else { _availableAiMedics = [[_possibleMedic], _availableAiMedics] call BIS_fnc_arrayPushStack; }; }; }; } forEach (crew _x); } forEach ([getPos _unit, 60, {West == side _x}] call SA_fnc_getNearEntities); if (INS_REV_CFG_require_medkit) then { _availableAiMedicsWithMedkits = []; { private ["_uniformItems","_vestItems","_backpackItems","_itemList"]; _uniformItems = uniformItems _x; _vestItems = vestItems _x; _backpackItems = backpackItems _x; _itemList = _uniformItems + _vestItems + _backpackItems; if ("FirstAidKit" in _itemList) then { _availableAiMedicsWithMedkits pushBack _x; }; } forEach _availableAiMedics; _availableAiMedicsWithMedkits; } else { _availableAiMedics; }; }; [] spawn { private ["_revivableUnits","_unit","_medic","_unitGroup","_reviveTarget","_all_medics_requested","_medics_to_remove","_newGroup","_medic_requested"]; _all_medics_requested = []; while {true} do { _revivableUnits = []; { if([_x] call SA_fnc_isRevivable) then { _revivableUnits pushBack _x; }; } forEach allUnits; //hint format ["%1", _revivableUnits]; { _unit = _x; //diag_log format ["Avail Medics: %1", [_unit] call SA_fnc_availableAiMedics]; { _medic = _x; if( _medic distance _unit < 50 && [_unit] call SA_fnc_isRevivable && isNull (_medic getVariable ["revive_target",objNull]) && ( isNull (_unit getVariable ["medic_requested",objNull]) || !alive (_unit getVariable ["medic_requested",_unit]) ) ) then { //diag_log format ["Medic Requested: %1", _medic]; _unit setVariable ["medic_requested", _medic]; _medic setVariable ["original_group", group _medic]; _medic setVariable ["original_team", assignedTeam _medic]; _medic setVariable ["revive_target", _unit]; _medic setVariable ["start_time_sec", diag_tickTime]; _medic setVariable ["SA_auto_revive_count", (_medic getVariable ["SA_auto_revive_count",1]) - 1, true]; if(count (units group _medic) > 1) then { _newGroup = createGroup (side _medic); [_medic] join _newGroup; } else { _newGroup = group _medic; }; [[_newGroup,_unit],"SA_fnc_moveGroupLocal",_medic] spawn BIS_fnc_MP; _all_medics_requested pushBack _medic; }; } forEach ([_unit] call SA_fnc_availableAiMedics); _medic_requested = _unit getVariable ["medic_requested",objNull]; if( !isNull _medic_requested && _medic_requested distance _unit < 8 && [_unit] call SA_fnc_isRevivable && alive _medic_requested) then { [[_medic_requested,_unit],"SA_fnc_doReviveLocal",_medic_requested] spawn BIS_fnc_MP; }; } forEach _revivableUnits; _medics_to_remove = []; { _medic = _x; _reviveTarget = _medic getVariable ["revive_target",objNull]; //diag_log format ["%1, %2, %3, %4", !isNull _reviveTarget, not ([_reviveTarget] call SA_fnc_isRevivable), !alive _medic, _medic]; if( (!isNull _reviveTarget && not ([_reviveTarget] call SA_fnc_isRevivable)) || ( !alive _medic) ) then { [_medic] joinSilent (_medic getVariable "original_group"); [_medic,(_medic getVariable "original_team")] remoteExec ["assignTeam"]; _medic setVariable ["original_group", nil]; _medic setVariable ["original_team", nil]; _medic setVariable ["revive_target",objNull]; _reviveTarget setVariable ["medic_requested", objNull]; _medics_to_remove pushBack _medic; } else { _start_time = _medic getVariable ["start_time_sec", diag_tickTime]; if( diag_tickTime - _start_time > 60 ) then { [_medic] joinSilent (_medic getVariable "original_group"); [_medic,(_medic getVariable "original_team")] remoteExec ["assignTeam"]; _medic setVariable ["original_group", nil]; _medic setVariable ["original_team", nil]; _medic setVariable ["revive_target",objNull]; _reviveTarget setVariable ["medic_requested", objNull]; _medics_to_remove pushBack _medic; }; }; } forEach _all_medics_requested; if(count _medics_to_remove > 0) then { //diag_log format ["Medics Removed: %1", _medics_to_remove]; _all_medics_requested = _all_medics_requested - _medics_to_remove; //diag_log format ["Medics Remaining: %1", _all_medics_requested]; }; sleep 5; }; }; }; if(isServer) then { [] spawn { private ["_tempGroup","_tempGroupLeader","_newUnit"]; private ["_lastLoadOut", "_lastGroup","_unitType","_position","_lastTeam"]; _tempGroup = createGroup West; _tempGroupLeader = _tempGroup createUnit ["LOGIC",[0, 0, 0] , [], 0, ""]; private ["_allFriendlyAiUnits"]; _allFriendlyAiUnits = []; while {true} do { { if ((side _x) == West && !(isPlayer _x)) then { _x setVariable ["SA_Last_Known_Loadout", [_x] call SA_fnc_getLoadout]; _x setVariable ["SA_Last_Known_Group", _x getVariable ["original_group",group _x]]; _x setVariable ["SA_Last_Known_Team", _x getVariable ["original_team",assignedTeam _x]]; _x setVariable ["SA_AI_Revive_Seen", true]; }; if (isPlayer _x && !(_x getVariable ["SA_AI_Revive_Is_Player",false])) then { _x setVariable ["SA_AI_Revive_Is_Player", true]; }; } forEach allUnits; { if ( !(_x getVariable ["SA_Handling_Revive",false]) && (_x getVariable ["SA_AI_Revive_Seen",false]) && !(_x getVariable ["SA_AI_Revive_Is_Player",false]) ) then { _x setVariable ["SA_Handling_Revive",true]; _lastLoadOut = _x getVariable ["SA_Last_Known_Loadout", nil]; _lastGroup = _x getVariable ["SA_Last_Known_Group", grpNull]; _lastTeam = _x getVariable ["SA_Last_Known_Team", "MAIN"]; _unitType = (format["%1", typeof _x]); _position = [(position _x) select 0, (position _x) select 1]; deleteVehicle _x; _newUnit = _tempGroup createUnit [_unitType, _position, [], 0, "CAN_COLLIDE"]; _newUnit setDir (random floor(random 361)); _newUnitMarker = [position _newUnit, "ColorRed", "AI is down"] call SA_fnc_createDotMarker; [_newUnit,"AinjPpneMstpSnonWrflDnon"] remoteExec ["switchMove"]; _newUnit disableAI "ANIM"; [_newUnit, false] call INS_REV_FNCT_allowDamage; if(!isNil "_lastLoadOut") then { [_newUnit,_lastLoadOut] call SA_fnc_setLoadout; }; _newUnit setVariable ["SA_Last_Known_Loadout", _lastLoadOut]; _newUnit setVariable ["SA_Last_Known_Group", _lastGroup]; _newUnit setVariable ["SA_Last_Known_Team", _lastTeam]; _newUnit setVariable ["SA_AI_Revive_Seen", true]; _newUnit setVariable ["INS_REV_PVAR_is_unconscious", true, true]; //_newUnit setVariable ["INS_REV_PVAR_playerSide", _side, true]; //_newUnit setVariable ["INS_REV_PVAR_playerGroup", _group, true]; _newUnit setVariable ["INS_REV_PVAR_who_taking_care_of_injured", nil, true]; _newUnit setVariable ["INS_REV_revived", false, true]; INS_REV_GVAR_start_unconscious = _newUnit; publicVariable "INS_REV_GVAR_start_unconscious"; ["INS_REV_GVAR_start_unconscious", _newUnit] call INS_REV_FNCT_add_actions; [_newUnit,_lastGroup,_newUnitMarker,_lastTeam] spawn { private ["_player", "_condition","_lastGroup","_newUnitMarker","_lastTeam","_isDead","_unconsciousStartTime"]; _player = _this select 0; _lastGroup = _this select 1; _newUnitMarker = _this select 2; _lastTeam = _this select 3; _condition = _player getVariable ["INS_REV_PVAR_is_unconscious",false]; _unconsciousStartTime = diag_tickTime; _isDead = false; while {_condition} do { _who_taking_care_of_injured = _player getVariable "INS_REV_PVAR_who_taking_care_of_injured"; // If somebody is taking care of you if !(isNil "_who_taking_care_of_injured") then { // If the one who taking care of you is not alive. if (isNull _who_taking_care_of_injured || !alive _who_taking_care_of_injured) then { // Reset player's state detach _player; if !(isNull _who_taking_care_of_injured) then {detach _who_taking_care_of_injured;}; [_player,"AinjPpneMstpSnonWrflDnon"] remoteExec ["switchMove"]; _player setVariable ["INS_REV_PVAR_who_taking_care_of_injured", nil, true]; }; }; // Check MEDEVAC vehicle if (INS_REV_CFG_medevac) then { if (_player != vehicle _player) then { if (alive vehicle _player) then { INS_REV_GVAR_is_loaded = true; INS_REV_GVAR_loaded_vehicle = vehicle _player; } else { [] call INS_REV_FNCT_unload; }; }; if (_player == vehicle _player && !isNil "INS_REV_GVAR_is_loaded" && {INS_REV_GVAR_is_loaded}) then { [] call INS_REV_FNCT_unload; }; }; sleep 3; _condition = _player getVariable "INS_REV_PVAR_is_unconscious"; [_player] call INS_REV_FNCT_prevent_drown; if(diag_tickTime - _unconsciousStartTime > (60 * ("PARAM_AIReviveLimit" call BIS_fnc_getParamValue))) then { _condition = false; _isDead = true; }; }; sleep 0.2; if(_isDead) then { deleteMarker _newUnitMarker; _player setVariable ["SA_Handling_Revive", true]; // Remove revive action INS_REV_GVAR_end_unconscious = _player; publicVariable "INS_REV_GVAR_end_unconscious"; ["INS_REV_GVAR_end_unconscious", INS_REV_GVAR_end_unconscious] spawn INS_REV_FNCT_remove_actions; _player enableAI "ANIM"; [_player, true] call INS_REV_FNCT_allowDamage; _player setDamage 1; } else { // Select primary weapon _player selectWeapon (primaryWeapon _player); // Remove revive action INS_REV_GVAR_end_unconscious = _player; publicVariable "INS_REV_GVAR_end_unconscious"; ["INS_REV_GVAR_end_unconscious", INS_REV_GVAR_end_unconscious] spawn INS_REV_FNCT_remove_actions; // Remove unload action if (!isNil "INS_REV_GVAR_is_loaded" && {INS_REV_GVAR_is_loaded} && INS_REV_CFG_medevac) then { INS_REV_GVAR_del_unload = [INS_REV_GVAR_loaded_vehicle, _player]; publicVariable "INS_REV_GVAR_del_unload"; ["INS_REV_GVAR_del_unload", INS_REV_GVAR_del_unload] spawn INS_REV_FNCT_remove_unload_action; INS_REV_GVAR_is_loaded = false; INS_REV_GVAR_loaded_vehicle = nil; }; [_player, true] call INS_REV_FNCT_allowDamage; _player setVariable ["INS_REV_PVAR_isTeleport", false, true]; _player setVariable ["INS_REV_PVAR_is_dead", false, true]; _player enableAI "ANIM"; [_player,"AmovPercMstpSrasWrflDnon"] remoteExec ["playMove"]; deleteMarker _newUnitMarker; [_player] joinSilent _lastGroup; [_player,_lastTeam] remoteExec ["assignTeam"]; }; }; }; } forEach allDeadMen; sleep 5; }; }; }; SA_fnc_enableAutoRevive = { private ["_units","_enabled","_count"]; _units = param [0,[]]; _enabled = param [1,false]; _count = param [2,1]; { if( !isPlayer _x) then { _x setVariable ["SA_auto_revive", _enabled, true]; _x setVariable ["SA_auto_revive_count", _count, true]; }; } forEach _units; }; //SA_CUSTOM_ACTION_MENU_SUBMENU = //[ // ["Action",true], // ["Option-1", [2], "", -5, [["expression", "player sidechat ""-1"" "]], "0", "0", "\ca\ui\data\cursor_support_ca"], // ["Option 0", [3], "", -5, [["expression", "player sidechat "" 0"" "]], "1", "0", "\ca\ui\data\cursor_support_ca"], // ["Option 1", [4], "", -5, [["expression", "player sidechat "" 1"" "]], "1", "CursorOnGround", "\ca\ui\data\cursor_support_ca"] //]; SA_CUSTOM_ACTION_MENU = [ // First array: "User menu" This will be displayed under the menu, bool value: has Input Focus or not. // Note that as to version Arma2 1.05, if the bool value set to false, Custom Icons will not be displayed. ["Action",false], // Syntax and semantics for following array elements: // ["Title_in_menu", [assigned_key], "Submenu_name", CMD, [["expression",script-string]], "isVisible", "isActive" <, optional icon path> ] // Title_in_menu: string that will be displayed for the player // Assigned_key: 0 - no key, 1 - escape key, 2 - key-1, 3 - key-2, ... , 10 - key-9, 11 - key-0, 12 and up... the whole keyboard // Submenu_name: User menu name string (eg "#USER:MY_SUBMENU_NAME" ), "" for script to execute. // CMD: (for main menu:) CMD_SEPARATOR -1; CMD_NOTHING -2; CMD_HIDE_MENU -3; CMD_BACK -4; (for custom menu:) CMD_EXECUTE -5 // script-string: command to be executed on activation. (no arguments passed) // isVisible - Boolean 1 or 0 for yes or no, - or optional argument string, eg: "CursorOnGround" // isActive - Boolean 1 or 0 for yes or no - if item is not active, it appears gray. // optional icon path: The path to the texture of the cursor, that should be used on this menuitem. //["Enable Auto Revive", [0], "", -5, [["expression", "[groupSelectedUnits player, true] spawn SA_fnc_enableAutoRevive;"]], "1", "1"], ["Enable Auto Revive (1 Revive)", [0], "", -5, [["expression", "[groupSelectedUnits player, true, 1] spawn SA_fnc_enableAutoRevive;"]], "1", "1"], ["Disable Auto Revive", [0], "", -5, [["expression", "[groupSelectedUnits player, false, 0] spawn SA_fnc_enableAutoRevive;"]], "1", "1"], ["Halo Jump (Without Leader)", [0], "", -5, [["expression", "[halo, groupSelectedUnits player] spawn SA_fnc_haloJumpMap"]], "1", "1"], ["Form Squad", [0], "", -5, [["expression", "[groupSelectedUnits player] spawn SA_fnc_formNewGroup"]], "1", "1"], ["Other Actions", [7], "#ACTION", -5, [["expression", "player sidechat ""Submenu"" "]], "1", "1"] ]; [] spawn { while {true} do { waitUntil { commandingMenu == "RscGroupRootMenu" }; waitUntil { commandingMenu == "#ACTION" }; showCommandingMenu "#USER:SA_CUSTOM_ACTION_MENU"; }; }; [] spawn { private ["_selectedGroupUnits","_keyDownHandler"]; while {true} do { waitUntil { commandingMenu == "#USER:SA_CUSTOM_ACTION_MENU" }; SA_command_actions_backspace_pressed = false; SA_command_actions_selected_units = []; _keyDownHandler = (finddisplay 46) displayaddeventhandler ["keydown", "if( _this select 1 == 14 && commandingMenu == ""#USER:SA_CUSTOM_ACTION_MENU"") then { SA_command_actions_selected_units = groupSelectedUnits player; SA_command_actions_backspace_pressed = true};"]; waitUntil { commandingMenu == "" }; (finddisplay 46) displayremoveeventhandler ["keydown",_keyDownHandler]; if(SA_command_actions_backspace_pressed) then { showCommandingMenu "RscGroupRootMenu"; { player groupSelectUnit [_x, true]; } forEach (SA_command_actions_selected_units); }; }; }; Looking to streamline these scripts and improve performance, as the INS_Revive still has some Arma 2 code checks in it. Thanks, Share this post Link to post Share on other sites
pierremgi 4875 Posted January 8, 2018 I never use HC. I will have a look. This script (mine) should be improved anyway. I'm not playing with scripts form others but the Naong's one is fine. The approach is more "dead-respawn" oriented. 1 Share this post Link to post Share on other sites
Jnr4817 215 Posted January 8, 2018 I would not want you to play with others scripts. Just posting what we have going for now as reference. I have used this (yours) in a few small missions and like it. Just asking if a little more functionality could be added to the command menu or control of the AI healing players and each other. I meant Dudas AI command not high command sorry. Thanks for the hard work Reed Share this post Link to post Share on other sites
pierremgi 4875 Posted January 8, 2018 No problem. I see what you mean with the command menu. Never tested that. Good idea but a lot of work. I should test what Arma's engine is able to do by default. 1 Share this post Link to post Share on other sites
-XFIRE- 4 Posted January 11, 2018 Best Scripts for Ai > Revive > Ai But i testing ai can't revive player < i am Fix it is confused with my other scripts. but you can set ai don't get damage when incapacitated? Share this post Link to post Share on other sites
pierremgi 4875 Posted January 12, 2018 18 hours ago, -XFIRE- said: Best Scripts for Ai > Revive > Ai But i testing ai can't revive player < i am Fix it is confused with my other scripts. but you can set ai don't get damage when incapacitated? Yes. It's on my mind. 1 Share this post Link to post Share on other sites
Rockapes 103 Posted January 22, 2018 Hey @pierre MGI Is there anything special I need to do get this to work on a dedicated server. If I am hosting the mission that I have placed your script into everything works as it should but on a dedicated it doesn't appear to be. Thanks Edit: Sorry I am running the ExecVM from initserver.sqf Share this post Link to post Share on other sites