Jump to content
omri2050

AI surrender when some of group dies - video

Recommended Posts

@omri2050,
Here's a function which requires the unit to enter "fleeing" state before surrendering.

Spoiler

You_fnc_capture={	params [["_grp", grpNull, []]];

[_grp] spawn {
		{
		waitUntil {sleep 1; fleeing _x};
		if (fleeing _x) exitWith {
				_x setCaptive true;
				_x action ["surrender", _x]
			};
		} forEach units (_this select 0);
	};
};

[group this] spawn you_fnc_capture;

 

Have fun!

  • Like 1

Share this post


Link to post
Share on other sites

Adding to the code to have the surrendering ai to drop or put down their weapons would add a bit more immersion to it.

  • Like 2

Share this post


Link to post
Share on other sites

@Gunter Severloh,
Here ya go,

Spoiler

You_fnc_capture={	params [["_grp", grpNull, []]];

[_grp] spawn {
		{
		waitUntil {sleep 1; fleeing _x};
		if (fleeing _x) exitWith {
				_x setVariable ["you_surrender", true];
				_x setCaptive true;
				_x action ["surrender", _x];
	removeAllWeapons _x; removeHeadgear _x; _x unlinkItem "NVGoggles"; removeAllItems _x;
			};
		} forEach units (_this select 0);
	};
};

[group this] spawn you_fnc_capture;

*edit: let's stick a variable in there

And a button,


[player, "Capture Unit", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"(_this distance cursorTarget) <4 && {cursorTarget getvariable ""you_surrender""} && {alive cursorTarget} && {!((faction cursorTarget) == (faction _this))}", "isNull objectParent _this", {}, {}, {
cursorTarget disableAI "ALL";
cursorTarget switchMove "revive_secured";
[cursorTarget, _caller] spawn {private _time= time + 30; waitUntil {time>_time || ((_this select 0) distance (_this select 1))>10};
deleteVehicle (_this select 0);
systemChat "Captive Secured";
};
}, {}, [], 5, 0, false, false] call BIS_fnc_holdActionAdd;

Captive is hog-tied for 30 seconds or until player moves away.


Have fun!

  • Like 3

Share this post


Link to post
Share on other sites

Well, for the "drop their weapons" part I have a prepared script (used in a personal project). Here it is in case you would like to use it or adapt it to your needs

/*
 * Function named You_fnc_surrender
 */

// Get the passed parameters
params[["_unit", objNull, [objNull]]]; // Get the unit

// Do some parameter checking
if(_unit isEqualTo objNull) exitWith {
	// Log the error and print a message to the user
	["Given unit is null"] call BIS_fnc_error;
};

// Give the script to the scheduler
private _nil = [_unit] spawn {
  // Get the parameters
  _unit = _this select 0; // The unit to surrender

  // Drop weapons
  _wh = "GroundWeaponHolder_Scripted" createVehicle (getPos _unit); // Create a ground weapon holder

  // Drop primary weapon
  _unit action["DropWeapon", _wh, primaryWeapon _unit]; // Drop the primary weapon
  waitUntil {
	uiSleep 0.5; // Wait a bit to save some CPU cycles
	(primaryWeapon _unit) isEqualTo ""; // Wait until main weapon is dropped
  };

  // Drop handgun
  _unit action["DropWeapon", _wh, handgunWeapon _unit]; // Drop the handgun
  waitUntil {
	uiSleep 0.5; // Wait a bit to save some CPU cycles
	(handgunWeapon _unit) isEqualTo ""; // Wait until handgun is dropped
  };

  // Drop secondary weapon
  _unit action["DropWeapon", _wh, secondaryWeapon _unit]; // Drop the secondary weapon
  waitUntil {
	uiSleep 0.5; // Wait a bit to save some CPU cycles
	(secondaryWeapon _unit) isEqualTo ""; // Wait until secondary weapon is dropped
};

  // Make the unit surrender
  _unit action["Surrender", _unit]; // Surrender
  _unit setCaptive true; // Set as captive

  // Delete the ground weapon holder
  deleteVehicle _wh; // Needs to be checked. The weapons that were dropped may be destroyed.
					 // In this case we are to remove the deleteVehicle command.
};

Please note that this function does not remove all the items from the unit as it is meant to add some "immersion/realism", where you wouldn't expect the items of a unit to just vanish. Instead, the unit drops all its weapons. It is quite straight forward to remove any of the drops in order to make the unit not drop any of its weapons. Additionally, you could use something like

private _cWeapon = currentWeapon; // Get the current weapon
_unit action["DropWeapon", _wh, _cWeapon]; // Drop current weapon
waitUntil {
	uiSleep 0.5; // Sleep a bit to save some CPU cycles
	!((currentWeapon _unit) isEqualTo _cWeapon); // Wait until current is dropped
};

in order to make the unit drop only its currently holding weapon.

 

So, you could possibly use the above function in the same way wogz187 suggests like (copying wogz187's code and changing some parts)

// Set your function
You_fnc_capture = {
  // Get parameters
  params [["_grp", grpNull, [grpNull]]]; // Get the group (added valid types)

  // Pass code to the scheduler
  [_grp] spawn {
    private _grpUnits = units (_this select 0); // Get the units directly

	// Wait until the group flees
	waitUntil {
      sleep 1; // Sleep to save some CPU
	  fleeing (_grpUnits select 0); // Check only one of the units
                                    // because the whole group flees as a whole or none at all
	};
	
    {
      _x setVariable ["you_surrender", true]; // Keep this variable if you want
	  [_x] call You_fnc_surrender; // Make the unit surrender
	} forEach _grpUnits;
  };
};

// Call your function
[group this] call you_fnc_capture; // Changed spawn to call as there's no need to spawn it (no sleep in the function)

Hope this helps a wee bit.

 

Happy ArmA and please don't hesitate to ask more questions if you want to.

Edited by ZaellixA
Deleted the if() exitWith{} part as it was not needed
  • Like 2

Share this post


Link to post
Share on other sites

@ZaellixA,

Nice.

My previous post didn't make sense but we should still exit if the group is null.
 

Quote

[group this] call you_fnc_capture; // Changed spawn to call as there's no need to spawn it (no sleep in the function)


That's how I originally wrote the it but then I thought it was redundant because the function if called, read straight it would be,

[params] call {[params] spawn {script};};
//instead of,
[params] spawn {script};

Is that wrong?
 

Have fun!

Share this post


Link to post
Share on other sites
2 hours ago, wogz187 said:

Is that wrong?

I can't see something wrong with what you got. I only changed the spawn to call because in the main body of the function there's no sleep (or other "delay") command, so there's no actual reason to give the whole function to the scheduler, you can just execute it.

 

Obviously, inside the function, you do give some code to the scheduler with spawn but this has nothing to do with the execution of the function. The function actually just gets the parameters and passes them to the code that is given to the scheduler. Thus, no sleeps in the function, so no need to spawn instead of call. So, I thought it would be better not to clutter the scheduler with scripts.

 

Of course one could omit entirely the creation of a function and just do something like

/*
 * Script file called surrender.sqf
 */

// Get parameters
params [["_grp", grpNull, [grpNull]]]; // Get the group (added valid types)

// Pass code to the scheduler
[_grp] spawn {
  private _grpUnits = units (_this select 0); // Get the units directly

  // Wait until the group flees
  waitUntil {
    sleep 1; // Sleep to save some CPU
	fleeing (_grpUnits select 0); // Check only one of the units
                                  // because the whole group flees as a whole or none at all
  };
	
  {
    _x setVariable ["you_surrender", true]; // Keep this variable if you want
	[_x] call You_fnc_surrender; // Make the unit surrender
  } forEach _grpUnits;
};

And then just call the script like

[group this] call compile preprocessFileLineNumbers "surrender.sqf";

Although, using compile preprocessFileLineNumbers is not the best idea ever. So you could change the script a little bit like

/*
 * Script file called surrender.sqf
 */

// Get parameters
params [["_grp", grpNull, [grpNull]]]; // Get the group (added valid types)

private _grpUnits = units _grp; // Get the units

// Wait until the group flees
waitUntil {
  sleep 1; // Sleep to save some CPU
  fleeing (_grpUnits select 0); // Check only one of the units
                                // because the whole group flees as a whole or none at all
};
	
{
  _x setVariable ["you_surrender", true]; // Keep this variable if you want
  [_x] call You_fnc_surrender; // Make the unit surrender
} forEach _grpUnits;

and instead of calling the script that will just get the parameter and then just pass it to the code that the scheduler will handle, you can give the script directly to the scheduler. The only overhead imposed to the scheduler here is to get the parameter and create the local variable to hold it. I am not sure how much this is for ArmA but I would be it is nothing compared to the rest of the script commands. So with the above script, you should call it like

[group this] execVM "surrender.sqf";

Please, keep in mind that I have NOT tested any of those scripts so I cannot guarantee that they work. Additionally, I haven't performed any performance tests, so I cannot say whether one or the other way of calling and/or structuring the code is more efficient and in what way than the other. I would be glad to hear your opinions and results on any of those topics.

 

Happy ArmA :).

Edited by ZaellixA
Corrected the script
  • Like 1

Share this post


Link to post
Share on other sites

@omri2050,
The first script posted above was based on a single test. Upon further testing there are a lot of problems. Not the least of which-- fleeing is super unreliable!

If the units are spawned in the editor, and they have more than 0% ammunition, it is almost impossible to make them flee. With 0% ammo they will flee pretty much immediately (that's how I tested the above). Depleting ammo within the mission has a different effect than starting with no ammo, for some reason. So, under most circumstances the first code is totally useless.

This works a little better,
 

Spoiler

You_fnc_capture={	params [["_grp", grpNull, []]];

you_captureState={
	_this switchMove "";
	_this setVariable ["you_surrender", true];
	_this setCaptive true;
	_this action ["surrender", _this];
	removeAllWeapons _this; removeHeadgear _this; removeAllItems _this;
	};

	{
	[_x]spawn{	waitUntil {sleep 1; !alive (_this select 0) || fleeing (_this select 0) || damage (_this select 0) >0.5};
			if (!alive (_this select 0) || !isNull objectParent (_this select 0)) exitWith {false};
			(_this select 0) call you_captureState;
		};
	} forEach units _grp;
};

null=[group this] call you_fnc_capture;

pasted into the init of one unit in the group.

And,


null=[this, "Capture Unit", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"(_this distance cursorTarget) <4 && {cursorTarget getvariable ""you_surrender""} && {alive cursorTarget} && {!((faction cursorTarget) == (faction _this))}", "isNull objectParent _this", {}, {}, {
cursortarget setVariable ["you_surrender", false];
cursorTarget disableAI "ALL";
cursorTarget switchMove "revive_secured";
[cursorTarget, _caller] spawn {private _time= time + 30; waitUntil {time>_time || ((_this select 0) distance (_this select 1))>10};
deleteVehicle (_this select 0);
(_this select 1) sideChat "Captive Secured";
};
}, {}, [], 5, 0, false, false] call BIS_fnc_holdActionAdd;

pasted into the init of player(s).


Have fun!

Edited by wogz187
updated
  • Like 2

Share this post


Link to post
Share on other sites

@omri2050,
Here's a completely different method,

Example Mission (drive)

Spoiler

null=[group this] spawn {
	private _grp= (_this select 0);
	private _num= count units _grp;
	private _grpStr= 100 / _num;
	{
		_x setVariable ["you_grpStr", _grpStr];
	} forEach units _grp;
};

paste into init of one unit in group

init.sqf (or whatever),


you_captureState={
	_this switchMove "";
	_this setVariable ["you_surrender", true];
	_this setCaptive true;
	_this action ["surrender", _this];
	removeAllWeapons _this; removeHeadgear _this; removeAllItems _this;
	};


	addMissionEventHandler ["EntityKilled", {
		params ["_unit", "_killer"];
	private _grp= group _unit;
	private _count = {alive _x} count units _grp;
	private _per= _unit getVariable "you_grpStr";
	private _num= _per * _count;
//systemChat format ["%1, %2, %3", _count, _per, _num];
	if (_num > 59) exitWith {false};
		if (!((faction _unit) == (faction _killer)) && !((faction _unit) == "CIV_f")) exitWith {
			if (_killer==player && _killer distance _unit < 50) then {
			{
				private _surrender=selectRandom [true, false];
				if (_surrender || fleeing _unit) then {
					if (alive _x) then {
						_x call you_captureState
						};
					};
				} forEach units (group _unit);
			};
		};
	}];

and the capture button (init.sqf, player init, whatever),


null=[player, "Capture Unit", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"\a3\ui_f\data\IGUI\Cfg\holdactions\holdAction_connect_ca.paa", 
"(_this distance cursorTarget) <4 && {cursorTarget getvariable ""you_surrender""} && {alive cursorTarget} && {!((faction cursorTarget) == (faction _this))}", "isNull objectParent _this", {}, {}, {
cursortarget setVariable ["you_surrender", false];
cursorTarget disableAI "ALL";
cursorTarget switchMove "revive_secured";
[cursorTarget, _caller] spawn {private _time= time + 30; waitUntil {time>_time || ((_this select 0) distance (_this select 1))>10};
deleteVehicle (_this select 0);
(_this select 1) sideChat "Captive Secured";
};
}, {}, [], 5, 0, false, false] call BIS_fnc_holdActionAdd;

 

Once the majority of the group is killed there is a chance the rest will surrender.

Have fun!

Edited by wogz187
updated link
  • Like 3

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

×