Jump to content
pierremgi

AI VEHICLE RESPAWN script, an alternative for BI module

Recommended Posts

                                                                                 AI VEHICLE RESPAWN SP/MP

 

Hi all,

Did you ever try the BI respawn vehicle module? That works well on empty ones, as far as you linked the vehicles to the module.

With some disappointment trying to link a flying helicopter and see it (them!) falling to the ground.
A little code in the "expression field" and, yeah, you create a new crew and a helo just hovering now!

But, what if you want, not only the standard crew, but also the airborne assault squad into it? When? Where on helo track (waypoints)?

And, why not respawning a crate? and the loadout for any respawned vehicle/crate?

 

I suggest the following script to allow AI vehicle, manned or empty, but no player on board),  respawning according to parameters. This works in SP or MP.

Only vehicles (+ full crew if any)  / crates are concerned as far as the respawn for killed infantry AI units is the object of a this other script.

 

version December 06th 2018

 

parameters:   VEHICLES  /  POSITIONS /   DELAY   /   RESPAWN WHEN DISABLED  /   EMPTY VEHICLES (ALL)

Spoiler

[

  <object,side, or any array of side(s) and object(s)>, //    example:  [bob,EAST,RESISTANCE,karl]            (optional)    default: [ ] - only empty vehicle can respawn if allowed

                                                   object(s) must be vehicles (car, air, drone...crate ). Note: Crates are empty vehicles, respawning with little added delay.

                                                   but, IMPORTANT: you don't need to specify CIVILIAN in order to respawn empty vehicles. Civilian here means

                                                   that you want to respawn vehicles driven/manned by some civilian units.

  <string or array if string for respawn position>,  // examples: "marker1" or ["start","mk1",""].   (optional)   default:  "death" , "start" for positions at mission start.
                                                 you need one option for each side, so:

                                                 If more sides, completed by "death" for all remaining declared sides.
                                                 ([west,east,resistance] and ["mk1"] or "mk1" give... ["mk1","death","death"] )

                                                 if this string is a marker name, this position is chosen,

                                                 or "start" (not a marker name) gives the positions of units at start,

                                                 or "death", "", any unused string, gives the position of death for each vehicle/crate,

  <number, seconds (minimum) before respawn>,  // example: 15                                             (optional)           default: 10, min: 2 (scripted)

                                                takes 15 seconds to respawn a vehicle  after death but the double (30) on a disabled vehicle if the last parameter is set as true,

  <boolean, respawn when the vehicle is disabled && the crew has disembarked >          // example: true                       (optional)          default: false

                                                in default engine, the crew disembark when a vehicle can't move anymore. In this case, this parameter set as true makes the

                                                script destroying the vehicle (no explosion) after a first delay, then respawning it after a second delay.

                                                By default (false), you need a complete destruction for a vehicle to be respawned after the delay.

  <boolean, respawn for empty vehicle >          // example: true                       (optional)          default: true

                                               Will respawn all empty destroyed vehicles on their death position.

                                               If you simply want to respawn some of them, disable this option (set false) and add these chosen vehicles as objects inside first parameter.

 

]

 

 

Examples:

[] spawn MGI_fnc_vehicleRespawn       //   [] passed  as parameter  equals to [ [ ], "death", 10, false, true]

                    All empty vehicles can respawn on their position at death, after 10 sec delay, without possibility to respawn if just disabled.

 

[ [WEST,EAST], ["mrk1","death","start",""], nil, false,false ] spawn MGI_fnc_unitRespawn      //    equals to [ [WEST,EAST], ["mrk1","death"], 15, false,false]

                   here, only WEST & EAST ai vehicles can respawn:

                       - on the marker "mk1" if any, (on death position if marker not present), for BLUFOR vehicles

                       - on the position of death for OPFOR vehicles,

                      (other strings in positions array are useless), 10 second delay (default), without respawn when disabled.

                        

Code to be run on server (eventually on Headless Client). example: initServer.sqf if no HC.

 or inside a simple trigger in 3den, server only, non-repeatable, condition true

 

FIRST SCRIPT for  a basic MGI_fnc_vehicleRespawn (with standard loadout, crew and waypoints,  but no kept appearance, pylons, actions ,arsenal...):

Spoiler

 


MGI_fnc_VehicleRespawn = {
  if (!isServer && hasInterface) exitWith {};
  params [["_vehs",[],[[],objNull,WEST],[]],["_positions","death",["",[]],[]],["_delay",10,[0]],["_respOnDisabled",false,[true]],["_empty",true,[true]]];
  private ["_pos","_positionArray"];
  MGIrespVehDelay = _delay max 2;
  MGIrespOnDisabled = _respOnDisabled;
  if (isnil "MGIrespVeh") then {MGIrespVeh = []};
  if (_vehs isEqualType objnull or _vehs isEqualType WEST) then {_vehs = [_vehs]};
  if (_empty) then {
    {
      _Vehs pushBackUnique _x;
    } forEach (vehicles select {!(_x isKindOf "weaponHolderSimulated") && count crew _x == 0})
  };
  {MGIrespVeh pushBackUnique _x} forEach _vehs;
  if (_positions isEqualType "") then { _positions = [_positions]};

  fn_pos = compileFinal "
    params ['_position','_veh','_pos'];
    call {
      if !(getMarkerPos _position isEqualTo [0,0,0]) exitWith {_pos = getMarkerPos _position};
      if (_position == 'start' or (_x getVariable ['emptyVeh',false])) exitWith {_pos = getPos _veh};
        _pos = [0,0,0];
     };
    _pos
  ";

  _nbrEntries = count _vehs;
  _nbrPos = count _positions;
  if (_nbrPos < _nbrEntries) then {
    for '_i' from 0 to (_nbrEntries - _nbrPos - 1) do {
      _positions pushback 'death';
    };
  };

  private ["_idx","_position"];
  while {true} do {
    sleep 1;
    _allVehicles = vehicles select {!(_x isKindOf "WeaponHolderSimulated" or _x isKindOf "Ejection_Seat_Base_F" or _x isKindOf "ParachuteBase") && !isPlayer _x && local _x && alive _x};
    {
      if (side _x in _vehs or _x in MGIrespVeh) then {
        _x setVariable ["MGIrespVehOK",true];
        if (fullCrew _x isEqualTo []) then {
          _x setVariable ["emptyVeh",true]
        } else {
          _x setVariable ["emptyVeh",false]
        };
        call {
          if (side _x in _vehs) exitWith {_idx = _vehs find (side _x); _position = _positions select _idx};
         if (_x in MGIrespVeh) exitWith {_idx = MGIrespVeh find _x; _position = _positions select _idx};
          _position = "death"
          };
        _pos = [_position,_x] call fn_pos;
        _x setVariable ["MGIrespVehDATA",[typeOf _x ,_pos, side _x, fullcrew _x,vehicleVarName _x,getdir _x]];

        if (_position == "death" && !(_x getVariable ["emptyVeh",false])) then {
          _x spawn {
            _veh = _this;
            while {alive _veh} do {
              if ({alive (_x select 0)} count (fullCrew _veh) > 0) then {
                _fullOldCrew = +(fullCrew _veh select {alive (_x select 0)});
                {(_x select 0) setVariable ["oldGrp",group (_x select 0)]} forEach _fullOldCrew;
                (_veh getVariable "MGIrespVehDATA") set [3,_fullOldCrew];
              } else {
                if(MGIrespOnDisabled && !canmove _veh) exitWith {
                  _veh spawn {
                    params ["_veh"];
                    uiSleep MGIrespVehDelay/2;
                    if (crew _veh findIf {alive _x} < 0) then {
                      _veh setDamage [1,false];
                    };
                  };
                };
              };
              sleep 2;
            };
          };
        } else {
          {(_x select 0) setVariable ["oldGrp",group (_x select 0)]} forEach fullCrew _x;
        };
      };
    } foreach (_allVehicles select {isNil {_x getVariable "MGIrespVehOK"}});
  };
};


fn_destroy = compileFinal "
      params [['_destroyed',objNull]];
      if !(isNull _destroyed) then {
      _type = (_destroyed getVariable 'MGIrespVehDATA') select 0;
      _pos = (_destroyed getVariable 'MGIrespVehDATA') select 1;
      _side = (_destroyed getVariable 'MGIrespVehDATA') select 2;
      _fullOldCrew = (_destroyed getVariable 'MGIrespVehDATA') select 3;
      _varName = (_destroyed getVariable 'MGIrespVehDATA') select 4;
      _initDir = (_destroyed getVariable 'MGIrespVehDATA') select 5;
      _oldSpeed = speed _destroyed;
      _oldCrew = _fullOldCrew apply {_x select 0};
      _respawnName =['initial point','grid'] select (_pos isEqualTo [0,0,0]);
      _cfgVeh = configfile >> 'cfgvehicles' >> typeOf _destroyed;
      _displayName = gettext (_cfgVeh >> 'displayName');
      _picture = (gettext (_cfgVeh >> 'picture')) call bis_fnc_textureVehicleIcon;
      _curr = currentWaypoint group _destroyed;
      if (_pos isEqualTo [0,0,0]) then {_pos = getpos _destroyed};
      _dir = if (_destroyed getVariable ['emptyVeh',false]) then [{_initDir},{getDir _destroyed}];
      _onGround = (isTouchingGround _destroyed);
      _timer = diag_tickTime;
      waitUntil {isTouchingGround _destroyed or diag_tickTime > _timer + 30 or isNull _destroyed};
      uiSleep MGIrespVehDelay;
      _destroyed hideObjectGlobal true;
      _newVeh =  createVehicle [_type, [0,0,0], [], 0, ['FLY','CAN_COLLIDE'] select _onGround];
      uiSleep 0.01;
      _newVeh setpos _pos;
      _newVeh setDir _dir;
      if !(_varName isEqualTo '') then {
        [_newVeh,_varName] remoteExec ['setVehicleVarName',0,true];
        missionNameSpace setVariable [_varName, _newVeh, true];
      };
      if (_destroyed in MGIrespVeh) then {
        _idx = MGIrespVeh find _destroyed;
        MGIrespVeh set [_idx, _newVeh];
        MGIrespVeh = MGIrespVeh - [objNull]
      };
      if (_respawnName == 'grid') then {
        _respawnName = format [localize 'str_a3_bis_fnc_respawnmenuposition_grid',mapgridposition (position _newVeh)];
      } else { _curr = 1};
      sleep 0.1;
      if (['UAV',typeOf _newVeh] call bis_fnc_inString or ['UGV',typeOf _newVeh] call bis_fnc_inString) then {
          createVehicleCrew _newVeh;
          if (['UAV',typeOf _newVeh] call bis_fnc_inString) then {
            _newVeh setVelocityModelSpace [0,_oldSpeed/3.6,0];
          };
      };
      if (count _fullOldCrew > 0) then {
        _grps = [];
        {
          _unit = _x select 0;
          _grp = _unit getVariable ['oldGrp',createGroup civilian];
          _grps pushBackUnique _grp;
          if (!alive _unit or !isTouchingGround _newVeh) then {
            (typeOf _unit) createUnit [getpos _newVeh, _grp, 'this allowDamage false; switch toLower (_x select 1) do {
              case ""driver"": {this moveInDriver _newVeh};
              case ""commander"": {this moveInCommander _newVeh};
              case ""gunner"": {this moveInGunner _newVeh};
              case ""cargo"": {this moveInCargo [_newVeh,(_x select 2)]};
              case ""turret"": {this moveInturret  [_newVeh,(_x select 3)]};
              };
              this allowDamage true;
              if (vehicle _newVeh isKindOf ""plane"") then {_newVeh setVelocityModelSpace [0,_oldSpeed/3.6,0]}'];
            } else {
              _unit allowDamage false;
              switch toLower (_x select 1) do {
                case ""driver"": {_unit moveInDriver _newVeh};
                case ""commander"": {_unit moveInCommander _newVeh};
                case ""gunner"": {_unit moveInGunner _newVeh};
                case ""cargo"": {_unit moveInCargo [_newVeh,(_x select 2)]};
                case ""turret"": {_unit moveInturret  [_newVeh,(_x select 3)]};
              };
              _unit allowDamage true;
            };
        } forEach _fullOldCrew;
        {
          _grp = _x;
          if (count waypoints _grp >1 && (effectiveCommander _newVeh in units _grp)) then {
            _grp selectLeader (effectiveCommander _newVeh);
            [_grp,_curr] spawn {
              params ['_grp','_curr'];
              comment ' waituntil {sleep 1; unitReady leader _grp}     not needed or to be confirmed for some kinds of assets. please report ';
              _grp setCurrentWaypoint [_grp,_curr];
              leader _grp doMove (waypointPosition [_grp,_curr]);
            };
          };
        } forEach _grps;
      } else {
        _sideNbr = getNumber (configfile >> 'CfgVehicles' >> typeOf _newVeh >> 'side');
        _side = [EAST,WEST,INDEPENDENT,CIVILIAN,sideUnknown,sideEnemy,sideFriendly] select _sideNbr;
      };
      ['RespawnVehicle',[_displayName,_respawnName,_picture]] remoteExec ['BIS_fnc_showNotification',_side];
      {_destroyed deleteVehicleCrew _x} forEach (_oldCrew select {!alive _x});
       uiSleep 0.01;
      _destroyed setVariable ['MGIrespVehDATA',nil];
      _destroyed setVariable ['MGIrespVehOK',nil];
      deleteVehicle _destroyed;
  };
    ";

addMissionEventHandler ["EntityKilled",{
  params ["_destroyed"];
  if (!isNil {_destroyed getVariable "MGIrespVehOK"}) then {
    _destroyed spawn fn_destroy;
  };
}];

0 = [EAST,"death",10,true,false] spawn MGI_fnc_VehicleRespawn;   // example

 

 

 

 

 

___________________________________________________________________

 

SECOND SCRIPT (instead of first one) for MGI_fnc_vehicleRespawn (now adding skin, appearance, loadout, pylons and turrets config, actions menu).

Tha's a step further, with integration of the two functions MGI_fnc_getVehicleLoadout and MGI_setVehicleLoadout for recovering the vehicle loadout after respawn:

Spoiler

 


MGI_fnc_getVehicleLoadout = compileFinal "
  _veh = param [0,objNull, [objNull]];
  _veh setVariable ['MGIallCont',[]];
  (_veh getVariable 'MGIallCont') pushBack [_veh,itemCargo _veh,magazineCargo _veh,weaponCargo _veh,backpackCargo _veh];
  {(_veh getVariable 'MGIallCont') pushBack [_x select 0,itemCargo (_x select 1),magazineCargo (_x select 1),weaponCargo (_x select 1),[]]} forEach everyContainer _veh;
";

MGI_fnc_setVehicleLoadout = compileFinal "
  params [['_newVeh',objNull,[objNull]], ['_oldVeh',objNull,[objNull]]];
  if ( {_x isKindOf 'CAManBase'} count [_newVeh,_oldVeh] >0 or isnil {_oldVeh getVariable 'MGIallCont'}) exitWith {};
  if (!isnil {_oldVeh actionParams 0}) then {
    private _flagArsenalDbl = false;
    if (!isnil {_oldVeh getVariable 'bis_addVirtualWeaponCargo_cargo'}) then {_newVeh setVariable ['bis_addvirtualweaponcargo_cargo', _oldVeh getVariable ['bis_addvirtualweaponcargo_cargo',''],true]};
    for '_i' from 0 to (_oldVeh addAction ['','']) -1 do {
      if (!_flagArsenalDbl or !(['bis_fnc_arsenal',_oldVeh actionParams _i select 1] call bis_fnc_instring)) then {
        private _act = _oldVeh actionParams _i;
        {_act deleteAt 10;true} count [1,2];
        [_newVeh,_act] remoteExec ['addaction',0,true];
        if(['bis_fnc_arsenal',_oldVeh actionParams _i select 1] call bis_fnc_instring) then {_flagArsenalDbl = true};
      };
    };
  };

  if (typeOf _newVeh isEqualTo typeOf _oldVeh) then {
    private _oldTexture = getObjectTextures _oldVeh;
    if ( count _oldTexture > 0) then {
      for '_i' from 0 to count _oldTexture - 1 do {
        _oldTexture  set [_i,[_i,_oldTexture select _i]]
      };
      {_newVeh setObjectTextureGlobal _x } forEach _oldTexture;
    };
    private _animList = animationNames _oldVeh;
    if (count _animList > 0) then {
      _ll = [];
      for '_i' from 0 to count _animList -1 do {
        _ll pushBack [_animList select _i,_oldVeh animationPhase (_animList select _i)];
      {_newVeh animate _x} forEach _ll;
      };
    };
    if (_newVeh isKindOf 'air') then {
      private _pylons = getPylonMagazines _oldVeh;
      private _pylonPaths = (configProperties [configFile >> 'CfgVehicles' >> typeOf _oldVeh >> 'Components' >> 'TransportPylonsComponent' >> 'Pylons', 'isClass _x']) apply {getArray (_x >> 'turret')};
      {
        _newVeh removeWeaponGlobal getText (configFile >> 'CfgMagazines' >> _x >> 'pylonWeapon')
      } forEach getPylonMagazines _newVeh;
      {
       _newVeh setPylonLoadOut [_forEachIndex + 1, _x, true, _pylonPaths select _forEachIndex]
      } forEach _pylons;
    };
    private _oldTrt = magazinesAllTurrets _oldVeh;
    {_newVeh removeMagazineTurret _x} forEach (magazinesAllTurrets _newVeh apply {[_x select 0,_x select 1]});
    {_newVeh addMagazineTurret _x} forEach _oldTrt;
  };
  if (!isnil {_oldVeh getVariable 'MGIallCont'} && {(_oldveh getVariable 'MGIallCont') isEqualType []}) then {
    {
      _x params ['_cont',['_it',[]],['_mag',[]],['_wp',[]],['_bpk',[]]];
      if (_cont isEqualType '') then {
        _cont = everyContainer _newVeh select (_foreachindex -1) select 1;
      } else {
        _cont = _newVeh;
      };
      clearItemCargoGlobal _cont;
      clearMagazineCargoGlobal _cont;
      clearWeaponCargoGlobal _cont;
      clearBackpackCargoGlobal _cont;
      {_cont addItemCargoGlobal [_x,1];true} count _it;
      {_cont addMagazineCargoGlobal [_x,1];true} count _mag;
      {_cont addWeaponCargoGlobal [_x,1];true} count _wp;
      {_cont addBackpackCargoGlobal [_x,1];true} count _bpk;
    } forEach (_oldVeh getVariable ['MGIallCont',[]]);
  }
";

fn_destroy = compileFinal "
  params [['_destroyed',objNull]];
  _type = (_destroyed getVariable 'MGIrespVehDATA') select 0;
  _pos = (_destroyed getVariable 'MGIrespVehDATA') select 1;
  _side = (_destroyed getVariable 'MGIrespVehDATA') select 2;
  _fullOldCrew = (_destroyed getVariable 'MGIrespVehDATA') select 3;
  _varName = (_destroyed getVariable 'MGIrespVehDATA') select 4;
  _initDir = (_destroyed getVariable 'MGIrespVehDATA') select 5;
  _initCode = (_destroyed getVariable ['MGIcustomCode','']);
  _oldSpeed = speed _destroyed;
  _oldCrew = _fullOldCrew apply {_x select 0};
  _respawnName =['initial point','grid'] select (_pos isEqualTo [0,0,0]);
  _cfgVeh = configfile >> 'cfgvehicles' >> typeOf _destroyed;
  _displayName = gettext (_cfgVeh >> 'displayName');
  _picture = (gettext (_cfgVeh >> 'picture')) call bis_fnc_textureVehicleIcon;
  _curr = currentWaypoint group _destroyed;
  if (_pos isEqualTo [0,0,0]) then {_pos = getpos _destroyed};
  _dir = if (_destroyed getVariable ['emptyVeh',false]) then [{_initDir},{getDir _destroyed}];
  _onGround = (isTouchingGround _destroyed);
  _timer = diag_tickTime;
  waitUntil {isTouchingGround _destroyed or diag_tickTime > _timer + 10 or isNull _destroyed};
  uiSleep MGIrespVehDelay;
  _destroyed hideObjectGlobal true;
  _newVeh =  createVehicle [_type, [0,0,0], [], 0, ['FLY','CAN_COLLIDE'] select _onGround];
  uiSleep 0.01;
  _newVeh setpos _pos;
  _newVeh setDir _dir;
  if !(_varName isEqualTo '') then {
    [_newVeh,_varname] remoteExec ['setVehicleVarName',0,true];
    missionNameSpace setVariable [_varName, _newVeh, true];
  };
  if (_destroyed in MGIrespVeh) then {
    _idx = MGIrespVeh find _destroyed;
    MGIrespVeh set [_idx, _newVeh];
    MGIrespVeh = MGIrespVeh - [objNull]
  };
  [_newVeh,_destroyed] call MGI_fnc_setVehicleLoadout;
  if (_respawnName == 'grid') then {
    _respawnName = format [localize 'str_a3_bis_fnc_respawnmenuposition_grid',mapgridposition (position _newVeh)];
  } else { _curr = 1};
  sleep 0.1;
  if (_initCode != '') then {
    (compile _initCode) remoteExec ['call',0,true];      
    _newVeh setVariable ['MGIcustomCode',_initCode,true];
  };
  if (['UAV',typeOf _newVeh] call bis_fnc_inString or ['UGV',typeOf _newVeh] call bis_fnc_inString) then {
    createVehicleCrew _newVeh;
    if (['UAV',typeOf _newVeh] call bis_fnc_inString) then {
      _newVeh setVelocityModelSpace [0,_oldSpeed/3.6,0];
    };
  };
  if (count _fullOldCrew > 0) then {
    _grps = [];
    {
      _unit = _x select 0;
      _grp = _unit getVariable ['oldGrp',createGroup civilian];
      _grps pushBackUnique _grp;
      if (!alive _unit or !isTouchingGround _newVeh) then {
        (typeOf _unit) createUnit [getpos _newVeh, _grp, 'this allowDamage false; switch toLower (_x select 1) do {
            case ""driver"": {this moveInDriver _newVeh};
            case ""commander"": {this moveInCommander _newVeh};
            case ""gunner"": {this moveInGunner _newVeh};
            case ""cargo"": {this moveInCargo [_newVeh,(_x select 2)]};
            case ""turret"": {this moveInturret  [_newVeh,(_x select 3)]};
          };
          this allowDamage true;
          if (vehicle _newVeh isKindOf ""plane"") then {_newVeh setVelocityModelSpace [0,_oldSpeed/3.6,0]}'];
      } else {
        _unit allowDamage false;
        switch toLower (_x select 1) do {
          case ""driver"": {_unit moveInDriver _newVeh};
          case ""commander"": {_unit moveInCommander _newVeh};
          case ""gunner"": {_unit moveInGunner _newVeh};
          case ""cargo"": {_unit moveInCargo [_newVeh,(_x select 2)]};
          case ""turret"": {_unit moveInturret  [_newVeh,(_x select 3)]};
        };
        _unit allowDamage true;
      };
    } forEach _fullOldCrew;
    {
      _grp = _x;
      if (count waypoints _grp >1 && (effectiveCommander _newVeh in units _grp)) then {
        _grp selectLeader (effectiveCommander _newVeh);
        [_grp,_curr] spawn {
          params ['_grp','_curr'];
          comment ' waituntil {sleep 1; unitReady leader _grp}     not needed or to be confirmed for some kinds of assets. please report ';
          _grp setCurrentWaypoint [_grp,_curr];
          leader _grp doMove (waypointPosition [_grp,_curr]);
        };
      };
    } forEach _grps;
  } else {
    _sideNbr = getNumber (configfile >> 'CfgVehicles' >> typeOf _newVeh >> 'side');
    _side = [EAST,WEST,INDEPENDENT,CIVILIAN,sideUnknown,sideEnemy,sideFriendly] select _sideNbr;
  };
  ['RespawnVehicle',[_displayName,_respawnName,_picture]] remoteExec ['BIS_fnc_showNotification',_side];
  {deleteVehicle _x} forEach (_oldCrew select {!alive _x});
  sleep 0.1;
  _destroyed setVariable ['MGIrespVehDATA',nil];
  _destroyed setVariable ['MGIrespVehOK',nil];
  deleteVehicle _destroyed;
";

MGI_fnc_VehicleRespawn = {
  if (!isServer && hasInterface) exitWith {};
  params [["_vehs",[],[[],objNull,WEST],[]],["_positions","death",["",[]],[]],["_delay",10,[0]],["_respOnDisabled",false,[true]],["_empty",true,[true]]];
  private ["_pos","_positionArray"];
   MGIrespVehDelay = _delay max 2;
  MGIrespOnDisabled = _respOnDisabled;
  if (isnil "MGIrespVeh") then {MGIrespVeh = []};
  if (_vehs isEqualType objnull or _vehs isEqualType WEST) then {_vehs = [_vehs]};
  if (_empty) then {
    {
      _Vehs pushBackUnique _x} forEach (vehicles select {!(_x isKindOf "weaponHolderSimulated") && count crew _x == 0})
  };
  {MGIrespVeh pushBackUnique _x} forEach _vehs;
  if (_positions isEqualType "") then { _positions = [_positions]};

  fn_pos = compileFinal "
    params ['_position','_veh','_pos'];
    call {
      if !(getMarkerPos _position isEqualTo [0,0,0]) exitWith {_pos = getMarkerPos _position};
      if (_position == 'start' or (_x getVariable ['emptyVeh',false])) exitWith {_pos = getPos _veh};
        _pos = [0,0,0];
     };
    _pos
  ";

  _nbrEntries = count _vehs;
  _nbrPos = count _positions;
  if (_nbrPos < _nbrEntries) then {
    for "_i" from 0 to (_nbrEntries - _nbrPos - 1) do {
      _positions pushback "death";
    };
  };

  private ["_idx","_position"];
  while {true} do {
    sleep 1;
    _allVehicles = vehicles select {!(_x isKindOf "WeaponHolderSimulated" or _x isKindOf "Ejection_Seat_Base_F" or _x isKindOf "ParachuteBase") && !isPlayer _x && local _x && alive _x};
    {
      _x addEventHandler ["handledamage", {
        params ["_veh","_hit","_dam"];
          if (alive _veh) then {
          _veh call MGI_fnc_getVehicleLoadout; _dam
        };
      }];
      if (side _x in _vehs or _x in MGIrespVeh) then {
        _x setVariable ["MGIrespVehOK",true];
        if (fullCrew _x isEqualTo []) then {
          _x setVariable ["emptyVeh",true]
        } else {
          _x setVariable ["emptyVeh",false]
        };
        call {
          if (side _x in _vehs) exitWith {_idx = _vehs find (side _x); _position = _positions select _idx};
         if (_x in MGIrespVeh) exitWith {_idx = MGIrespVeh find _x; _position = _positions select _idx};
          _position = "death"
          };
        _pos = [_position,_x] call fn_pos;
        _x setVariable ["MGIrespVehDATA",[typeOf _x ,_pos, side _x, fullcrew _x,vehicleVarName _x,getDir _x]];


        if (_position == "death" && !(_x getVariable ["emptyVeh",false])) then {
          _x spawn {
            _veh = _this;
            while {alive _veh} do {
              if ({alive (_x select 0)} count (fullCrew _veh) > 0) then {
                _fullOldCrew = +(fullCrew _veh select {alive (_x select 0)});
                {(_x select 0) setVariable ["oldGrp",group (_x select 0)]} forEach _fullOldCrew;
                (_veh getVariable "MGIrespVehDATA") set [3,_fullOldCrew];
              } else {
                if(MGIrespOnDisabled && !canmove _veh) exitWith {
                  _veh spawn {
                    params ["_veh"];
                    sleep MGIrespVehDelay/2;
                    if (crew _veh findIf {alive _x} < 0) then {
                      _veh setDamage [1,false];
                    };
                  };
                };
              };
              sleep 2;
            };
          };
        } else {
          {(_x select 0) setVariable ["oldGrp",group (_x select 0)]} forEach fullCrew _x;
        };
      };
    } foreach (_allVehicles select {isNil {_x getVariable "MGIrespVehOK"}});
  };
};

addMissionEventHandler ["EntityKilled",{
  params ["_destroyed"];
  if (!isNil {_destroyed getVariable "MGIrespVehOK"}) then {
    _destroyed spawn fn_destroy;
  };
}];

0 = [[crate2,WEST,karl,CIVILIAN],["death","start","start","start"],10,true,false] spawn MGI_fnc_VehicleRespawn; // example

 

 

 

 

 

Enjoy!

Pierre MGI

 

Notes:

- If you choose to respawn the disabled vehicles, these will be destroyed (then respawned), probably earlier than for the normal destruction. Destruction occurs sooner but not before the crew leaves the vehicle. So, if you allow crew staying inside immobilized vehicle, this "respawn on disabled" is postponed until destruction by enemy or abandon.

- using the second scrip^t, some behaviors like custom loadout and actions menu needs to fire the EH handle damage. That is to say, you have to damage the vehicle in-game (firing at it), not using a simple setDamage via debug console (this command doesn't trigger the EH). Also, let some seconds after mission start (Arma engine actions menu returm something for the actionParams).

 

Version 13112018: added possibility to "respawn"  the code written in init field of a vehicle.

You just need to write it this way:

instead of <your code>

write:

this setVariable ["MGIcustomCode",  ' <your code>  ' ]; call compile (this getVariable "mgiCustomcode")

Pay attention for double and single quote!

Example:

in normal init field, you can write:

0 = [] spawn {waitUntil {!isNull player}; hint ("hello "+ (name player))}

Here you need to write:

this setVariable ["MGIcustomCode" ' 0 = [] spawn {waitUntil {!isNull player}; hint ("hello "+ (name player))} ' ]; call compile (this getVariable "mgiCustomcode")

 

Version 06122018: improved jets respawn.

 

  • Like 7

Share this post


Link to post
Share on other sites

These sound and look great, Pierre! Thanks for posting them here, much appreciated.

I'm going to give them a test run in the near future.

Share this post


Link to post
Share on other sites

Changed some behaviors for respawn when a vehicle is disabled with crew and remaining waypoints. To stop definitely the vehicle, you have to kill the driver before the vehicle.

 

So, how it works:

* a vehicle like HEMTT can have 1 driving group, several assault groups. All groups can have their own waypoints;

* this vehicle is taking fire. The groups have their own dead;

*  - if the vehicle is destroyed, the vehicle will respawn and all alive units inside it (within 0-2 sec. max before explosion) will respawn
     and continue (restart) their waypoints (if the driver respawned);

  - if the vehicle is disabled (can't move), along with the allowCrewInImmobile (to be defined elsewhere), the remaining crew disembark or not.
    If disembarking, the vehicle is treated as an empty one (so, respawning) then the disembarked units will be teleported inside (movein... where they were)
    and the vehicle/groups will continue their waypoints.

 

If position "start" is chosen, you can obtain some working waves of enemies,as far as the whole groups are respawned (if already inside vehicles). Foot units are treated in another script.

Thinking also for a new parameter for several choices on respawn for empty vehicles (all, side(s), type(s) ) and one more: only (no respawn if crew) .

 

Any suggestion appreciated.

 

Share this post


Link to post
Share on other sites

Added some features for respawned vehicle:

- Hull skin (command setObjectTextureGlobal to be confirmed by test on dedicated server);

- appearance (custom doors, roll cage, fenders, .. as in Editor if any)

- loadout, as any other crates, with Arsenal if any

- armament turrets and pylons with their magazines.

 

Share this post


Link to post
Share on other sites

Hi Pierre... spoke with you over PM about aircraft respawning and following waypoints I had set up. Your reply was this: What you need to do:
- add a group name in the init field of the group helo, just example helo1grp

then, the module expression field becomes:
_newVeh = _this select 0; createVehicleCrew _newVeh; _newCrew = crew _newVeh; _newGrp = group (_newCrew select 0); _newgrp allowfleeing 0; {_x setSkill 1} forEach units _newGrp; _newGrp copywaypoints strikegrp

 

I changed the name of the group to strikegrp instead of helo1grp but other than that, I added this to the expression line in the vehicle respawn module like you requested. Then in the aircraft object init I added strikegrp to the variable name. when I run the game in the editor the aircraft takes off like it is suppose to and follows all the waypoints I had created, the problem comes when the aircraft is destroyed. A new aircraft spawns in the original position and takes off but will not follow the waypoints it is supose to follow, it just turns and heads south to the corner of the map and just continually circles. This tells me that it is not following or copying the waypoints it is suppose to do when a new aircraft spawns.. any help with this would be appreciated.. thanks Pierre... Ding

 

Here are the screen shots for the respawn module and the aircraft: 107410_20170712175020_1.png

 

                                                                                                          107410_20170712174958_1.png

Share this post


Link to post
Share on other sites

I can answer for BI module, even here is a topic supposed to bring an alternative for it....:hehe:

 

 

I wrote (you in MP): add a group name in the init field of the group helo ... Not in the init field of the unit (helo), but in the variable name of the group icon. Double click on the rectangular (BLUFOR) group icon. Waypoints always apply to groups. strikeGrp must be a name of a group, not a unit.

You can also write something in the init field of the unit : strikeGrp = group this; (same)

Share this post


Link to post
Share on other sites

Pierre......Is it possible to delete the pilot if he ejects so the plane will respawn? Right now if the pilot ejects and lives he will just wander the map and the aircraft will not respawn while he is still alive. I have the respawn module set to if he is more than 5 m away from the aircraft it will respawn but it doesn't as long as the pilot is alive. Any help would be appreciated :)

Share this post


Link to post
Share on other sites
On 13/07/2017 at 2:23 PM, captainding said:

Pierre......Is it possible to delete the pilot if he ejects so the plane will respawn? Right now if the pilot ejects and lives he will just wander the map and the aircraft will not respawn while he is still alive. I have the respawn module set to if he is more than 5 m away from the aircraft it will respawn but it doesn't as long as the pilot is alive. Any help would be appreciated :)

 

If you want to correct all particular non-implemented features of the BI module, you could save time in testing my script!. You are at the right post! :drinking2:

Share this post


Link to post
Share on other sites

The script works beautifully for the mission I'm trying to do, thanks.

 

I do have one issue, and that's that I'm trying to use ALiVE CAS with this script, which doesn't work very well because the script respawns the vehicle instead of ALiVE doing it.

 

Is there a a way I could set this to only respawn empty vehicles? Thanks again.

 

Edit: Obviously I mean vehicles that are empty at the start of the mission, I have only a very thin grasp of how scripting works so I'm not sure when exactly the script decides which vehicles are respawnable. Either way, I just want to exclude some vehicles from respawning so if you had any idea how I would achieve that I would appreciate it.

Share this post


Link to post
Share on other sites

Yep! As workaround, waiting for script modification, you can pass sideUnknown in side parameter. As there is no "unknown" vehicle, only the empty ones (by default) will respawn. The problem is, at this time, you don't have choice for a "side" , you respawn all empty vehicles. To be continued.

Share this post


Link to post
Share on other sites

Added respawn save for the vehicle name (variable name in object init). That helps for some scripts.

Share this post


Link to post
Share on other sites

Reworked to allow specific vehicles, passed as objects, or array of objects/sides. See parameters.

Corrected impossibility to respawn a specific vehicle several times.

 

Next step: respawn ticket.

  • Like 1

Share this post


Link to post
Share on other sites

Hai,

I'd scavenged some of code from couple of guys in this forums to make a Jet Patrolling dedicated place for my mission. Unfortunately, i can't make it to respawn after being destroyed / out of fuel/ pilot dead. I'd tried couple of code by failed.

AirPatrol.sqf

Spoiler

 

_jet = createVehicle ["O_Plane_CAS_02_F", [27158,24907.2,0], [], 0, "NONE"]; _jet setDir 220;
_group = createGroup east;
_unit = _group createUnit ["O_Pilot_F", [27160.1,24901.9,0], [], 0, "NONE"]; _unit setskill 1; _unit setRank "CAPTAIN"; _unit moveInDriver _jet;
_jet flyInHeightASL [400, 200, 800];

wp0 = _group addwaypoint[getmarkerpos"wp0",0];
wp0 setwaypointtype"Move"; 

wp1 = _group addwaypoint[getmarkerpos"wp1",0];
wp1 setwaypointtype"Move";

wp2 = _group addwaypoint[getmarkerpos"wp2",0];
wp2 setwaypointtype"Move";

wp3 = _group addwaypoint[getmarkerpos"wp3",0];
wp3 setwaypointtype"Move";

wp4 = _group addwaypoint[getmarkerpos"wp4",0];
wp4 setwaypointtype"Move";

wp5 = _group addwaypoint[getmarkerpos"wp5",0];
wp5 setwaypointtype"Move";

wp0 = _group addwaypoint[getmarkerpos"wp0",0];
wp0 setwaypointtype"Move";

wp0 setwaypointtype "CYCLE"; 


[_group, 1] setWaypointSpeed "FULL";
[_group, 1] setWaypointCombatMode "RED";
[_group, 1] setWaypointBehaviour "AWARE";

 

Init.sqf

Spoiler

//airpatrol
nul = execVM "AirPatrol.sqf";

 

Your help will be much needed and appreciated.

Btw, i'm not a scripter/coder. I'm just a scavenger who looking for a code/script to make mission. Learning this will take ages for me.

Share this post


Link to post
Share on other sites

_jetGrp =  [[27158,24907.2,800],EAST,["O_Plane_CAS_02_F"],[],["CAPTAIN"],[1],[],[],220] call Bis_fnc_spawnGroup;
_jet  = units _jetGrp select 0;

//    _jet setVelocity [150 * sin 220,150 * cos 220, 0];  // mandatory for some modded aircraft (CUP)
_jet flyInHeightASL [400, 200, 800];
{_jetGrp addWaypoint [getMarkerPos _x,0] } forEach ["wp0","wp1","wp2","wp3","wp4","wp5"];

_wp = _jetGrp addWaypoint [getMarkerPos "wp0",0];

_wp setWaypointType "CYCLE";

[_jetGrp, 1] setWaypointSpeed "FULL";
[_jetGrp, 1] setWaypointCombatMode "RED";
[_jetGrp, 1] setWaypointBehaviour "AWARE";

[ _jet, "start",nil, false,false ] spawn MGI_fnc_unitRespawn;

 

You need the script above.

Share this post


Link to post
Share on other sites

Where do I put this?

0 = [[crate2,WEST,karl,CIVILIAN],[["death","start","start","start"],10,true,false] spawn MGI_fnc_VehicleRespawn; // example

Does that stay in the initServer.sqf or do I put it in a vehicle's init? When I put everything in initServer.sqf and configure that line I get loads of errors.

 

This is what I had it set to:

0 = [[],[["start"],3,true,false] spawn MGI_fnc_VehicleRespawn; // example

Share this post


Link to post
Share on other sites

Alright, found the problem. Was that sneaky little extra "[". Now for some reason though the vehicle won't keep it's paintjob and it won't respawn at the start location. And a major downside to this over the BIS module is that the BIS one keeps curator editable objects still editable after respawn; Is there any way to fix that?

 

Btw this is what I'm using now:

0 = [[MRZR_1,MRZR_2],["start","start"],3,true,false] spawn MGI_fnc_VehicleRespawn;

Share this post


Link to post
Share on other sites

The script will keep any "appearance", if you use the longest version of the code. check this point.

Don't mix respawn module and the script.

Corrected position on start.

Share this post


Link to post
Share on other sites

@pierremgi
This line got error where it doesn't set the pilot skill to 1 and set rank to Captain.

Spoiler

_jetGrp =  [[27158,24907.2,800],EAST,["O_Plane_CAS_02_F"],[],["CAPTAIN"],[1],[],[],220] call Bis_fnc_spawnGroup;

 

For this line :

Spoiler

 [ _jet, "start",nil, false,false ] spawn MGI_fnc_unitRespawn;

to function, i had to put this code :

Spoiler

MGI_fnc_unitRespawn = {
  if (!isServer && hasInterface) exitWith {};
  params [["_sides",[WEST,EAST,RESISTANCE,CIVILIAN],[[WEST]],[]],["_positions","start",["",["","","",""]],[]],["_delay",10,[0]],["_waitForGrp",144,[0]],["_existingLO",false,[true]]];
  private ["_pos","_positionArray"];
  MGIrespDelay = _delay max 2;
  MGIwaitForGrp = _waitForGrp;
  MGIexistingLO = _existingLO;

  fn_pos = {
    params ["_position","_pos"];
    call {
      if !(getMarkerPos _position isEqualTo [0,0,0]) exitWith {_pos = getMarkerPos _position};
      if (_position == "start") exitWith {_pos = getPos _x};
        _pos = [0,0,0];
     };
    _pos
  };

  if (_positions isEqualType "") then { _positions = [_positions]};
  if (_positions isEqualType []) then {
    _nbrSide = count _sides;
    _nbrPos = count _positions;
    if (_nbrPos < _nbrSide) then {
      for "_i" from 0 to (_nbrSide - _nbrPos - 1) do {
        _positions pushback "start";
      };
    };
  };

  _positionArray = [];
  for "_i" from 0 to count _sides - 1 do {
    _positionArray pushback (_sides select _i);
    _positionArray pushback (_positions select _i);
  };

  while {true} do {
    sleep 1;
    _allUnits = allUnits select {isnull objectParent _x && !isplayer _x && local _x};
    {
      if (!(_x getVariable ["MGIrespOK",false]) && (side _x in _sides)) then {
        _side = side _x;
        _position = _positionArray select ((_positionArray find _side) + 1);
        _pos = _position call fn_pos;
        _oldGrp = group _x;
        if (isnil {_oldGrp getVariable ["_squadNbr", nil]}) then {
          _oldGrp setVariable ["_squadNbr", count units _oldGrp]
        };
        _x setVariable ["MGIrespDATA",[typeOf _x ,_pos, side _x, getdir _x, _oldGrp,_oldGrp getVariable "_squadNbr"]];
        if !(MGIexistingLO) then {
          _x setVariable ["MGIloadout",getUnitLoadout _x]
        };
        _x setVariable ["MGIrespOK",true];
      };
    } foreach _allUnits;
  };
};


addMissionEventHandler ["entityKilled",{
  _killed = _this select 0;
  if (_killed getVariable ["MGIrespOK",false]) then {
    _killed spawn {
      private "_loadout";
      _killed = _this;
      _type = (_killed getVariable "MGIrespDATA") select 0;
      _pos = (_killed getVariable "MGIrespDATA") select 1;
      _side = (_killed getVariable "MGIrespDATA") select 2;
      _dir = (_killed getVariable "MGIrespDATA") select 3;
      _oldGrp = (_killed getVariable "MGIrespDATA") select 4;
      _squadNbr = (_killed getVariable "MGIrespDATA") select 5;
      if (MGIexistingLO) then {_loadout = getUnitLoadout _killed};
      if !(MGIexistingLO) then {_loadout = _killed getVariable "MGIloadout"};
      if (_pos isEqualTo [0,0,0]) then {_pos = getpos _killed};
      sleep MGIrespDelay;
      waitUntil {({alive _x} count units _oldGrp < (MGIwaitForGrp min _squadNbr)) or (_oldGrp getVariable ["fillIt",false])};
      _newbie = _oldGrp createUnit [_type, _pos, [],0,"CAN_COLLIDE"];
      _newbie setDir _dir;
      _oldGrp setVariable ["fillIt", true];
      if (({alive _x} count units _oldGrp == _squadNbr)) then {
        _oldGrp setVariable ["fillIt", false]
      };
      _newbie setUnitLoadout _loadout;
      sleep (MGIrespDelay +0.1);
      _killed setVariable ["MGIrespDATA",nil];
      _killed setVariable ["MGIrespOK",nil];
       deleteVehicle _killed;
    };
  };
}];

[ _jet, "start",nil, false,false ] spawn MGI_fnc_unitRespawn;

in initServer.sqf right? Still no luck for me to make it respawn after death.

Share this post


Link to post
Share on other sites

Bis_fnc_spawnGroup:

rank doesn't seem to work in this case. Ask BI why...

skill is a range. Use [1,1] if you want a skill set to 1.

 

You can workaround the missing rank, adding a loop for that:

_jet spawn {
  _jet = _this;

  while {true} do {

    waitUntil {sleep 2; (rank driver _jet != "captain" or skill driver _jet < 1) && alive driver _jet};

    driver _jet setRank "captain";

   driver _jet setSkill 1

  };

};

 

The MGI_fnc_unitRespawn is another script for infantry unit (follow mgi scripts tag). Not relevant here

Here your jet is a vehicle and you're at the right place! .. to respawn it with its AI crew, if you use the MGI_fnc_vehicleRespawn function.

Note: the skill is not saved (the reason why i added it in the loop).

 

 

 

Share this post


Link to post
Share on other sites

Hey Pierre! I'm trying out your script as a solution to the loss of customizations when respawning vehicles and it seems to work perfectly.

 

A feature request:

 

Vanilla vehicle respawn will place a vehicle at its start position and facing its original direction. This is fairly important for missions where a motor pool might be placed in and around vehicle sheds/other structures/objects. Your script seems to only run getDir on the destroyed vehicle, so when respawning at "start" pos, it is facing the direction it was facing when destroyed. I could probably hack a fix in for myself (give me a few days :D), but this is a functionality that I think others might also appreciate in your fine script.

 

Thanks again, you're a treasure!

Share this post


Link to post
Share on other sites
Quote

Hey Pierre! I'm trying out your script as a solution to the loss of customizations when respawning vehicles and it seems to work perfectly.

 

A feature request:

 

Vanilla vehicle respawn will place a vehicle at its start position and facing its original direction. This is fairly important for missions where a motor pool might be placed in and around vehicle sheds/other structures/objects. Your script seems to only run getDir on the destroyed vehicle, so when respawning at "start" pos, it is facing the direction it was facing when destroyed. I could probably hack a fix in for myself (give me a few days :D), but this is a functionality that I think others might also appreciate in your fine script.

 

Thanks again, you're a treasure!


Absolutely needed.

Share this post


Link to post
Share on other sites

And now that I have thought about it for a second, it might be a more complex issue than it first seemed.

 

Share this post


Link to post
Share on other sites

Sorry I didn't read this post. I 'll be back with a correction soon.

  • Like 2

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

×