Jump to content
Sign in to follow this  
pcc

Destroying vehicles with dead crew in warfare

Recommended Posts

I tried if({alive _x} count (crew _x)) == 0) in Common_UpdateEmptyVehicle.sqf. 

Spoiler

scriptName format ["%1Scripts\Common\Common_UpdateEmptyVehicle.sqf",BIS_WFdPath];
//Last modified 11/17/9
//Run any common initialization on a unit including cleanup routines after death.
Private["_destroy","_timeLeft","_vehicle"];

_vehicle = _this Select 0;
_destroy = true;

//if (Count Crew _vehicle > 0) ExitWith {};
if({alive _x} count (crew _x)) > 0) ExitWith {};
//Unlock abandoned AI vehicles...
_vehicle Lock false;

//If vehicle stays empty for 5 minutes then remove it.
_timeLeft = time + (BIS_WF_Constants GetVariable "ABANDONEDVEHICLETIME");

while {time < _timeLeft} do
{
	Sleep 10;

	//if (Count Crew _vehicle > 0) ExitWith {_destroy = false};
  	if({alive _x} count (crew _x)) > 0) ExitWith {_destroy = false};
};

if (_destroy) then
{
	//Avoid explosions...;)
	_vehicle SetAmmoCargo 0;
	_vehicle SetFuelCargo 0;
	_vehicle SetDamage 1;
};

 

 

Also tried adding killed eventhandler to Common_InitUnit.sqf, but neither worked.

	if ((BIS_WF_Constants GetVariable "ABANDONEDVEHICLETIME") > 0) then
		{
			_unit AddEventHandler ["GetOut",{_this Spawn BIS_WF_UpdateEmptyVehicle}];
			_unit AddEventHandler ["killed",{_this Spawn BIS_WF_UpdateEmptyVehicle}];
		};

 

Share this post


Link to post
Share on other sites

Not tested, but maybe this will work in Server\Server_UpdateCleanup.sqf

 

Change this:

Spoiler

	if (!_visible) then
	{
		DeleteVehicle (_x Select 1);
		BIS_WF_Bodies Set[_count,ObjNull];
		if (IsNil "BIS_WF_BodiesCleaned") then {BIS_WF_BodiesCleaned = 1} else {BIS_WF_BodiesCleaned = BIS_WF_BodiesCleaned + 1};
	};

 

 

To this:

Spoiler

	if (!_visible) then
	{
		Private "_body";
		_body = _x select 1;

		if (_body != Vehicle _body) then 
		{
			Private "_vehicle";
			_vehicle = Vehicle _body;
			_body setPos [_unit select 0, _unit select 1, 0];
			DeleteVehicle _body;
			[_vehicle] spawn BIS_WF_UpdateEmptyVehicle;
		} else 
		{
			DeleteVehicle (_x Select 1);
		};
		BIS_WF_Bodies Set[_count,ObjNull];
		if (IsNil "BIS_WF_BodiesCleaned") then {BIS_WF_BodiesCleaned = 1} else {BIS_WF_BodiesCleaned = BIS_WF_BodiesCleaned + 1};
	};

 

 

DeleteVehicle doesn't work on the body in the vehicle.  Command moveOut and action "GetOut" also don't work on dead bodies.  So the thought is that setPos might place the body on the ground below the vehicle, kind of obscured from sight, and once removed from the vehicle it gets deleted.

 

-- Edit:  Code updated,   forgot that _x is an array, containing time as well as dead unit.

Edited by opusfmspol
  • Like 1

Share this post


Link to post
Share on other sites

Just saw the edit, going to test.

Edit: The crew still in vehicle.  

If only they could eject like with atv and static defenses.

 

Late Edit: 

On 2/24/2017 at 6:00 PM, opusfmspol said:

DeleteVehicle doesn't work on the body in the vehicle.  Command moveOut and action "GetOut" also don't work on dead bodies.  So the thought is that setPos might place the body on the ground below the vehicle, kind of obscured from sight, and once removed from the vehicle it gets deleted.

 

Was trying to decrease script load like external looping delete unit scripts and happened to discovered that it works in Common_UnitKilled.sqf.  

if (IsServer && _isSoldier) then
{
	unassignVehicle _victim;
	_victim setPos (getPos (vehicle _victim));
	BIS_WF_Bodies = BIS_WF_Bodies + [[time,_victim]];
	[_victim] Select 0 spawn {sleep 4; hideBody _this; sleep 4;deleteVehicle _this};
...

 

Share this post


Link to post
Share on other sites

It's odd, because this added into the Init field of an editor unit works in A2 and OA:

this addEventHandler ["Killed", {_niv = [_this select 0] spawn {_body = _this select 0; _veh = Vehicle _body; if (_veh != _body) then {_pos = position _veh; sleep 5; _body setPos _pos; deleteVehicle _body;_niv1 = [_veh] spawn {sleep 5; deleteVehicle (_this select 0);};};};}];

It's very much the same idea.

 

Test example:

1)  Place player, group member and empty vehicle in editor.

2)  Add code to the group member Init field.

3)  Launch mission and order unit into the vehicle.

4)  Shoot member in the vehicle dead.

5)  Five second delay and the body is deleted.

6)  Five second delay and the vehicle is deleted.

 

Were you within 100m of the vehicle?  Because Server_UpdateCleanup won't run the code if a player is within 100m.

 

--edit:
After unit killed: Body cleanup time = BIS_WF_Constants variable "BODYCLEANUPTIME" (default 5 min)
After body deleted: Vehicle destroy time = BIS_WF_Constants variable "ABANDONEDVEHICLETIME" (default 15 min)
After vehicle destroyed: Vehicle cleanup time = Sleep 600 (10 min)

 

Each has to be observed from +100m at event time.

Edited by opusfmspol
  • Like 1

Share this post


Link to post
Share on other sites

I set both to 1 in in Init_Common.sqf.

BIS_WF_Constants SetVariable["ABANDONEDVEHICLETIME",1];
BIS_WF_Constants SetVariable["BODYCLEANUPTIME",1];

I bought a hmmwv with 1 AI crew.  After killing him I moved away, drove around a bit then came back, but crew stayed slumped in the vehicle. :(

With ATV and motorcycle, after killing the driver the vehicles self destruct almost right away even with me next to it.

Share this post


Link to post
Share on other sites

Been working with this.  The problem seems to stem from an object reference issue.

 

At the time the unit is killed their variable is a group reference, e.g. B 1-1-A:2.  setPos of the unit apart from the vehicle will work while the unit has its group reference.  But once the leader knows the unit is dead ("We lost 2!") the unit goes to grpNull, becomes an empty object, and becomes an object reference, e.g. ###: usmc_soldier.p3d.  But for some reason not clear to me, the unit object and the vehicle object become the same reference.  diag_log on the unit and the vehicle separately returned ###: usmc_soldier.p3d references for both.  At that point, not only does BIS_WF_isSoldier return true on the vehicle, but SetPos of the unit apart from the vehicle doesn't work.

  • Like 1

Share this post


Link to post
Share on other sites
On ‎2‎/‎25‎/‎2017 at 8:26 AM, pcc said:

I set both to 1 in in Init_Common.sqf.


BIS_WF_Constants SetVariable["ABANDONEDVEHICLETIME",1];
BIS_WF_Constants SetVariable["BODYCLEANUPTIME",1];

I bought a hmmwv with 1 AI crew.  After killing him I moved away, drove around a bit then came back, but crew stayed slumped in the vehicle. :(

With ATV and motorcycle, after killing the driver the vehicles self destruct almost right away even with me next to it.

 

The ATV and Motorcycle likely occurred because the killed unit automatically dismounted.  I observed that.  With the other vehicles they don't.

 

Found something that seems to work.  Involves changes to four scripts.  It's important to detect very early on whether a soldier is in a vehicle before he gets removed from group.  There are some new variables, so adjust Private arrays as needed.

 

This is the "killed" event handler for every unit, soldier and vehicle.  Depending on type and locality it sends the unit to one of two scripts for cleanup.
Common\Functions\Common_UnitKilled.sqf

Spoiler

Change this:


if (IsServer && _isSoldier) then
{
	BIS_WF_Bodies = BIS_WF_Bodies + [[time,_victim]];
}
//Client bodies or client/server vehicles.
else
{
	[_victim] Spawn BIS_WF_UpdateUnitCleanup;
};

 

To this:


if (IsServer && _isSoldier) then
{
	_vehicle = Vehicle _victim;
	_unitType = typeOf _victim;
	_vehicleType = typeOf _vehicle;

	BIS_WF_Bodies = BIS_WF_Bodies + [[time,_victim,_vehicle,_unitType,_vehicleType]];
}
//Client bodies or client/server vehicles.
else
{
	[_victim] Spawn BIS_WF_UpdateUnitCleanup;
};

 

 

This is the cleanup script for soldiers belonging to the server.  It runs from game start, looping every thiry seconds cleaning the BIS_WF_Bodies array while a player is not near.  The issue is that it cannot delete a dead body in a vehicle, especially after its group has gone null.  The vehicle has to be sent to Common_UpdateEmptyVehicle.sqf instead.
Server\Server_UpdateCleanup.sqf
 

Spoiler

Change this:


	ScopeName "CleanupBody";
			
	_unit = GetPos (_x select 1);
	_objects = _unit NearEntities[["Man","Car","Motorcycle","Tank"],100];
	_visible = false;

	{
		if (IsPlayer _x) then {_visible = true;BreakTo "CleanupBody"};
	} ForEach _objects;

	if (!_visible) then
	{
		DeleteVehicle (_x Select 1);
		BIS_WF_Bodies Set[_count,ObjNull];
		if (IsNil "BIS_WF_BodiesCleaned") then {BIS_WF_BodiesCleaned = 1} else {BIS_WF_BodiesCleaned = BIS_WF_BodiesCleaned + 1};
	};

 

To this:


	ScopeName "CleanupBody";

	_unit = GetPos (_x select 1);
	_vehicle = _x select 2;
	_unitType = _x select 3;
	_vehicleType = _x select 4;

	_objects = _unit NearEntities[["Man","Car","Motorcycle","Tank"],100];
	_visible = false;

	{
		if (IsPlayer _x) then {_visible = true;BreakTo "CleanupBody"};
	} ForEach _objects;

	if (!_visible) then
	{
		DeleteVehicle (_x Select 1);
		BIS_WF_Bodies Set[_count,ObjNull];
		if (IsNil "BIS_WF_BodiesCleaned") then {BIS_WF_BodiesCleaned = 1} else {BIS_WF_BodiesCleaned = BIS_WF_BodiesCleaned + 1};
		if (_unitType != _vehicleType) then {_niv = [_vehicle] spawn BIS_WF_UpdateEmptyVehicle;};
	};

 

 

This is the cleanup script for vehicles belonging to the server, and for soldiers and vehicles belonging to Clients.  It gets spawned by the "killed" event handler.  It sleeps either 5 or ten minutes, then tries to delete when a player is not near.  If player is still near after another 10 minutes, it deletes anyway.  The issue is that it cannot delete a dead body in a vehicle, especially after its group has gone null.  The vehicle has to be sent to Common_UpdateEmptyVehicle.sqf instead.
Common\Common_UpdateUnitCleanup.sqf
 

Spoiler

At the beginning, change this:
 


_unit = _this Select 0;

if (!(_unit Call BIS_WF_IsSoldier) || IsNull Group _unit) then {Sleep 600}
else {Sleep 300};

to this:
 


_unit = _this Select 0;
_vehicle = Vehicle _unit;
_unitType = typeOf _unit;
_vehicleType = typeOf _vehicle;

if (!(_unit Call BIS_WF_IsSoldier) || IsNull Group _unit) then {Sleep 600}
else {Sleep 300};

 

At the end, change this:
 


	Sleep 30 + Random 5;
};

DeleteVehicle _unit;

To this:
 


	Sleep 30 + Random 5;
};

DeleteVehicle _unit;

if (_unitType != _vehicleType) then {_niv = [_vehicle] Spawn BIS_WF_UpdateEmptyVehicle;};

 

 

This is the "GetOut" event handler added to every vehicle.  Its the cleanup script for abandoned vehicles.  It also needs to be spawned to serve as the cleanup script when crew are killed in vehicles.
Common\Common_UpdateEmptyVehicle.sqf
 

Spoiler

Change this:
 


_vehicle = _this Select 0;
_destroy = true;

if (Count Crew _vehicle > 0) ExitWith {};

//Unlock abandoned AI vehicles...
_vehicle Lock false;

//If vehicle stays empty for 5 minutes then remove it.
_timeLeft = time + (BIS_WF_Constants GetVariable "ABANDONEDVEHICLETIME");

while {time < _timeLeft} do
{
	Sleep 10;

	if (Count Crew _vehicle > 0) ExitWith {_destroy = false};
};

if (_destroy) then
{

To this:
 


_vehicle = _this Select 0;
_destroy = true;

if ({alive _x} Count Crew _vehicle > 0) ExitWith {};

//Unlock abandoned AI vehicles...
_vehicle Lock false;

//If vehicle stays empty for 5 minutes then remove it.
_timeLeft = time + (BIS_WF_Constants GetVariable "ABANDONEDVEHICLETIME");

while {time < _timeLeft} do
{
	Sleep 10;

	if (isNull _vehicle) exitWith {_destroy = false;};
	if ({alive _x} Count Crew _vehicle > 0) ExitWith {_destroy = false;};
};

if (_destroy) then
{

 

 

I haven't been able to test it in multiplayer yet, my other computer is down.  You were right in your post on beta, it needed to count live crew rather than just crew.
 

  • Like 1

Share this post


Link to post
Share on other sites

Run this script on all vehicles you want to be cleaned, it destroys abandoned vehicles, or vehicles with dead crew after 3 minutes. If the player gets in the vehicle, the script will obviously hold off on blowing up the vehicle.

 

_unit = _this;
_stacks = 0;

while {alive _unit} do
{

if ({alive _x} count crew _unit <= 0) then {

	_stacks = _stacks + 1;

	if(_stacks >= 3) then {	
		_unit setDamage 1;	
	};
	
};

sleep 60;

};

 

Combine this with the master "cleaning script" that loops on the server itself:

 

if(isDedicated) then {

while {true} do {

// Clean dead units
{deleteVehicle _x;} forEach allDead;

// Clean abandoned
{
_unit2 = _x;
if((owner _unit2) <= 2 && _unit2 getVariable["ServerVehicle",0] != 1) then {
deleteVehicle _x;
diag_log "Deleted unit for no ownership";
};

} forEach allUnits;

// Clean far units
{
	_unit = _x;
	if ((side _unit) == east) then {
		if ( ({(_unit distance _x) > 800} count playableUnits) == ({isplayer _x} count playableUnits) ) then {
			deletevehicle _unit;
			diag_log "Deleted unit for too far";
		};
	};
} forEach allUnits;

// Clean far vehicles
{
	_unit = _x;
		if ( ({(_unit distance _x) > 800} count playableUnits) == ({isplayer _x} count playableUnits) && _unit getVariable["ServerVehicle",0] != 1) then {
			deletevehicle _unit;
			diag_log "Deleted vehicle for too far";
		};
} forEach vehicles;

sleep 300;

};

};

Make sure to change the side from east, to whatever you use for your enemy AI. You can also play with the distance from 800. In addition, any vehicles in your map that you give the setVariable ["ServerVehicle", true], will be skipped by the cleaner.

Edited by ezremake
Fixed getVariable checks
  • Like 1

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×