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 April 29th 2020

Totally reworked for better reliability in heavy scenario (MP/SP)

This script is also available as module in MGI ADVANCED MODULES, with more possibilities.

 

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_vehicleRespawn      //    equals to [ [WEST,EAST], ["myMrk1","death"], 15, false,false]

                   here, only WEST & EAST ai vehicles can respawn:

                       - on the marker "myMrk1" 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

 

___________________________________________________________________

 

SCRIPT

 

Spoiler

 


MGI_fnc_getVehicleLoadout = compileFinal " 
  _veh = param [0,objNull, [objNull]]; 
  _veh setVariable ['MGIallCont',[]]; 
  (_veh getVariable 'MGIallCont') pushBack [_veh,itemCargo _veh,magazinesAmmoCargo _veh,weaponsItemsCargo _veh,backpackCargo _veh]; 
  {(_veh getVariable 'MGIallCont') pushBack [_x select 0,itemCargo (_x select 1),magazinesAmmoCargo (_x select 1),weaponsItemsCargo (_x select 1),[]]} forEach everyContainer _veh; 
"; 
 
MGI_fnc_setVehicleLoadout = compileFinal " 
  params [['_newVeh',objNull,[objNull]], ['_oldVeh',objNull,[objNull]]]; 
  isNil { 
    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} forEach [1,2]; 
          [_newVeh,_act] remoteExec ['addaction',0,true]; 
          if(['bis_fnc_arsenal',_oldVeh actionParams _i select 1] call bis_fnc_instring) then { 
            _flagArsenalDbl = true 
          }; 
        }; 
      }; 
    }; 
 
    private _oldTexture = getObjectTextures _oldVeh; 
    if !(_oldTexture isEqualTo []) 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 !(_animList isEqualTo []) then { 
      private _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 = _oldVeh getVariable ['vehiclePylons', 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; 
    }; 
 
    if (!isNil {_oldveh getVariable 'vehicleFuel'}) then { 
      _newVeh setfuel (_oldVeh getVariable 'vehicleFuel') 
    }; 
 
    private _oldTrt = _oldVeh getVariable ['vehicleTrts',magazinesAllTurrets _oldVeh]; 
    {_newVeh removeMagazineTurret _x} forEach (magazinesAllTurrets _newVeh apply {[_x select 0,_x select 1]}); 
    {_newVeh addMagazineTurret _x} forEach _oldTrt; 
 
    { 
      _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]} count _it; 
      {_cont  addMagazineAmmoCargo [_x#0,1,_x#1]} count _mag; 
      {_cont addWeaponWithAttachmentsCargoGlobal [_x,1]} count _wp; 
      {_cont addBackpackCargoGlobal [_x,1]} count _bpk; 
    } forEach (_oldVeh getVariable ['MGIallCont',[]]); 
  }; 
"; 
 
fn_destroy = compileFinal " 
  params [['_destroyed',objNull]]; 
  private _oldPositionType = _destroyed getVariable ['oldPositionType','death']; 
  private _type = (_destroyed getVariable 'MGIrespVehDATA') select 0; 
  private _pos = (_destroyed getVariable 'MGIrespVehDATA') select 1; 
  private _side = (_destroyed getVariable 'MGIrespVehDATA') select 2; 
  private _fullOldCrew = (_destroyed getVariable 'MGIrespVehDATA') select 3; 
  private _varName = (_destroyed getVariable 'MGIrespVehDATA') select 4; 
  private _initDir = (_destroyed getVariable 'MGIrespVehDATA') select 5; 
  private _initTouch = (_destroyed getVariable 'MGIrespVehDATA') select 6; 
 
  private _initCode = (_destroyed getVariable ['MGIcustomCode','']); 
  private _respawnName =['initial point','grid'] select (_oldPositionType == 'death'); 
  private _cfgVeh = configfile >> 'cfgvehicles' >> typeOf _destroyed; 
  private _displayName = gettext (_cfgVeh >> 'displayName'); 
  private _picture = (gettext (_cfgVeh >> 'picture')) call bis_fnc_textureVehicleIcon; 
  private _curr = currentWaypoint group _destroyed; 
 
  private _posType = 'static'; 
  private _oldSpeed = _destroyed getVariable ['initSpeed',0]; 
  private _dir = _initDir; 
  if (_oldPositionType == 'death') then { 
    if (!isNil {_destroyed getVariable 'damPosDirSpd'}) then { 
      _pos = (_destroyed getVariable 'damPosDirSpd') #0; 
      _dir = (_destroyed getVariable 'damPosDirSpd') #1; 
      _oldSpeed = (_destroyed getVariable 'damPosDirSpd') #2; 
    } else { 
      _pos = getPosASL _destroyed; 
      _dir = getDir _destroyed; 
    }; 
    _posType = 'enRoute'; 
  }; 
  private _onGround = (isTouchingGround _destroyed && surfaceIsWater getpos _destroyed) or (ASLToATL _pos) #2 < 10; 
  private _respMode = ['FLY','CAN_COLLIDE'] select _onGround; 
 
  private _timer = diag_tickTime; 
  waitUntil {isTouchingGround _destroyed or diag_tickTime > _timer + 10}; 
  uiSleep MGIrespVehDelay; 
 
  _destroyed hideObjectGlobal true; 
  waitUntil {isHidden _destroyed}; 
  uisleep 1; 
 
  isNil { 
    private _newVeh =  createVehicle [_type, [0,0,0], [], 0, _respMode]; 
    _newVeh allowDamage false; 
     private _autonomous = (getText (configFile >> 'cfgVehicles' >> typeOf _destroyed >> 'vehicleClass') == 'Autonomous'); 
 
    if (!((_pos nearEntities [['landVehicle','air','CAManBase','ReammoBox_F'],(0 boundingBoxReal _newVeh) #2 /2]) isEqualTo []) && !surfaceIsWater _pos) then { 
      _pos = [_pos,0,100,(0 boundingBoxReal _newVeh) #2,1,0,0,[],[_pos,_pos]] call BIS_fnc_findSafePos; 
      _pos set [2,0.1]; 
    }; 
    _newVeh setDir _dir; 
    _newVeh setPosASL _pos; 
    _newVeh lock (locked _destroyed); 
    if !(_varName isEqualTo '') then { 
      [_newVeh,_varname] remoteExec ['setVehicleVarName',0,true]; 
      missionNameSpace setVariable [_varName, _newVeh, true]; 
    }; 
    [_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}; 
 
    if (count _fullOldCrew > 0 && ! _autonomous) then { 
      private _grps = []; 
      { 
        private _unit = _x select 0; 
        private _typeUnit = typeOf _unit; 
        private _ldout = _unit getVariable ['oldLdOut',getUnitLoadout typeOf _unit]; 
        private _grp = _unit getVariable ['oldGrp',createGroup side _newVeh]; 
        private _varNameUu = _unit getVariable ['oldVar','']; 
        _grps pushBackUnique _grp; 
        if (!alive _unit or !isTouchingGround _newVeh or _posType == 'static') then { 
          private _uu = _grp createUnit [_typeUnit,[0,0,0],[],0,'NONE']; 
          _uu  allowDamage false; 
          _uu setUnitLoadout _ldout; 
          if !(_varNameUu isEqualTo '') then { 
            [_uu,_varnameUu] remoteExec ['setVehicleVarName',0,true]; 
            missionNameSpace setVariable [_varNameUu, _uu, true]; 
          }; 
          deleteVehicle vehicle _unit; 
          _destroyed deleteVehicleCrew _unit; 
          switch toLower (_x select 1) do { 
            case 'driver': {_uu assignAsDriver _newVeh; _uu moveInDriver _newVeh}; 
            case 'commander': {_uu assignAsCommander _newVeh; _uu moveInCommander _newVeh}; 
            case 'gunner': {_uu assignAsGunner _newVeh; _uu moveInGunner _newVeh}; 
            case 'cargo': {_uu assignAsCargoIndex [_newVeh,(_x select 2)]; _uu moveInCargo [_newVeh,(_x select 2)]}; 
            case 'turret': {_uu assignAsTurret [_newVeh,(_x select 3)]; _uu moveInturret [_newVeh,(_x select 3)]}; 
          }; 
          [_uu] joinSilent _grp; 
          _uu allowDamage true; 
        } else { 
          _unit allowDamage false; 
          switch toLower (_x select 1) do { 
            case 'driver': {_unit assignAsDriver _newVeh; _unit moveInDriver _newVeh}; 
            case 'commander': {_unit assignAsCommander _newVeh; _unit moveInCommander _newVeh}; 
            case 'gunner': {_unit assignAsGunner _newVeh; _unit moveInGunner _newVeh}; 
            case 'cargo': {_unit assignAsCargoIndex [_newVeh,(_x select 2)]; _unit moveInCargo [_newVeh,(_x select 2)]}; 
            case 'turret': {_unit assignAsTurret [_newVeh,(_x select 3)]; _unit moveInturret [_newVeh,(_x select 3)]}; 
          }; 
          _unit allowDamage true; 
        }; 
      } forEach _fullOldCrew; 
      { 
        private _grp = _x; 
        if (count waypoints _grp >1 && (effectiveCommander _newVeh in units _grp)) then { 
          _grp selectLeader (effectiveCommander _newVeh); 
          [_grp,_curr,_newVeh] spawn { 
            params ['_grp','_curr','_newVeh']; 
            waituntil {sleep 1; if (_newVeh isKindOf 'air') then [{unitReady _newVeh},{TRUE}]};   comment 'seems to be necessary for some kind of assets. please report any lack of waypoints'; 
            _grp setCurrentWaypoint [_grp,_curr]; 
            leader _grp doMove (waypointPosition [_grp,_curr]); 
          }; 
        }; 
      } forEach _grps; 
    } else { 
      private _sideNbr = getNumber (configfile >> 'CfgVehicles' >> typeOf _newVeh >> 'side'); 
      _side = [EAST,WEST,INDEPENDENT,CIVILIAN,sideUnknown,sideEnemy,sideFriendly] select _sideNbr; 
    }; 
    if (_initCode != '') then { 
      (compile _initCode) remoteExec ['call',0,true]; 
      _newVeh setVariable ['MGIcustomCode',_initCode,true]; 
    }; 
    if (_autonomous) then { 
      if !(_fullOldCrew isEqualTo []) then { 
          createVehicleCrew _newVeh; 
        _grp = _destroyed getVariable ['oldUAVGrp',createGroup side (crew _newVeh select 0)]; 
        {[_x] joinSilent _grp} forEach crew _newVeh; 
        if (count waypoints _grp >1) then { 
          _grp setCurrentWaypoint [_grp,_curr]; 
          leader _grp doMove (waypointPosition [_grp,_curr]); 
        }; 
      } else { 
        {_newVeh deleteVehicleCrew _x} forEach crew _newVeh; 
      }; 
    }; 
    if (_oldSpeed != 0) then { 
      if (!_onGround or !_initTouch) then { 
        _newVeh setVelocityModelSpace [0,_oldSpeed/3.6,0]; 
      }; 
    }; 
    _newVeh setUnloadInCombat [true, false]; 
    if (isnull driver _newVeh) then { 
      if (!isTouchingGround _newVeh && !(_newVeh isKindOf 'ship')) then { 
        if (surfaceIsWater getPosASL _newVeh) then { 
          {_newVeh deleteVehicleCrew _x} count crew _newVeh; deleteVehicle _newVeh; 
        } else { 
          _newVeh allowDamage false; 
          _grdPos = getPosATL _newVeh; 
          _grdPos set [2,0.5]; 
          _newVeh setPosATL _grdPos; 
          _newVeh setVelocityModelSpace [0,0,0]; 
        }; 
        _newVeh engineOn false; 
        _newVeh animateSource ['canopy_hide',0,true]; 
      }; 
    }; 
 
    if (_destroyed in MGIrespVeh) then { 
      _idx = MGIrespVeh find _destroyed; 
      MGIrespVeh set [_idx, _newVeh]; 
      MGIrespVeh = MGIrespVeh - [objNull] 
    }; 
 
    if (!isNull _newVeh) then { 
      ['RespawnVehicle',[_displayName,_respawnName,_picture]] remoteExec ['BIS_fnc_showNotification',_side]; 
    }; 
    _destroyed setVariable ['MGIrespVehDATA',nil]; 
    _destroyed setVariable ['MGIrespVehOK',nil]; 
    _destroyed setVariable ['passedRespVeh',nil]; 
    deleteVehicle _destroyed; 
    _newVeh spawn { 
      params ['_newVeh']; 
      uiSleep 3; 
      _newVeh allowDamage true; 
    }; 
  }; 
"; 
 
fn_pos = compileFinal " 
  params ['_positionType','_veh','_pos']; 
  call { 
    if !(getMarkerPos _positionType isEqualTo [0,0,0]) exitWith { 
      _pos = AGLToASL getMarkerPos [_positionType,TRUE]; 
    }; 
    if (_positionType == 'start' or (_veh getVariable ['emptyVeh',false])) exitWith {_pos = getPosASL _veh}; 
      _pos = [0,0,0]; 
    }; 
    _pos 
  "; 
 
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 (_vehs isEqualType objnull or _vehs isEqualType WEST) then {_vehs = [_vehs]}; 
  MGIrespVeh = +_vehs; 
  if (_positions isEqualType "") then { 
    _positions = [_positions]; 
  }; 
  private _nbrEntries = count _vehs; 
  private _nbrPos = count _positions; 
  if (_nbrPos < _nbrEntries) then { 
    for "_i" from 0 to (_nbrEntries - _nbrPos - 1) do { 
      _positions pushback "death"; 
    }; 
  }; 
  _positions = _positions apply {if (getMarkerpos _x isEqualTo [0,0,0] && _x != "start") then {"death"} else {_x}}; 
  private ["_idx","_positionType"]; 
 
  while {true} do { 
    uiSleep 1; 
    private _allVehicles = vehicles select {!(_x isKindOf "WeaponHolderSimulated" or _x isKindOf "Ejection_Seat_Base_F" or _x isKindOf "ParachuteBase") && local _x && alive _x}; 
    { 
      _x setVariable ["passedRespVeh",true]; 
      if (fullCrew _x isEqualTo []) then { 
        _x setVariable ["emptyVeh",true] 
      } else { 
        _x setVariable ["emptyVeh",false] 
      }; 
      private _emptyThis = (_x getVariable "emptyVeh") && _empty; 
 
      if (side _x in +_vehs or _x in MGIrespVeh or _emptyThis) then { 
        call { 
          if (_x in MGIrespVeh) exitWith {_x setVariable ["MGIrespVehOK",TRUE]}; 
          if (side _x != CIVILIAN) exitWith {_x setVariable ["MGIrespVehOK",TRUE]}; 
          if (side _x == CIVILIAN && !(_x getVariable "emptyVeh") && CIVILIAN in +_vehs) exitWith {_x setVariable ["MGIrespVehOK",TRUE]}; 
          if (_emptyThis && _x isKindOf "allVehicles") exitWith {_x setVariable ["MGIrespVehOK",TRUE]}; 
        }; 
 
        if (!isNil {_x getVariable "MGIrespVehOK"}) then { 
 
          _x addEventHandler ["handledamage", { 
            params ["_veh","_hit","_dam"]; 
            if (isNil {_veh getVariable "vehicleLoadout"}) then { 
              _veh call MGI_fnc_getVehicleLoadout; 
              _veh  setVariable ["vehicleLoadout",TRUE]; 
            }; 
            [_veh,_thisEventHandler] spawn { 
              params ["_veh","_eh"]; 
              private _timer = diag_tickTime; 
              if (isnil {_veh getVariable "respDamaged"}) then { 
                _veh setVariable ["respDamaged",true]; 
                if (alive _veh) then { 
                  if (_veh isKindOf 'air') then { 
                    private _onGround = (isTouchingGround _veh && surfaceIsWater getpos _veh) or getPosATL _veh #2 < 10; 
                    private _altPos = if (_onGround && speed _veh > getNumber (configFile >> "cfgVehicles" >> typeOf _veh >> "stallSpeed") && _veh isKindOf "plane") then [{_veh modelToWorldWorld [0,0,200]},{getPosASL _veh}]; 
                    _veh setVariable ['damPosDirSpd',[_altPos,getdir _veh,speed _veh]]; 
                  }; 
                }; 
                waitUntil {uiSleep 0.5; diag_tickTime > _timer + 1}; 
                _veh setVariable ["respDamaged",nil]; 
                _veh removeEventHandler ["handleDamage",_eh]; 
              }; 
            }; 
            _dam 
          }]; 
 
          group _x deleteGroupWhenEmpty false; 
          call { 
            if (side _x in +_vehs) exitWith { 
              _idx = +_vehs find (side _x); 
              _positionType = _positions select _idx; 
              _x setVariable ["oldPositionType",_positionType]; 
            }; 
            if (_x in MGIrespVeh) exitWith { 
              _idx = MGIrespVeh find _x; 
              _positionType = _positions select _idx; 
              _x setVariable ["oldPositionType",_positionType]; 
            }; 
            _positionType = _x getVariable ["oldPositionType","death"]; 
          }; 
          private _pos = [_positionType,_x] call fn_pos; 
          _x setVariable ["MGIrespVehDATA",[typeOf _x ,_pos, side _x,fullcrew _x select {alive (_x select 0) && !((_x select 0) in ([[player],playableUnits] select isMultiplayer))},vehicleVarName _x,getDir _x,isTouchingGround _x]]; 
 
          if (_x isKindOf "plane") then { 
            _type = typeOf _x; 
            _initSpeed = getNumber (configfile >> "CfgVehicles" >> _type >> "stallSpeed") max getNumber (configfile >> "CfgVehicles" >> _type >> "landingSpeed") max 150; 
            _x setVariable ["initSpeed",_initSpeed]; 
          }; 
 
          if (_positionType != "death") then { 
            _x setVariable ["vehicleTrts",magazinesAllTurrets _x]; 
            _x setVariable ["vehicleFuel", fuel _x]; 
            if (_x isKindOf "air") then { 
              _x setVariable ["vehiclePylons",getPylonMagazines _x]; 
            }; 
          }; 
          if ((_positionType != "start" && !(_x getVariable ["emptyVeh",false])) or MGIrespOnDisabled) then { 
            _x spawn { 
              params ["_veh"]; 
              private _type = typeOf _veh; 
              if (getText (configFile >> 'cfgVehicles' >> _type >> 'vehicleClass') == 'Autonomous') then { 
                _veh setVariable ["oldUAVGrp",group (crew _veh select 0)]; 
              }; 
              while {alive _veh} do { 
                uiSleep 2; 
                if ((fullCrew _veh findIf {alive (_x #0)} > -1) && canMove _veh) then { 
                  private _fullOldCrew = +(fullCrew _veh select {alive (_x select 0) && !((_x select 0) in ([[player],playableUnits] select isMultiplayer))}); 
                  { 
                    (_x #0) setVariable ["oldGrp",group (_x #0)]; 
                    (_x #0) setVariable ["oldVar",vehicleVarName (_x #0)]; 
                    (_x #0) setVariable ["oldLdOut",getUnitLoadout [(_x #0),true]]; 
                  } forEach _fullOldCrew; 
                  (_veh getVariable "MGIrespVehDATA") set [3,_fullOldCrew]; 
                } else { 
                  if(MGIrespOnDisabled && !canmove _veh) exitWith { 
                    uiSleep MGIrespVehDelay/2; 
                    if (crew _veh findIf {alive _x} < 0) then { 
                      _veh setDamage [1,false]; 
                    }; 
                  }; 
                }; 
              }; 
            }; 
          } else { 
            { 
              (_x #0) setVariable ["oldGrp",group (_x #0)]; 
              (_x #0) setVariable ["oldVar",vehicleVarName (_x #0)]; 
              (_x #0) setVariable ["oldLdOut",getUnitLoadout [(_x #0),true]]; 
            } forEach fullCrew _x; 
          }; 
        }; 
      }; 
    } foreach (_allVehicles select {isNil {_x getVariable "passedRespVeh"}}); 
  }; 
}; 
 
addMissionEventHandler ["EntityKilled",{ 
  params ["_destroyed"]; 
  if (!isNil {_destroyed getVariable "MGIrespVehOK"} && !(_destroyed isKindOf "CAManBase")) then { 
    _destroyed spawn fn_destroy; 
  }; 
}]; 
 
0 = [[crate2,WEST,karl,CIVILIAN],["death","start","start","start"],10,true,false] spawn MGI_fnc_VehicleRespawn;

 

 

 

 

 

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 script, 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.

Spoiler

 

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.

Version 09102019: spawning vehicles on carrier at sea.

Version 13103019: fuel management and some extra cases

Version 26112019: all mags are restored with the exact ammo count.

Version 19122019: respawned vehicle is locked same as destroyed one.

Version 19042020: better reliability in heavy mission context. All in one script.

Version 21072020: repaired UAV respawn

 

  • Like 9
  • Thanks 2

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

Thank you Pierre.. changed it and now works perfect :) Thank you my friend..Ding

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

×