Jump to content
Sign in to follow this  
tpw

TPWC AI suppression system

Recommended Posts

Anyone feeling brave? Here's a development version

I tested it on dedicated server again and it works really nice!

Took the liberty to make the debug mode dedicated server proof too and 'upgraded' the debug code to 'suppression training mode' by turning the 'balls' from green to yellow to red

Disclaimer: I did not test this with multiple clients yet: a dedicated server requires the ball color changing to run on every client, for which I used the CBA 'CBA_fnc_globalExecute' function.

I don't know the impact of network sync needed in case of a lot of suppression with a lot of players.

Anyway, this 'cheat' mode shouldn't be enabled in a real game in the first place, so I guess like this this is just a nice debug/training feature.

From now on everybody wants to be the heavy machine gunner and lay down some nice suppressing fire :p

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.02 20120626
*/ 

if (isServer || isDedicated) then {

diag_log format ["AI SUPPRESS STARTED: Server: %1 - Dedicated: %2", isServer, isDedicated];

////////////
//VARIABLES 
////////////

//Delay before suppression functions start. Allows time for other mods if needed
tpwc_ai_sup_sleep = 2;

//Debugging. Will display red balls over any suppressed units. 0 = no debugging, 1 = debugging
tpwc_ai_sup_debug = 1;

//Bullet detection radius (m). Bullets must pass within this distance of unit to suppress them. If set much below 10m, bullets may not be detected
tpwc_ai_sup_br = 10;

//Bullet ignore radius (m). Bullets from a shooter closer than this will not suppress.
tpwc_ai_sup_ir = 25;

//Shot threshold. More shots than this will cause unit to drop/crawl
tpwc_ai_sup_st = 5;

//Startup hint. 0 = no hint, 1 = hint
tpwc_ai_sup_hint = 1;

//Player suppression visuals. 0 = no player suppression, 1 = player suppression
tpwc_ai_sup_playersup = 1;

//Pistol and SMG ammo to ignore. Add custom ammo (eg suppressed) or change to taste
tpwc_ai_sup_mags =[
"30rnd_9x19_MP5",  
"30rnd_9x19_MP5SD",    
"15Rnd_9x19_M9",
"15Rnd_9x19_M9SD",
"7Rnd_45ACP_1911",
"7Rnd_45ACP_1911",
"8Rnd_9x18_Makarov",
"8Rnd_9x18_MakarovSD",
"64Rnd_9x19_Bizon",
"64Rnd_9x19_SD_Bizon",
"13Rnd_9mm_SLP",
"17Rnd_9x19_glock17",
"6Rnd_45ACP",
"30Rnd_9x19_UZI",
"30Rnd_9x19_UZI_SD" 
];

//////////
// SET UP
//////////

//Declare private variables
private ["_stanceregain","_skillregain","_unit","_bc","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball","_skillset","_asr"];

//Allow time for ASR AI skills to propagate
sleep tpwc_ai_sup_sleep;

//Start hint
if (tpwc_ai_sup_hint == 1) then {
0 = [] spawn {
hintsilent "TPWC AI Suppress 1.02 Active";
sleep 3;
hintsilent ""};
};


//////////////////
// MAIN FUNCTIONS 
//////////////////

//BULLET DETECTION LOOP (TIME CRITICAL)
tpwc_ai_sup_detect =
{
   {
   _unit = _x;
   if !(isnull tpwc_ai_sup_bullet) then
       {
       _bc = count ((getposatl _unit) nearobjects ["bulletbase",tpwc_ai_sup_br]);
       if (_bc > 0) then
           {
           if ((tpwc_ai_sup_fired distance _unit) > tpwc_ai_sup_ir) then
               {
               if !(tpwc_ai_sup_mag in tpwc_ai_sup_mags) then
                   {
                   _unit setvariable ["tpwc_skillregain", diag_ticktime + (random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage"))];
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];
                   _unit setvariable ["tpwc_supshots",(_unit getvariable "tpwc_supshots") + _bc];
                   _unit setvariable ["tpwc_suppressedstance", 1];
                   if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
                       {
                       _unit setvariable ["tpwc_suppressedstance", 2];
                       if (_unit getvariable "tpwc_supshots" > tpwc_ai_sup_st) then
                           {
                           _unit setvariable ["tpwc_suppressedstance", 3];
                           };
                       };
                   };
               };
           };
       };
   } foreach allunits;
};


//UNIT STANCE/SKILL MODIFICATION LOOP (NON TIME CRITICAL)
tpwc_ai_sup_behaviour =
{
tpwc_ai_sup_supvisflag = 0;
while {true} do
   {
       {
       if (alive _x) then
           {
           _unit  = _x;
           _skillregain = _unit getvariable ["tpwc_skillregain", -1];
           _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];

           //Set initial parameters for each unit
           if (_stanceregain == -1) then
               {
               _unit setvariable ["asr_ai_sys_aiskill_configured", false];
               _unit setvariable ["tpwc_skillset", false];
               _unit setvariable ["tpwc_combatmode", "unchanged"];
               _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];
               _unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];
               _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];
               _unit setvariable ["tpwc_general", _unit skill "general"];
               _unit setvariable ["tpwc_stanceregain", diag_ticktime];
               _unit setvariable ["tpwc_skillregain", diag_ticktime];
               _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];
               _ball = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
			_ball setObjectTexture [0,"#(argb,8,8,3)color(0.1,0.9,0.1,0.8,ca)"]; // green
			_ball attachTo [_unit,[0,0,2]]; _unit setvariable ["tpwc_supball",_ball];
			};

           //If unit skills are unsuppressed
           if (diag_ticktime >= _skillregain) then
               {
               _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";
               _originalshake = _unit getvariable "tpwc_originalshake";
               _originalcourage = _unit getvariable "tpwc_originalcourage";
               _general = _unit getvariable "tpwc_general";
               if((_unit skill "aimingaccuracy") < _originalaccuracy) then
                   {
                   _unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.3)];
                   };
               if((_unit skill "aimingshake") < _originalshake) then
                   {
                   _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.3)];
                   };
               };

           //If unit stance is unsuppressed
           if ( diag_ticktime >= _stanceregain) then
               {
			_ball = _unit getvariable "tpwc_supball";
			if ( !isDedicated ) then
				{
				_ball setObjectTexture [0,"#(argb,8,8,3)color(0.2,0.9,0.2,0.5,ca)"]; // green
				}
			else
				{
				[-2, {_this setObjectTexture [0,"#(argb,8,8,3)color(0.1,0.9,0.1,0.8,ca)"]}, _ball] call CBA_fnc_globalExecute; //green
				};
			_unit setvariable ["tpwc_supshots", 0];
               _unit setunitpos "auto";
               _originalcourage = _unit getvariable "tpwc_originalcourage";
               _general = _unit getvariable "tpwc_general";
               _unit setvariable ["tpwc_suppressedstance", 0];
               if((_unit skill "courage") < (_originalcourage - 0.1)) then
                   {
                   _unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];
                   }
                   else
                   {
                   if (_unit getvariable "tpwc_combatmode" != "unchanged") then
                       {
                       _unit setbehaviour str(_unit getvariable "tpwc_combatmode");
                       _unit setvariable ["tpwc_combatmode", "unchanged"];
                       };
                   };
               };

           //If any bullets near unit
           if (_unit getvariable "tpwc_suppressedstance" > 0) then
               {
               _unit setunitpos "middle";
               };

           //If enemy bullets near unit
           if (_unit getvariable "tpwc_suppressedstance" > 1) then
               {
               if (tpwc_ai_sup_debug == 1) then
                   {
				_ball = _unit getvariable "tpwc_supball";
				if ( !isDedicated ) then
					{
					_ball setObjectTexture [0,"#(argb,8,8,3)color(0.6,0.9,0.0,0.7,ca)"]; // yellow
					}
				else
					{
					[-2, {_this setObjectTexture [0,"#(argb,8,8,3)color(0.6,0.9,0.0,0.7,ca)"]}, _ball] call CBA_fnc_globalExecute; //yellow
					};
                   };
               _unit setvariable ["tpwc_combatmode", behaviour _unit];
               _unit setbehaviour "COMBAT";
               _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";
               _originalshake = _unit getvariable "tpwc_originalshake";
               _originalcourage = _unit getvariable "tpwc_originalcourage";
               _general = _unit getvariable "tpwc_general";
               _shots = _unit getvariable "tpwc_supshots";
               _unit setskill ["aimingaccuracy",_originalaccuracy*_originalcourage*_general-(_shots*(1-_general)*.003)];
               _unit setskill ["aimingshake",_originalshake*_originalcourage*_general-(_shots*(1-_general)*.003)];
               _unit setskill ["courage",_originalcourage*_originalcourage*_general-(_shots*(1-_general)*.003)]; 
               };

           //If unit is suppressed with more than 5 enemy bullets
           if (_unit getvariable "tpwc_suppressedstance" == 3) then
               {
               _unit setunitpos "down";
               if ((_unit == player) and (tpwc_ai_sup_playersup == 1)) then
                   {
                   [] spawn tpwc_ai_sup_visuals;
                   addCamShake [2 - (skill player), 2, 5];
                   };

				if (tpwc_ai_sup_debug == 1) then
					{
					_ball = _unit getvariable "tpwc_supball";
					if ( !isDedicated ) then
						{
						_ball setObjectTexture [0,"#(argb,8,8,3)color(0.8,0.5,0.5,0.5,ca)"]; //red
						}
					else
						{
						[-2, {_this setObjectTexture [0,"#(argb,8,8,3)color(0.8,0.5,0.5,0.5,ca)"]}, _ball] call CBA_fnc_globalExecute; //red
						};
					};
               };
           };
       } foreach allunits;

if (tpwc_ai_sup_debug == 1) then
	{
		//remove balls from dead AI
		{
			// unit not alive
			_unit = _x;
			_ball = _unit getvariable "tpwc_supball";
			if ( !(_ball == objNull) ) then 
			{  
				detach _ball; 
				deleteVehicle _ball;
				_unit setvariable ["tpwc_supball",nil];		
			};
		} foreach allDead;
	};
   sleep 2;
   }
};

//Blur player vision when suppressed
tpwc_ai_sup_visuals =
{
if (tpwc_ai_sup_supvisflag == 0) then
   {
   tpwc_ai_sup_supvisflag = 1;
   _hndl = ppEffectCreate ["RadialBlur", 1551];
   _hndl ppEffectEnable true;
   _hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 0.1;
   _hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 0.1;
   _hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 0.1;
   _hndl ppEffectAdjust [0.004,0.004,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 5;
   _hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 0.1;
   _hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
   _hndl ppEffectCommit 0;
   sleep 0.1;
   _hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
   _hndl ppEffectCommit 0;
   ppEffectDestroy _hndl;
   tpwc_ai_sup_supvisflag = 0;
   };
};


//IF ASR AI HAS SET UNIT SKILLS, MAKE THESE THE "ORIGINALS" FOR EACH UNIT
tpwc_ai_sup_asrskills =
{
sleep 3;
while {true} do
   {
       {
       _unit = _x;
       _asr = _unit getVariable "asr_ai_sys_aiskill_configured";
       _skillset = _unit getVariable "tpwc_skillset";
       if ((_asr) && !(_skillset))then
           {
           _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];
           _unit setvariable ["tpwc_originalshake", _unit skill "aimingshake"];
           _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];
           _unit setvariable ["tpwc_general",_unit skill "general"];
           _unit setvariable ["tpwc_skillset", true];
           };
       } foreach allunits;
   sleep 30;
   };
};

/////////////////
// RUN IT
/////////////////

//Spawn behaviour loop
[] spawn tpwc_ai_sup_behaviour;
sleep 1;

//Spawn ASR_AI skill set loop if running ASR_AI > 1.15.1
if (isclass (configfile >> "cfgPatches">>"asr_ai_sys_aiskill")) then
   {
   _asr_ai_va = getArray (configfile>>"cfgPatches">>"asr_ai_main">>"versionAr");
   if (_asr_ai_va select 0 >= 1 && _asr_ai_va select 1 >= 15 && _asr_ai_va select 2 >= 1) then
       {
       [] spawn tpwc_ai_sup_asrskills;
       };
   };

//Call time critical bullet detection loop
[tpwc_ai_sup_detect,0] call cba_fnc_addPerFrameHandler;

};

Edited by Ollem

Share this post


Link to post
Share on other sites

Hi metalcraze, Ollem, countroland and CMcD

Sorry I haven't been able to give your excellent posts the attention they deserve. My faithful box from the last 4 years has finally shat itself and I am in the throes of getting my new computer up and running (with Arma of course).

Hopefully by tomorrow I'll be back on deck fully.

Share this post


Link to post
Share on other sites
Possible bug in 1.01: The readme says it doesn't suppress units in vehicles in modes 2 and 3, but I don't think it's working to suppress units fired at from vehicles in any mode.

Just read the following about the 'Fired' EventHandler:

Fired: 
Triggered when the unit fires a weapon.
This EH will not trigger if a unit fires out of a vehicle. For those cases an EH has to be attached to that particular vehicle.

Share this post


Link to post
Share on other sites
Just read the following about the 'Fired' EventHandler:

Fired: 
Triggered when the unit fires a weapon.
This EH will not trigger if a unit fires out of a vehicle. For those cases an EH has to be attached to that particular vehicle.

Try replacing this

_unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];

With this

(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];

Sorry, I can't test it, my new computer is still not Arma ready!

Share this post


Link to post
Share on other sites

QUOTE @ Günter Severloh

player will be suppressed by Ai with this. SLX_Suppression_Effects.pbo_______________

Agree with this in part, but mix GL4 & SLX mods together and you don’t need anything else ai wise imo.

However, that said, if this mod grows into a better more realistic suppression mod, then will be tested with the other two and if compatible included in the mix as well, very hard to acheive though..

Building searches & positions, rooftop use, flanking, suppressing, reinforcements, units working together as a whole, retreating & re-grouping, ai that care for their own lives, etc, etc. its all there. Very hard to beat, these mods (GL4 & SLX, mixed), ai wise..

Share this post


Link to post
Share on other sites
With regards to this script breaking scripted setunitpos (as opposed to commanded setunitpos), couldn't you include a line similar to:

_priorstance = unitpos _unit

...before commencing stance change (in the "If unit stance is unsuppressed" area of the SQF), then simply:

_unit setunitpos _priorstance

Of course, note that this won't work, you'll need to check the string, I just put it here for argument's sake.

Using unitpos has the added advantage in that it only ever returns something besides "auto" if the unit has been given a setunitpos scripting command (via init or otherwise).

And then voila - units that have been told to stand up or kneel behind cover will eventually return to their starting stances when able to fire/unsuppressed. An example of usage - troops firing over sandbags or the lip of a roof.

Excellent idea mate. We're currently doing something similar for switching units in and out of combat mode, so this should be doable for stance

---------- Post added at 22:11 ---------- Previous post was at 22:06 ----------

Good suppression shake too but do note that blur effect does not work when postprocessing is disabled. So it should be some other effect. Like quick desaturation maybe (colour effects do work at 'diabled')?

Also the setting should be server-side enforceable so it will be fair for all players at all times whether it's off or on since now it can be used for PvP too.

Well the blur is purely cosmetic, but the shake is gameplay changing.

If you mean the shake should be server-side enforceable, then I agree, even though I don't know how to do it yet.

If you mean the cosmetic stuff, then that's a bit lower priority ATM.

Share this post


Link to post
Share on other sites

Shake should be server-side enforced.

About cosmetic stuff - as I've said that problem is that at disabled PP it isn't seen. It would've been good if there was some kind of a visual effect seen by all. Maybe brighter edges of the screen? Kinda like ACE's pain effect when you are not applying morphine for some time.

Share this post


Link to post
Share on other sites

I had my doubts about the effect on player but after experiencing it I liked it, for me (pp on) the blur is a really nice effect, reminds me of the wizz script? and a good visual indicator that maybe I should keep low and without hijacking the weapon with too much sway?

This is amazing work guys, thanks to everyone involved!

I use this along with Ace/Asr/Slx and finally I'm starting to see the AI behave like soldiers in battle, they keep low and move very cautiously using cover... Aliabad is a perfect playground to watch them, clutter every where!

Arma 2 is only getting better and A3 around the corner... Good times :)

Share this post


Link to post
Share on other sites
Try replacing With this

(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];

I tested it and it does part of the job. I had to add an additional section to add the eventhandler specifically to the vehicle.

Unfortunately I did not succeed yet to find the right check to determine the vehicle the unit might be in.

According to the wiki: ? vehicle player != player : hint "Player is in a vehicle"

But vehicle _unit is always the same as _unit, also when the _unit is in a vehicle..???

As a workaround I temporarily used:

if ( count (crew vehicle _unit) > 1  ) then

, but e.g. a static M2 has only 1 crew member...

However, the concept works: with a specific EH linked to vehicles I'm able to suppress AI with e.g. Humvee mounted M2.

Share this post


Link to post
Share on other sites
I tested it and it does part of the job. I had to add an additional section to add the eventhandler specifically to the vehicle.

Unfortunately I did not succeed yet to find the right check to determine the vehicle the unit might be in.

According to the wiki: ? vehicle player != player : hint "Player is in a vehicle"

But vehicle _unit is always the same as _unit, also when the _unit is in a vehicle..???

As a workaround I temporarily used:

if ( count (crew vehicle _unit) > 1  ) then

, but e.g. a static M2 has only 1 crew member...

However, the concept works: with a specific EH linked to vehicles I'm able to suppress AI with e.g. Humvee mounted M2.

Simply use (vehicle _unit) as tpw indicated. It gives you the vehicle if the unit is in one, or the unit if not.

Share this post


Link to post
Share on other sites

The usage of (vehicle _unit) might work fine for vehicles that spawn with a crew (though I could not get it to work), but the challenge occurs for players or ai who man an empty vehicle.

They already do have an EH linked on unit level, and the vehicle EH creation doesn't get triggered without identifying 'something' has changed.

assignedVehicleRole _unit seems to be useful here:

output if no vehilce is []

in case of driver ["Driver]

and e.g. in case of static ör mounted M2: ["Turret",[0]]

---- update -----

The following additional code works for vehicles for me too:

        if (alive _x) then
		{
           _unit  = _x;
           _skillregain = _unit getvariable ["tpwc_skillregain", -1];
           _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];

           //Set initial parameters for each unit
           if (_stanceregain == -1) then
		{
               _unit setvariable ["asr_ai_sys_aiskill_configured", false];
               _unit setvariable ["tpwc_skillset", false];
               _unit setvariable ["tpwc_combatmode", "unchanged"];
               _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];
               _unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];
               _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];
               _unit setvariable ["tpwc_general", _unit skill "general"];
               _unit setvariable ["tpwc_stanceregain", diag_ticktime];
               _unit setvariable ["tpwc_skillregain", diag_ticktime];
			//_unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];
			(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];

			_ball = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
			_ball setObjectTexture [0,"#(argb,8,8,3)color(0.1,0.9,0.1,0.8,ca)"]; // green
			_ball attachTo [_unit,[0,0,2]]; _unit setvariable ["tpwc_supball",_ball];

			if ( tpwc_ai_sup_debug == 1 ) then
			{
				diag_log format ["AI SUPPRESS: added unit %1 - %2", _unit, count assignedVehicleRole _unit];
			};
		};

			// Check if Vehicle
			if ( ( assignedVehicleRole _unit) select 0 == "Turret"  ) then
			{
				_checkVehicle = (vehicle _unit) getVariable "tpwc_supvehicleball";
				if (isNil "_checkVehicle") then
				{						
					(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];
					_ball = "Sign_sphere25cm_EP1" createvehicle getposatl (vehicle _unit);
					_ball setObjectTexture [0,"#(argb,8,8,3)color(0.0,0.1,0.9,0.8,ca)"]; // blue
					_ball attachTo [vehicle _unit,[0,0,3]];
					(vehicle _unit) setvariable ["tpwc_supvehicleball",_ball];

					if ( tpwc_ai_sup_debug == 1 ) then
					{
						diag_log format ["AI SUPPRESS: added vehicle %1", vehicle _unit];
					}
					else
					{
						_ball hideobject true;
					};						
				};
			};

Edited by Ollem

Share this post


Link to post
Share on other sites
Anyone feeling brave? Here's a development version

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.02 20120626
*/ 

if (isServer || isDedicated) then {

//////////// 
//VARIABLES 
/////////// 

//Delay before suppression functions start. Allows time for other mods if needed
tpwc_ai_sup_sleep = 2; 

//Debugging. Will display red balls over any suppressed units. 0 = no debugging, 1 = debugging 
tpwc_ai_sup_debug = 1; 

//Bullet detection radius (m). Bullets must pass within this distance of unit to suppress them. If set much below 10m, bullets may not be detected 
tpwc_ai_sup_br = 10; 

//Bullet ignore radius (m). Bullets from a shooter closer than this will not suppress.  
tpwc_ai_sup_ir = 25; 

//Shot threshold. More shots than this will cause unit to drop/crawl 
tpwc_ai_sup_st = 5; 

//Startup hint. 0 = no hint, 1 = hint 
tpwc_ai_sup_hint = 1;  

//Player suppression visuals. 0 = no player suppression, 1 = player suppression 
tpwc_ai_sup_playersup = 1;  

//Pistol and SMG ammo to ignore. Add custom ammo (eg suppressed) or change to taste     
tpwc_ai_sup_mags =[ 
"30rnd_9x19_MP5",    
"30rnd_9x19_MP5SD",    
"15Rnd_9x19_M9",    
"15Rnd_9x19_M9SD",    
"7Rnd_45ACP_1911",    
"7Rnd_45ACP_1911",   
"8Rnd_9x18_Makarov",   
"8Rnd_9x18_MakarovSD",   
"64Rnd_9x19_Bizon",   
"64Rnd_9x19_SD_Bizon",   
"13Rnd_9mm_SLP",   
"17Rnd_9x19_glock17",   
"6Rnd_45ACP",   
"30Rnd_9x19_UZI",   
"30Rnd_9x19_UZI_SD" 
];   

////////// 
// SET UP 
////////// 

//Declare private variables 
private ["_stanceregain","_skillregain","_unit","_bc","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball","_skillset","_asr"];  

//Allow time for ASR AI skills to propagate 
sleep tpwc_ai_sup_sleep; 

//Start hint    
if (tpwc_ai_sup_hint == 1) then { 
0 = [] spawn {
hintsilent "TPWC AI Suppress 1.02 Active"; 
sleep 3; 
hintsilent ""}; 
};    


////////////////// 
// MAIN FUNCTIONS  
//////////////////  

//BULLET DETECTION LOOP (TIME CRITICAL)
tpwc_ai_sup_detect =      
{     
   {    
_unit = _x;
if !(isnull tpwc_ai_sup_bullet) then     
	{    
	_bc = count ((getposatl _unit) nearobjects ["bulletbase",tpwc_ai_sup_br]);    
	if (_bc > 0) then     
		{   
		if ((tpwc_ai_sup_fired distance _unit) > tpwc_ai_sup_ir) then     
			{    
			if !(tpwc_ai_sup_mag in tpwc_ai_sup_mags) then     
				{   
				_unit setvariable ["tpwc_skillregain", diag_ticktime + (random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage"))];     
				_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];    
				_unit setvariable ["tpwc_supshots",(_unit getvariable "tpwc_supshots") + _bc];    
				_unit setvariable ["tpwc_suppressedstance", 1];
				if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
					{
					_unit setvariable ["tpwc_suppressedstance", 2];							 
					if (_unit getvariable "tpwc_supshots" > tpwc_ai_sup_st) then    
						{
						_unit setvariable ["tpwc_suppressedstance", 3];								
						};    
					};     
				};    
			};    
		};    
	};    
   } foreach allunits;    
};    


//UNIT STANCE/SKILL MODIFICATION LOOP (NON TIME CRITICAL)
tpwc_ai_sup_behaviour = 
{
tpwc_ai_sup_supvisflag = 0;
while {true} do 
{
	{
	if (alive _x) then 
		{
		_unit  = _x;
		_skillregain = _unit getvariable ["tpwc_skillregain", -1];     
		_stanceregain = _unit getvariable ["tpwc_stanceregain", -1];   

		//Set initial parameters for each unit
		if (_stanceregain == -1) then     
			{ 
			_unit setvariable ["asr_ai_sys_aiskill_configured", false];  
			_unit setvariable ["tpwc_skillset", false];  
			_unit setvariable ["tpwc_combatmode", "unchanged"]; 
			_unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
			_unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];  
			_unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
			_unit setvariable ["tpwc_general", _unit skill "general"];  
			_unit setvariable ["tpwc_stanceregain", diag_ticktime];   
			_unit setvariable ["tpwc_skillregain", diag_ticktime];     
			_unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];    
			_ball = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;_ball attachTo [_unit,[0,0,2]]; _unit setvariable ["tpwc_supball",_ball];  
			}; 

		//If unit skills are unsuppressed
		if (diag_ticktime >= _skillregain) then    
			{  
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";      
			_originalshake = _unit getvariable "tpwc_originalshake";               
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";         
			if((_unit skill "aimingaccuracy") < _originalaccuracy) then    
				{  
				_unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.3)];     
				};   
			if((_unit skill "aimingshake") < _originalshake) then    
				{    
				_unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.3)];    
				};  
			};

		//If unit stance is unsuppressed
		if ( diag_ticktime >= _stanceregain) then     
			{   
			_ball = _unit getvariable "tpwc_supball"; _ball hideobject true;          
			_unit setvariable ["tpwc_supshots", 0];    
			_unit setunitpos "auto";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";
			_unit setvariable ["tpwc_suppressedstance", 0]; 			
			if((_unit skill "courage") < (_originalcourage - 0.1)) then    
				{    
				_unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];     
				}   
				else  
				{  
				if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
					{
					_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
					_unit setvariable ["tpwc_combatmode", "unchanged"]; 
					};
				};  
			};   

		//If any bullets near unit 
		if (_unit getvariable "tpwc_suppressedstance" > 0) then 
			{
			_unit setunitpos "middle";
			};

		//If enemy bullets near unit 	
		if (_unit getvariable "tpwc_suppressedstance" > 1) then 
			{
			if (tpwc_ai_sup_debug == 1) then   
				{  
				_ball = _unit getvariable "tpwc_supball";_ball hideobject false;  
				};   
			_unit setvariable ["tpwc_combatmode", behaviour _unit]; 
			_unit setbehaviour "COMBAT";	
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
			_originalshake = _unit getvariable "tpwc_originalshake";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";    
			_general = _unit getvariable "tpwc_general";  
			_shots = _unit getvariable "tpwc_supshots";  
			_unit setskill ["aimingaccuracy",_originalaccuracy*_originalcourage*_general-(_shots*(1-_general)*.003)];    
			_unit setskill ["aimingshake",_originalshake*_originalcourage*_general-(_shots*(1-_general)*.003)];   
			_unit setskill ["courage",_originalcourage*_originalcourage*_general-(_shots*(1-_general)*.003)];  	
			};

		//If unit is suppressed with more than 5 enemy bullets
		if (_unit getvariable "tpwc_suppressedstance" == 3) then 
			{
			_unit setunitpos "down"; 
			if ((_unit == player) and (tpwc_ai_sup_playersup == 1)) then 
				{
				[] spawn tpwc_ai_sup_visuals;
				addCamShake [2 - (skill player), 2, 5]
				}; 
			};
		};
	} foreach allunits; 
sleep 2;	
}
};

//Blur player vision when suppressed
tpwc_ai_sup_visuals = 
{
if (tpwc_ai_sup_supvisflag == 0) then 
{
tpwc_ai_sup_supvisflag = 1;
_hndl = ppEffectCreate ["RadialBlur", 1551];
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.004,0.004,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 5;
_hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
_hndl ppEffectCommit 0;
ppEffectDestroy _hndl;
tpwc_ai_sup_supvisflag = 0;
};
};


//IF ASR AI HAS SET UNIT SKILLS, MAKE THESE THE "ORIGINALS" FOR EACH UNIT  
tpwc_ai_sup_asrskills = 
{ 
sleep 3; 
while {true} do  
   { 
       { 
       _unit = _x; 
       _asr = _unit getVariable "asr_ai_sys_aiskill_configured"; 
       _skillset = _unit getVariable "tpwc_skillset"; 
       if ((_asr) && !(_skillset))then  
           { 
           _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
           _unit setvariable ["tpwc_originalshake", _unit skill "aimingshake"];  
           _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
           _unit setvariable ["tpwc_general",_unit skill "general"];  
           _unit setvariable ["tpwc_skillset", true]; 
           }; 
       } foreach allunits; 
   sleep 30; 
   }; 
};  

/////////////////
// RUN IT
/////////////////

//Spawn behaviour loop
[] spawn tpwc_ai_sup_behaviour; 
sleep 1;

//Spawn ASR_AI skill set loop if running ASR_AI > 1.15.1 	
if (isclass (configfile >> "cfgPatches">>"asr_ai_sys_aiskill")) then  
{ 
_asr_ai_va = getArray (configfile>>"cfgPatches">>"asr_ai_main">>"versionAr");
if (_asr_ai_va select 0 >= 1 && _asr_ai_va select 1 >= 15 && _asr_ai_va select 2 >= 1) then 
	{
	[] spawn tpwc_ai_sup_asrskills; 
	};	
}; 

//Call time critical bullet detection loop
[tpwc_ai_sup_detect,0] call cba_fnc_addPerFrameHandler;  

};

which does a few things:

  • All the non time critical behaviour stuff has been moved out to it's own 2 second loop
  • Only the essential time critical bullet detection stuff stays in the PFEH loop
  • Added user selectable player suppression effects (camera shake and radial blur)
  • Added Ollem's server stuff

What this means for you? You should experience less performance hit/lag with more AI.

What this means for us? We can bolt on additional behaviour stuff (eg suppression fx) without worrying so much about it killing performance.

Please test it out, hopefully this will form the basis of the addon going forward.

Very very nice.

Minor stuff:

* Add "_x" to private vars;

* Maybe:

_unit setbehaviour "COMBAT";
can be changed to
if( !( behaviour _unit in ["COMBAT", "STEALTH"] ) ) then { _unit setbehaviour "COMBAT"; };
As overriding STEALTH may not be always desirable;

* if

_unit getvariable "tpwc_suppressedstance" == 3
it would be interesting to add
_unit forcespeed -1;
In that situation unit is under heavy fire. Maybe it's eventually locked in place by recent a CAN FIRE event red triggered from within danger.fsm (it basically does forcespeed 0, locking unit in place up to 8 seconds if i recall correctly). I would forcespeed unit to -1 to "unlock" unit movement, allowing it to eventually move into nearby cover. A better solution would be altering danger.fsm so that code stopping the unit is skipped if _unit getvariable "tpwc_suppressedstance" evaluates to 3, as units under heavy fire should prioritize movement to cover vs. returning fire.

* Probably a bit OT, but i've found that as a rule of thumbrescaling accuracy non-linearly this way:

_unit setSkill ["AimingAccuracy", skill _unit ^ 2 ];

really helps in having better firefights without having to further manipulate ingame accuracy settings (you keep defaults). An important sideeffect is that with asymmetrical warfare in mind the accuracy gap between highly skilled vs. unskilled units is significatively bigger. Maybe you would like to check it out, it does nothing to skill=1 (so you de-facto keep unchanged the upper bound accuracy), while for skill=0.2 it makes a hell of difference, with units spraying bullets around.

Edited by fabrizio_T

Share this post


Link to post
Share on other sites

Minor stuff:

* Add "_x" to private vars;

* Maybe:

_unit setbehaviour "COMBAT";

can be changed to

if( !( behaviour _unit in ["COMBAT", "STEALTH"] ) ) then { _unit setbehaviour "COMBAT"; };

As overriding STEALTH may not be always desirable;

Nice. All good suggestions. I am sure tpw will use them.

In that situation unit is under heavy fire. Maybe it's eventually locked in place by recent a CAN FIRE event red triggered from within danger.fsm (it basically does forcespeed 0, locking unit in place up to 8 seconds if i recall correctly). I would forcespeed unit to -1 to "unlock" unit movement, allowing it to eventually move into nearby cover. A better solution would be altering danger.fsm so that code stopping the unit is skipped if _unit getvariable "tpwc_suppressedstance" evaluates to 3, a units under very heavy fire should prioritize movement to cover to vs. returning fire.

Interesting. That's a good idea. Do you have any idea why units don't always seek cover. Is there a way to "force" them toat least try to get to cover? Cause right now I would say that even in areas with dense cover many ai would still rather go prone in the open then get behind a wall or something. Maybe its just a side effect of a slow computer.

really helps in having better firefights without having to further manipulate ingame accuracy settings. An important sideeffect is that with asymmetrical warfare in mind the gap between highly skilled vs. unskilled units is significatively bigger. Maybe you would like to check it out, it does nothing to skill=1 (so you de-facto keep unchanged the upper bound accuracy), while for skill=0.2 it makes a hell of difference, with units spraying bullets around.

Thanks for the advice. Right now aiming accuracy is multiplied by the units courage and general skill so the same sort of effect is created, as low skill units typically also have low general skill and courage (using asr) and high skill units generally have high general and courage, creating a large divide between the two when underfire. And I found that if I used the the actual skill of the unit at the time, units skills dropped to "x10-5" levels because of a single burst of machinegun fire. Infact even now I've witnessed ai shooting the ground right in front of them because of poor accuracy, and aiming accuracy doesn't drop much lower than 5.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Thanks for all the code and advice Ollem and fabrizio_T. I'm gradually working it all into the next development version of the script, along with some more -coulum- changes and some of my own.

Since you boys obviously have some MP smarts, can you work out how to address metalcrazes idea of forcing player suppression fx in MP?

EDIT: I actually test drove your coloured suppression balls stuff Ollem and for me it doesn't work as expected. Unsuppressed units have no balls (!), suppressed have green. I can't get any yellow or red.

Edited by tpw

Share this post


Link to post
Share on other sites

Good job guys, I'm not using this yet, but it's getting there. Me and my guys use a array of mods for absolute realism and this is quickly getting ready to be on that list!

Share this post


Link to post
Share on other sites

Thanks to everyone's awesome input we're really starting to get somewhere

I've incorporated and changed a few things:

  • The coloured ball stuff has been simplified and doesn't need server intervention, as I have simply assigned a different coloured ball to each level of suppression
  • Gunners on a turret have the fired event handler assigned to the vehicle
  • Combat mode only kicks in if not already in combat or stealth, fully suppressed units can still crawl
  • Miscellaneous -Coulum- improvements to skills modification
  • A bit more general turd polishing, variable wrangling etc

I will also work on non PP visual suppression fx, and CMcDs stance suggestions later today.

Code:

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
Additional code: Fabrizio_T, Ollem
1.02 20120626
*/ 

if (isServer || isDedicated) then {

//Log it
diag_log format ["AI SUPPRESS STARTED: Server: %1 - Dedicated: %2", isServer, isDedicated];

//////////// 
//VARIABLES 
/////////// 

//Delay before suppression functions start. Allows time for other mods if needed
tpwc_ai_sup_sleep = 2; 

//Debugging. Will display red balls over any suppressed units. 0 = no debugging, 1 = debugging 
tpwc_ai_sup_debug = 1; 

//Bullet detection radius (m). Bullets must pass within this distance of unit to suppress them. If set much below 10m, bullets may not be detected 
tpwc_ai_sup_br = 10; 

//Bullet ignore radius (m). Bullets from a shooter closer than this will not suppress.  
tpwc_ai_sup_ir = 25; 

//Shot threshold. More shots than this will cause unit to drop/crawl 
tpwc_ai_sup_st = 5; 

//Startup hint. 0 = no hint, 1 = hint 
tpwc_ai_sup_hint = 1;  

//Player suppression visuals. 0 = no player suppression, 1 = player suppression 
tpwc_ai_sup_playersup = 1;  

//Pistol and SMG ammo to ignore. Add custom ammo (eg suppressed) or change to taste     
tpwc_ai_sup_mags =[ 
"30rnd_9x19_MP5",    
"30rnd_9x19_MP5SD",    
"15Rnd_9x19_M9",    
"15Rnd_9x19_M9SD",    
"7Rnd_45ACP_1911",    
"7Rnd_45ACP_1911",   
"8Rnd_9x18_Makarov",   
"8Rnd_9x18_MakarovSD",   
"64Rnd_9x19_Bizon",   
"64Rnd_9x19_SD_Bizon",   
"13Rnd_9mm_SLP",   
"17Rnd_9x19_glock17",   
"6Rnd_45ACP",   
"30Rnd_9x19_UZI",   
"30Rnd_9x19_UZI_SD" 
];   

////////// 
// SET UP 
////////// 

//Declare private variables 
private ["_stanceregain","_skillregain","_unit","_bc","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball1","_ball2","_ball3","_skillset","_asr","_x"];  

//Allow time for ASR AI skills to propagate 
sleep tpwc_ai_sup_sleep; 

//Start hint    
if (tpwc_ai_sup_hint == 1) then { 
0 = [] spawn {
hintsilent "TPWC AI Suppress 1.02 Active"; 
sleep 3; 
hintsilent ""}; 
};    


////////////////// 
// MAIN FUNCTIONS  
//////////////////  

//BULLET DETECTION LOOP (TIME CRITICAL)
//Do not touch this please
tpwc_ai_sup_detect =      
{     
   {    
_unit = _x;
if !(isnull tpwc_ai_sup_bullet) then     
	{    
	_bc = count ((getposatl _unit) nearobjects ["bulletbase",tpwc_ai_sup_br]);    
	if (_bc > 0) then     
		{   
		if ((tpwc_ai_sup_fired distance _unit) > tpwc_ai_sup_ir) then     
			{    
			if !(tpwc_ai_sup_mag in tpwc_ai_sup_mags) then     
				{   
				_unit setvariable ["tpwc_skillregain", diag_ticktime + (random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage"))];     
				_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];    
				_unit setvariable ["tpwc_supshots",(_unit getvariable "tpwc_supshots") + _bc];    
				_unit setvariable ["tpwc_suppressedstance", 1];
				if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
					{
					_unit setvariable ["tpwc_suppressedstance", 2];							 
					if (_unit getvariable "tpwc_supshots" > tpwc_ai_sup_st) then    
						{
						_unit setvariable ["tpwc_suppressedstance", 3];								
						};    
					};     
				};    
			};    
		};    
	};    
   } foreach allunits;    
};    


//UNIT STANCE/SKILL MODIFICATION LOOP (NON TIME CRITICAL)
tpwc_ai_sup_behaviour = 
{
tpwc_ai_sup_supvisflag = 0;
while {true} do 
{
	{
	if (alive _x) then 
		{
		_unit  = _x;
		_skillregain = _unit getvariable ["tpwc_skillregain", -1];     
		_stanceregain = _unit getvariable ["tpwc_stanceregain", -1];   

		//Set initial parameters for each unit
		if (_stanceregain == -1) then     
			{ 
			_unit setvariable ["asr_ai_sys_aiskill_configured", false];  
			_unit setvariable ["tpwc_skillset", false];  
			_unit setvariable ["tpwc_combatmode", "unchanged"]; 
			_unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
			_unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];  
			_unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
			_unit setvariable ["tpwc_general", _unit skill "general"];  
			_unit setvariable ["tpwc_stanceregain", diag_ticktime];   
			_unit setvariable ["tpwc_skillregain", diag_ticktime];     
			_unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];    
			if ( ( assignedVehicleRole _unit) select 0 == "Turret"  ) then 
				{
				(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}]; 
				};
			if (tpwc_ai_sup_debug == 1) then   
				{  
				_ball1 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball1 setObjectTexture [0,"#(argb,8,8,3)color(0.2,0.9,0.2,0.5,ca)"];
				_ball1 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup1ball",_ball1]; 

				_ball2 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball2 setObjectTexture [0,"#(argb,8,8,3)color(0.6,0.9,0.0,0.7,ca)"]; //yellow
				_ball2 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup2ball",_ball2]; 

				_ball3 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball3 setObjectTexture [0,"#(argb,8,8,3)color(0.8,0.5,0.5,0.5,ca)"]; //red
				_ball3 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup3ball",_ball3]; 

				};
			}; 

		//If unit skills are unsuppressed
		if (diag_ticktime >= _skillregain) then    
			{  
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";      
			_originalshake = _unit getvariable "tpwc_originalshake";               
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";         
			if((_unit skill "aimingaccuracy") < _originalaccuracy) then    
				{  
				_unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.325)];     
				};   
			if((_unit skill "aimingshake") < _originalshake) then    
				{    
				_unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.325)];    
				};  
			};

		//If unit stance is unsuppressed
		if ( diag_ticktime >= _stanceregain) then     
			{
			if (tpwc_ai_sup_debug == 1) then   
				{     
			_ball1 = _unit getvariable "tpwc_sup1ball"; 
			_ball1 hideobject true;
			_ball2 = _unit getvariable "tpwc_sup2ball"; 
			_ball2 hideobject true;
			_ball3 = _unit getvariable "tpwc_sup3ball"; 
			_ball3 hideobject true;
				};
			_unit setvariable ["tpwc_supshots", 0];    
			_unit setunitpos "auto";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";
			_unit setvariable ["tpwc_suppressedstance", 0]; 			
			if((_unit skill "courage") < (_originalcourage - 0.1)) then    
				{    
				_unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];     
				}   
				else  
				{  
				if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
					{
					_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
					_unit setvariable ["tpwc_combatmode", "unchanged"]; 
					};
				};  
			};   

		//If any bullets near unit 
		if (_unit getvariable "tpwc_suppressedstance" > 0) then 
			{
			_unit setunitpos "middle";
			if (tpwc_ai_sup_debug == 1) then   
				{  
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject false;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject true;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject true;
				}; 
			};

		//If enemy bullets near unit 	
		if (_unit getvariable "tpwc_suppressedstance" > 1) then 
			{
			if (tpwc_ai_sup_debug == 1) then   
				{ 
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject true;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject false;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject true;			
				};

			_unit setvariable ["tpwc_combatmode", behaviour _unit]; 
			if( !( behaviour _unit in ["COMBAT", "STEALTH"] ) ) then 
				{
				_unit setbehaviour "COMBAT"; 
				};	
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
			_originalshake = _unit getvariable "tpwc_originalshake";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";    
			_general = _unit getvariable "tpwc_general";  
			_shots = _unit getvariable "tpwc_supshots";  
			if (diag_ticktime < _skillregain) then 
				{       
				_unit setskill ["aimingaccuracy",_originalaccuracy*_originalcourage*_general-(_shots*(1-_general)*.003)];      
				_unit setskill ["aimingshake",_originalshake*_originalcourage*_general-(_shots*(1-_general)*.003)];     
				_unit setskill ["courage",(_unit skill "courage")-(_shots*(1-_general)*(1-_originalcourage)*.07)]; 
				}; 
			};

		//If unit is suppressed with more than 5 enemy bullets
		if (_unit getvariable "tpwc_suppressedstance" == 3) then 
			{
			if (tpwc_ai_sup_debug == 1) then   
				{
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject true;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject true;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject false;
				};
			_unit setunitpos "down"; 
			_unit forcespeed -1;
			if ((_unit == player) and (tpwc_ai_sup_playersup == 1)) then 
				{
				[] spawn tpwc_ai_sup_visuals;
				addCamShake [2 - (skill player), 2, 5]
				}; 
			};
		};
	} foreach allunits; 

	//Remove debug balls from dead AI
	if (tpwc_ai_sup_debug == 1) then
		{
			{
				_unit = _x;
				_ball1 = _unit getvariable "tpwc_sup1ball";
				if ( !(_ball1 == objNull) ) then 
					{  
					detach _ball1; 
					deleteVehicle _ball1;
					_unit setvariable ["tpwc_sup1ball",nil];        
					};
					_ball2 = _unit getvariable "tpwc_sup2ball";
				if ( !(_ball2 == objNull) ) then 
					{  
					detach _ball2; 
					deleteVehicle _ball2;
					_unit setvariable ["tpwc_sup2ball",nil];        
					};
					_ball3 = _unit getvariable "tpwc_sup3ball";
				if ( !(_ball3 == objNull) ) then 
					{  
					detach _ball3; 
					deleteVehicle _ball3;
					_unit setvariable ["tpwc_sup3ball",nil];        
					};
			} foreach allDead;
		};
sleep 1;	
}
};

//Blur player vision when suppressed
tpwc_ai_sup_visuals = 
{
if (tpwc_ai_sup_supvisflag == 0) then 
{
tpwc_ai_sup_supvisflag = 1;
_hndl = ppEffectCreate ["RadialBlur", 1551];
_hndl ppEffectEnable true;
_hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.004,0.004,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 5;
_hndl ppEffectAdjust [0.003,0.003,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.002,0.002,0.1,0.1];
_hndl ppEffectCommit 0;
sleep 0.1;
_hndl ppEffectAdjust [0.001,0.001,0.1,0.1];
_hndl ppEffectCommit 0;
ppEffectDestroy _hndl;
tpwc_ai_sup_supvisflag = 0;
};
};


//IF ASR AI HAS SET UNIT SKILLS, MAKE THESE THE "ORIGINALS" FOR EACH UNIT  
tpwc_ai_sup_asrskills = 
{ 
sleep 3; 
while {true} do  
   { 
       { 
       _unit = _x; 
       _asr = _unit getVariable "asr_ai_sys_aiskill_configured"; 
       _skillset = _unit getVariable "tpwc_skillset"; 
       if ((_asr) && !(_skillset))then  
           { 
           _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
           _unit setvariable ["tpwc_originalshake", _unit skill "aimingshake"];  
           _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
           _unit setvariable ["tpwc_general",_unit skill "general"];  
           _unit setvariable ["tpwc_skillset", true]; 
           }; 
       } foreach allunits; 
   sleep 30; 
   }; 
};  

/////////////////
// RUN IT
/////////////////

//Spawn behaviour loop
[] spawn tpwc_ai_sup_behaviour; 
sleep 1;

//Spawn ASR_AI skill set loop if running ASR_AI > 1.15.1 	
if (isclass (configfile >> "cfgPatches">>"asr_ai_sys_aiskill")) then  
{ 
_asr_ai_va = getArray (configfile>>"cfgPatches">>"asr_ai_main">>"versionAr");
if (_asr_ai_va select 0 >= 1 && _asr_ai_va select 1 >= 15 && _asr_ai_va select 2 >= 1) then 
	{
	[] spawn tpwc_ai_sup_asrskills; 
	};	
}; 

//Call time critical bullet detection loop
[tpwc_ai_sup_detect,0] call cba_fnc_addPerFrameHandler;  

};

Edited by tpw

Share this post


Link to post
Share on other sites

Ta -Coulum-

This script is the same as above but with gamma reduction as well as blur. If you have pp enabled then you'll get both, if not, then you'll only get the gamma

Script:

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
Additional code: Fabrizio_T, Ollem
1.02 20120626
*/ 

if (isServer || isDedicated) then {

//Log it
diag_log format ["AI SUPPRESS STARTED: Server: %1 - Dedicated: %2", isServer, isDedicated];

//////////// 
//VARIABLES 
/////////// 

//Delay before suppression functions start. Allows time for other mods if needed
tpwc_ai_sup_sleep = 2; 

//Debugging. Will display red balls over any suppressed units. 0 = no debugging, 1 = debugging 
tpwc_ai_sup_debug = 1; 

//Bullet detection radius (m). Bullets must pass within this distance of unit to suppress them. If set much below 10m, bullets may not be detected 
tpwc_ai_sup_br = 10; 

//Bullet ignore radius (m). Bullets from a shooter closer than this will not suppress.  
tpwc_ai_sup_ir = 25; 

//Shot threshold. More shots than this will cause unit to drop/crawl 
tpwc_ai_sup_st = 5; 

//Startup hint. 0 = no hint, 1 = hint 
tpwc_ai_sup_hint = 1;  

//Player suppression visuals. 0 = no player suppression, 1 = player suppression 
tpwc_ai_sup_playersup = 1;  

//Pistol and SMG ammo to ignore. Add custom ammo (eg suppressed) or change to taste     
tpwc_ai_sup_mags =[ 
"30rnd_9x19_MP5",    
"30rnd_9x19_MP5SD",    
"15Rnd_9x19_M9",    
"15Rnd_9x19_M9SD",    
"7Rnd_45ACP_1911",    
"7Rnd_45ACP_1911",   
"8Rnd_9x18_Makarov",   
"8Rnd_9x18_MakarovSD",   
"64Rnd_9x19_Bizon",   
"64Rnd_9x19_SD_Bizon",   
"13Rnd_9mm_SLP",   
"17Rnd_9x19_glock17",   
"6Rnd_45ACP",   
"30Rnd_9x19_UZI",   
"30Rnd_9x19_UZI_SD" 
];   

////////// 
// SET UP 
////////// 

//Declare private variables 
private ["_stanceregain","_skillregain","_unit","_bc","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball1","_ball2","_ball3","_skillset","_asr","_tint","_blur","_x"];  

//Allow time for ASR AI skills to propagate 
sleep tpwc_ai_sup_sleep; 

//Start hint    
if (tpwc_ai_sup_hint == 1) then { 
0 = [] spawn {
hintsilent "TPWC AI Suppress 1.02 Active"; 
sleep 3; 
hintsilent ""}; 
};    


////////////////// 
// MAIN FUNCTIONS  
//////////////////  

//BULLET DETECTION LOOP (TIME CRITICAL)
//Do not touch this please
tpwc_ai_sup_detect =      
{     
   {    
_unit = _x;
if !(isnull tpwc_ai_sup_bullet) then     
	{    
	_bc = count ((getposatl _unit) nearobjects ["bulletbase",tpwc_ai_sup_br]);    
	if (_bc > 0) then     
		{   
		if ((tpwc_ai_sup_fired distance _unit) > tpwc_ai_sup_ir) then     
			{    
			if !(tpwc_ai_sup_mag in tpwc_ai_sup_mags) then     
				{   
				_unit setvariable ["tpwc_skillregain", diag_ticktime + (random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage"))];     
				_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];    
				_unit setvariable ["tpwc_supshots",(_unit getvariable "tpwc_supshots") + _bc];    
				_unit setvariable ["tpwc_suppressedstance", 1];
				if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
					{
					_unit setvariable ["tpwc_suppressedstance", 2];							 
					if (_unit getvariable "tpwc_supshots" > tpwc_ai_sup_st) then    
						{
						_unit setvariable ["tpwc_suppressedstance", 3];								
						};    
					};     
				};    
			};    
		};    
	};    
   } foreach allunits;    
};    


//UNIT STANCE/SKILL MODIFICATION LOOP (NON TIME CRITICAL)
tpwc_ai_sup_behaviour = 
{
tpwc_ai_sup_supvisflag = 0;
while {true} do 
{
	{
	if (alive _x) then 
		{
		_unit  = _x;
		_skillregain = _unit getvariable ["tpwc_skillregain", -1];     
		_stanceregain = _unit getvariable ["tpwc_stanceregain", -1];   

		//Set initial parameters for each unit
		if (_stanceregain == -1) then     
			{ 
			_unit setvariable ["asr_ai_sys_aiskill_configured", false];  
			_unit setvariable ["tpwc_skillset", false];  
			_unit setvariable ["tpwc_combatmode", "unchanged"]; 
			_unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
			_unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];  
			_unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
			_unit setvariable ["tpwc_general", _unit skill "general"];  
			_unit setvariable ["tpwc_stanceregain", diag_ticktime];   
			_unit setvariable ["tpwc_skillregain", diag_ticktime];     
			_unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];    
			if ( ( assignedVehicleRole _unit) select 0 == "Turret"  ) then 
				{
				(vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}]; 
				};
			if (tpwc_ai_sup_debug == 1) then   
				{  
				_ball1 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball1 setObjectTexture [0,"#(argb,8,8,3)color(0.2,0.9,0.2,0.5,ca)"];
				_ball1 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup1ball",_ball1]; 

				_ball2 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball2 setObjectTexture [0,"#(argb,8,8,3)color(0.6,0.9,0.0,0.7,ca)"]; //yellow
				_ball2 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup2ball",_ball2]; 

				_ball3 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit;
				_ball3 setObjectTexture [0,"#(argb,8,8,3)color(0.8,0.5,0.5,0.5,ca)"]; //red
				_ball3 attachTo [_unit,[0,0,2]]; 
				_unit setvariable ["tpwc_sup3ball",_ball3]; 

				};
			}; 

		//If unit skills are unsuppressed
		if (diag_ticktime >= _skillregain) then    
			{  
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";      
			_originalshake = _unit getvariable "tpwc_originalshake";               
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";         
			if((_unit skill "aimingaccuracy") < _originalaccuracy) then    
				{  
				_unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.325)];     
				};   
			if((_unit skill "aimingshake") < _originalshake) then    
				{    
				_unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.325)];    
				};  
			};

		//If unit stance is unsuppressed
		if ( diag_ticktime >= _stanceregain) then     
			{
			if (tpwc_ai_sup_debug == 1) then   
				{     
			_ball1 = _unit getvariable "tpwc_sup1ball"; 
			_ball1 hideobject true;
			_ball2 = _unit getvariable "tpwc_sup2ball"; 
			_ball2 hideobject true;
			_ball3 = _unit getvariable "tpwc_sup3ball"; 
			_ball3 hideobject true;
				};
			_unit setvariable ["tpwc_supshots", 0];    
			_unit setunitpos "auto";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";   
			_general = _unit getvariable "tpwc_general";
			_unit setvariable ["tpwc_suppressedstance", 0]; 			
			if((_unit skill "courage") < (_originalcourage - 0.1)) then    
				{    
				_unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];     
				}   
				else  
				{  
				if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
					{
					_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
					_unit setvariable ["tpwc_combatmode", "unchanged"]; 
					};
				};  
			};   

		//If any bullets near unit 
		if (_unit getvariable "tpwc_suppressedstance" > 0) then 
			{
			_unit setunitpos "middle";
			if (tpwc_ai_sup_debug == 1) then   
				{  
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject false;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject true;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject true;
				}; 
			};

		//If enemy bullets near unit 	
		if (_unit getvariable "tpwc_suppressedstance" > 1) then 
			{
			if (tpwc_ai_sup_debug == 1) then   
				{ 
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject true;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject false;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject true;			
				};

			_unit setvariable ["tpwc_combatmode", behaviour _unit]; 
			if( !( behaviour _unit in ["COMBAT", "STEALTH"] ) ) then 
				{
				_unit setbehaviour "COMBAT"; 
				};	
			_originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
			_originalshake = _unit getvariable "tpwc_originalshake";   
			_originalcourage = _unit getvariable "tpwc_originalcourage";    
			_general = _unit getvariable "tpwc_general";  
			_shots = _unit getvariable "tpwc_supshots";  
			if (diag_ticktime < _skillregain) then 
				{       
				_unit setskill ["aimingaccuracy",_originalaccuracy*_originalcourage*_general-(_shots*(1-_general)*.003)];      
				_unit setskill ["aimingshake",_originalshake*_originalcourage*_general-(_shots*(1-_general)*.003)];     
				_unit setskill ["courage",(_unit skill "courage")-(_shots*(1-_general)*(1-_originalcourage)*.07)]; 
				}; 
			};

		//If unit is suppressed with more than 5 enemy bullets
		if (_unit getvariable "tpwc_suppressedstance" == 3) then 
			{
			if (tpwc_ai_sup_debug == 1) then   
				{
				_ball1 = _unit getvariable "tpwc_sup1ball"; 
				_ball1 hideobject true;
				_ball2 = _unit getvariable "tpwc_sup2ball"; 
				_ball2 hideobject true;
				_ball3 = _unit getvariable "tpwc_sup3ball"; 
				_ball3 hideobject false;
				};
			_unit setunitpos "down"; 
			_unit forcespeed -1;
			if ((_unit == player) and (tpwc_ai_sup_playersup == 1)) then 
				{
				[] spawn tpwc_ai_sup_visuals;
				addCamShake [2 - (skill player), 2, 5]
				}; 
			};
		};
	} foreach allunits; 

	//Remove debug balls from dead AI
	if (tpwc_ai_sup_debug == 1) then
		{
			{
				_unit = _x;
				_ball1 = _unit getvariable "tpwc_sup1ball";
				if ( !(_ball1 == objNull) ) then 
					{  
					detach _ball1; 
					deleteVehicle _ball1;
					_unit setvariable ["tpwc_sup1ball",nil];        
					};
					_ball2 = _unit getvariable "tpwc_sup2ball";
				if ( !(_ball2 == objNull) ) then 
					{  
					detach _ball2; 
					deleteVehicle _ball2;
					_unit setvariable ["tpwc_sup2ball",nil];        
					};
					_ball3 = _unit getvariable "tpwc_sup3ball";
				if ( !(_ball3 == objNull) ) then 
					{  
					detach _ball3; 
					deleteVehicle _ball3;
					_unit setvariable ["tpwc_sup3ball",nil];        
					};
			} foreach allDead;
		};
sleep 1;	
}
};

//BLUR PLAYER VISION WHEN SUPPRESSED
tpwc_ai_sup_visuals = 
{
if (tpwc_ai_sup_supvisflag == 0) then 
{
tpwc_ai_sup_supvisflag = 1;
_tint = ppEffectCreate ["Colorcorrections", 1552];
_tint ppEffectEnable true;
_blur = ppEffectCreate ["RadialBlur", 1551];
_blur ppEffectEnable true;
_blur ppEffectAdjust [0.001,0.001,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.002, [0,0,0,0], [0,0,0,1], [0,0,0,1]];
_tint ppEffectCommit 0;
sleep 0.1;
_blur ppEffectAdjust [0.002,0.002,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.004, [0,0,0,0], [0,0,0,1], [0,0,0,1]];
_tint ppEffectCommit 0;
sleep 0.1;
_blur ppEffectAdjust [0.003,0.003,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.006, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ; 
_tint ppEffectCommit 0;
sleep 0.1;
_blur ppEffectAdjust [0.004,0.004,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.008, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ; 
_tint ppEffectCommit 0;
sleep 5;
_blur ppEffectAdjust [0.003,0.003,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.006, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ;
_tint ppEffectCommit 0;
sleep 0.1;
_blur ppEffectAdjust [0.002,0.002,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.004, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ;
_tint ppEffectCommit 0;
sleep 0.1;
_blur ppEffectAdjust [0.001,0.001,0.1,0.1];
_blur ppEffectCommit 0;
_tint ppEffectAdjust[1, 1, -0.002, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ;
_tint ppEffectCommit 0;
ppEffectDestroy _blur;
ppEffectDestroy _tint;
tpwc_ai_sup_supvisflag = 0;
};
};


//IF ASR AI HAS SET UNIT SKILLS, MAKE THESE THE "ORIGINALS" FOR EACH UNIT  
tpwc_ai_sup_asrskills = 
{ 
sleep 3; 
while {true} do  
   { 
       { 
       _unit = _x; 
       _asr = _unit getVariable "asr_ai_sys_aiskill_configured"; 
       _skillset = _unit getVariable "tpwc_skillset"; 
       if ((_asr) && !(_skillset))then  
           { 
           _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];   
           _unit setvariable ["tpwc_originalshake", _unit skill "aimingshake"];  
           _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];   
           _unit setvariable ["tpwc_general",_unit skill "general"];  
           _unit setvariable ["tpwc_skillset", true]; 
           }; 
       } foreach allunits; 
   sleep 30; 
   }; 
};  

/////////////////
// RUN IT
/////////////////

//Spawn behaviour loop
[] spawn tpwc_ai_sup_behaviour; 
sleep 1;

//Spawn ASR_AI skill set loop if running ASR_AI > 1.15.1 	
if (isclass (configfile >> "cfgPatches">>"asr_ai_sys_aiskill")) then  
{ 
_asr_ai_va = getArray (configfile>>"cfgPatches">>"asr_ai_main">>"versionAr");
if (_asr_ai_va select 0 >= 1 && _asr_ai_va select 1 >= 15 && _asr_ai_va select 2 >= 1) then 
	{
	[] spawn tpwc_ai_sup_asrskills; 
	};	
}; 

//Call time critical bullet detection loop
[tpwc_ai_sup_detect,0] call cba_fnc_addPerFrameHandler;  

};

Share this post


Link to post
Share on other sites
Ta -Coulum-

This script is the same as above but with gamma reduction as well as blur. If you have pp enabled then you'll get both, if not, then you'll only get the gamma

tsk tsk tsk. Your half an hour late. And I thought you were dedicated...:)

Nah just jokin. I'll give it a test.

--EDIT--

I don't know what others will think about those suppression effects... but I think they're fucking sexy. Combined with the weapon sway/camshake they look really professional and natural. Awesome job.

And I like how in debug mode there's different coloured circles (balls just sounds... I don't know) marking different levels of suppression. I just watched the ai go at it and watched how they were suppressing each other/ getting suppressed. Very neat.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Guys, any video for the Arma addicts that are currently working at this hour ? :D

And seriously, possible to have this mod on six's updater? easier to track and update IMHO.

Share this post


Link to post
Share on other sites

Sorry fraps causes my computer to lag like hell, and I only have a 30 second trial anyways. But i can tell you it is SOOOOOOOO! awesome. sucks you can't see it;)

Nah, Its actually pretty simple. the edges of the screen go blurry, everything get brighter, and the weapon shakes. But I feel that the two suit each other quiet smoothely, and definitely give you the idea that you are suppressed without, being visually distracting. It could just be me but I like it alot.

As for the six updater, I tried contacting sickboy but for some reason he doesn't let anyone pm him. does anyone know how I can get a hold of him?

Edited by -Coulum-

Share this post


Link to post
Share on other sites

It should probably be renamed to TPWC suppression system soonish. Since it can be quite great for PvP too since players can suppress each other now.

Share this post


Link to post
Share on other sites

I tweaked it a bit so the sway lasts less time (previously it was lasting as long as "tpwc_suppressedstance" == 3 which meant 10 seconds) and made it so a lighter less noticealbe sway is also experienced at lower levels of suppression.

/*  
TPWC AI SUPPRESSION  

Authors: TPW & -Coulum-  
Additional code: Fabrizio_T, Ollem 
1.02 20120626 
*/  

if (isServer || isDedicated) then { 

//Log it 
diag_log format ["AI SUPPRESS STARTED: Server: %1 - Dedicated: %2", isServer, isDedicated]; 

////////////  
//VARIABLES  
///////////  

//Delay before suppression functions start. Allows time for other mods if needed 
tpwc_ai_sup_sleep = 2;  

//Debugging. Will display red balls over any suppressed units. 0 = no debugging, 1 = debugging  
tpwc_ai_sup_debug = 1;  

//Bullet detection radius (m). Bullets must pass within this distance of unit to suppress them. If set much below 10m, bullets may not be detected  
tpwc_ai_sup_br = 10;  

//Bullet ignore radius (m). Bullets from a shooter closer than this will not suppress.   
tpwc_ai_sup_ir = 25;  

//Shot threshold. More shots than this will cause unit to drop/crawl  
tpwc_ai_sup_st = 5;  

//Startup hint. 0 = no hint, 1 = hint  
tpwc_ai_sup_hint = 1;   

//Player suppression visuals. 0 = no player suppression, 1 = player suppression  
tpwc_ai_sup_playersup = 1;   

//Pistol and SMG ammo to ignore. Add custom ammo (eg suppressed) or change to taste      
tpwc_ai_sup_mags =[  
"30rnd_9x19_MP5",     
"30rnd_9x19_MP5SD",     
"15Rnd_9x19_M9",     
"15Rnd_9x19_M9SD",     
"7Rnd_45ACP_1911",     
"7Rnd_45ACP_1911",    
"8Rnd_9x18_Makarov",    
"8Rnd_9x18_MakarovSD",    
"64Rnd_9x19_Bizon",    
"64Rnd_9x19_SD_Bizon",    
"13Rnd_9mm_SLP",    
"17Rnd_9x19_glock17",    
"6Rnd_45ACP",    
"30Rnd_9x19_UZI",    
"30Rnd_9x19_UZI_SD"  
];    

//////////  
// SET UP  
//////////  

//Declare private variables  
private ["_stanceregain","_skillregain","_unit","_bc","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball1","_ball2","_ball3","_skillset","_asr","_tint","_blur","_x"];  

//Allow time for ASR AI skills to propagate  
sleep tpwc_ai_sup_sleep;  

//Start hint     
if (tpwc_ai_sup_hint == 1) then {  
0 = [] spawn { 
hintsilent "TPWC AI Suppress 1.02 Active";  
sleep 3;  
hintsilent ""};  
};     


//////////////////  
// MAIN FUNCTIONS   
//////////////////   

//BULLET DETECTION LOOP (TIME CRITICAL) 
//Do not touch this please 
tpwc_ai_sup_detect =       
{      
   {     
   _unit = _x; 
   if !(isnull tpwc_ai_sup_bullet) then      
       {     
       _bc = count ((getposatl _unit) nearobjects ["bulletbase",tpwc_ai_sup_br]);     
       if (_bc > 0) then      
           {    
           if ((tpwc_ai_sup_fired distance _unit) > tpwc_ai_sup_ir) then      
               {     
               if !(tpwc_ai_sup_mag in tpwc_ai_sup_mags) then      
                   {    
                   _unit setvariable ["tpwc_skillregain", diag_ticktime + (random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage"))];      
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];     
                   _unit setvariable ["tpwc_supshots",(_unit getvariable "tpwc_supshots") + _bc];     
                   _unit setvariable ["tpwc_suppressedstance", 1]; 
                   if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then 
                       { 
                       _unit setvariable ["tpwc_suppressedstance", 2];                             
                       if (_unit getvariable "tpwc_supshots" > tpwc_ai_sup_st) then     
                           { 
                           _unit setvariable ["tpwc_suppressedstance", 3];                                 
                           };     
                       };      
                   };     
               };     
           };     
       };     
   } foreach allunits;     
};     


//UNIT STANCE/SKILL MODIFICATION LOOP (NON TIME CRITICAL) 
tpwc_ai_sup_behaviour =  
{ 
tpwc_ai_sup_supvisflag = 0; 
while {true} do  
   { 
       { 
       if (alive _x) then  
           { 
           _unit  = _x; 
           _skillregain = _unit getvariable ["tpwc_skillregain", -1];      
           _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];    

           //Set initial parameters for each unit 
           if (_stanceregain == -1) then      
               {  
               _unit setvariable ["asr_ai_sys_aiskill_configured", false];   
               _unit setvariable ["tpwc_skillset", false];   
               _unit setvariable ["tpwc_combatmode", "unchanged"];  
               _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];    
               _unit setvariable ["tpwc_originalshake",  _unit skill "aimingshake"];   
               _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];    
               _unit setvariable ["tpwc_general", _unit skill "general"];   
               _unit setvariable ["tpwc_stanceregain", diag_ticktime];    
               _unit setvariable ["tpwc_skillregain", diag_ticktime];      
               _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];     
               if ( ( assignedVehicleRole _unit) select 0 == "Turret"  ) then  
                   { 
                   (vehicle _unit) addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;tpwc_ai_sup_mag = _this select 5; tpwc_ai_sup_bullet = _this select 6}];  
                   }; 
               if (tpwc_ai_sup_debug == 1) then    
                   {   
                   _ball1 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit; 
                   _ball1 setObjectTexture [0,"#(argb,8,8,3)color(0.2,0.9,0.2,0.5,ca)"]; 
                   _ball1 attachTo [_unit,[0,0,2]];  
                   _unit setvariable ["tpwc_sup1ball",_ball1];  

                   _ball2 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit; 
                   _ball2 setObjectTexture [0,"#(argb,8,8,3)color(0.6,0.9,0.0,0.7,ca)"]; //yellow 
                   _ball2 attachTo [_unit,[0,0,2]];  
                   _unit setvariable ["tpwc_sup2ball",_ball2];  

                   _ball3 = "Sign_sphere25cm_EP1" createvehicle getposatl _unit; 
                   _ball3 setObjectTexture [0,"#(argb,8,8,3)color(0.8,0.5,0.5,0.5,ca)"]; //red 
                   _ball3 attachTo [_unit,[0,0,2]];  
                   _unit setvariable ["tpwc_sup3ball",_ball3];  

                   }; 
               };  

           //If unit skills are unsuppressed 
           if (diag_ticktime >= _skillregain) then     
               {   
               _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";       
               _originalshake = _unit getvariable "tpwc_originalshake";                
               _originalcourage = _unit getvariable "tpwc_originalcourage";    
               _general = _unit getvariable "tpwc_general";          
               if((_unit skill "aimingaccuracy") < _originalaccuracy) then     
                   {   
                   _unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.325)];      
                   };    
               if((_unit skill "aimingshake") < _originalshake) then     
                   {     
                   _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.325)];     
                   };   
               }; 

           //If unit stance is unsuppressed 
           if ( diag_ticktime >= _stanceregain) then      
               { 
               if (tpwc_ai_sup_debug == 1) then    
                   {      
               _ball1 = _unit getvariable "tpwc_sup1ball";  
               _ball1 hideobject true; 
               _ball2 = _unit getvariable "tpwc_sup2ball";  
               _ball2 hideobject true; 
               _ball3 = _unit getvariable "tpwc_sup3ball";  
               _ball3 hideobject true; 
                   }; 
               _unit setvariable ["tpwc_supshots", 0];     
               _unit setunitpos "auto";    
               _originalcourage = _unit getvariable "tpwc_originalcourage";    
               _general = _unit getvariable "tpwc_general"; 
               _unit setvariable ["tpwc_suppressedstance", 0];              
               if((_unit skill "courage") < (_originalcourage - 0.1)) then     
                   {     
                   _unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];      
                   }    
                   else   
                   {   
                   if (_unit getvariable "tpwc_combatmode" != "unchanged") then  
                       { 
                       _unit setbehaviour str(_unit getvariable "tpwc_combatmode"); 
                       _unit setvariable ["tpwc_combatmode", "unchanged"];  
                       }; 
                   };   
               };    

           //If any bullets near unit  
           if (_unit getvariable "tpwc_suppressedstance" > 0) then  
               { 
               _unit setunitpos "middle"; 
               if (tpwc_ai_sup_debug == 1) then    
                   {   
                   _ball1 = _unit getvariable "tpwc_sup1ball";  
                   _ball1 hideobject false; 
                   _ball2 = _unit getvariable "tpwc_sup2ball";  
                   _ball2 hideobject true; 
                   _ball3 = _unit getvariable "tpwc_sup3ball";  
                   _ball3 hideobject true; 
                   };  
               }; 

           //If enemy bullets near unit      
           if (_unit getvariable "tpwc_suppressedstance" > 1) then  
               { 
               if (tpwc_ai_sup_debug == 1) then    
                   {  
                   _ball1 = _unit getvariable "tpwc_sup1ball";  
                   _ball1 hideobject true; 
                   _ball2 = _unit getvariable "tpwc_sup2ball";  
                   _ball2 hideobject false; 
                   _ball3 = _unit getvariable "tpwc_sup3ball";  
                   _ball3 hideobject true;             
                   }; 

               _unit setvariable ["tpwc_combatmode", behaviour _unit];  
               if( !( behaviour _unit in ["COMBAT", "STEALTH"] ) ) then  
                   { 
                   _unit setbehaviour "COMBAT";  
                   };     
               _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";      
               _originalshake = _unit getvariable "tpwc_originalshake";    
               _originalcourage = _unit getvariable "tpwc_originalcourage";     
               _general = _unit getvariable "tpwc_general";   
               _shots = _unit getvariable "tpwc_supshots";   
               if (diag_ticktime < _skillregain) then  
                   {        
                   _unit setskill ["aimingaccuracy",_originalaccuracy*_originalcourage*_general-(_shots*(1-_general)*.003)];       
                   _unit setskill ["aimingshake",_originalshake*_originalcourage*_general-(_shots*(1-_general)*.003)];      
                   _unit setskill ["courage",(_unit skill "courage")-(_shots*(1-_general)*(1-_originalcourage)*.07)];  
                   }; 
	if ((_unit == player) and (tpwc_ai_sup_playersup == 1) and (diag_ticktime < _skillregain)) then  
                   {  
                   addCamShake [1.5 - (skill player),(random 4)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage")) , 2.5] 
                   };   
               }; 

           //If unit is suppressed with more than 5 enemy bullets 
           if (_unit getvariable "tpwc_suppressedstance" == 3) then  
               { 
               if (tpwc_ai_sup_debug == 1) then    
                   { 
                   _ball1 = _unit getvariable "tpwc_sup1ball";  
                   _ball1 hideobject true; 
                   _ball2 = _unit getvariable "tpwc_sup2ball";  
                   _ball2 hideobject true; 
                   _ball3 = _unit getvariable "tpwc_sup3ball";  
                   _ball3 hideobject false; 
                   }; 
               _unit setunitpos "down";  
               _unit forcespeed -1; 
               if ((_unit == player) and (tpwc_ai_sup_playersup == 1) and (diag_ticktime < _skillregain)) then  
                   { 
                   [] spawn tpwc_ai_sup_visuals; 
                   addCamShake [2 - (skill player),(random 6)-((_unit getvariable "tpwc_general")+(_unit getvariable "tpwc_originalcourage")) , 5] 
                   };  
               }; 
           }; 
       } foreach allunits;  

       //Remove debug balls from dead AI 
       if (tpwc_ai_sup_debug == 1) then 
           { 
               { 
                   _unit = _x; 
                   _ball1 = _unit getvariable "tpwc_sup1ball"; 
                   if ( !(_ball1 == objNull) ) then  
                       {   
                       detach _ball1;  
                       deleteVehicle _ball1; 
                       _unit setvariable ["tpwc_sup1ball",nil];         
                       }; 
                       _ball2 = _unit getvariable "tpwc_sup2ball"; 
                   if ( !(_ball2 == objNull) ) then  
                       {   
                       detach _ball2;  
                       deleteVehicle _ball2; 
                       _unit setvariable ["tpwc_sup2ball",nil];         
                       }; 
                       _ball3 = _unit getvariable "tpwc_sup3ball"; 
                   if ( !(_ball3 == objNull) ) then  
                       {   
                       detach _ball3;  
                       deleteVehicle _ball3; 
                       _unit setvariable ["tpwc_sup3ball",nil];         
                       }; 
               } foreach allDead; 
           }; 
   sleep 1;     
   } 
}; 

//BLUR PLAYER VISION WHEN SUPPRESSED 
tpwc_ai_sup_visuals =  
{ 
if (tpwc_ai_sup_supvisflag == 0) then  
   { 
   tpwc_ai_sup_supvisflag = 1; 
   _tint = ppEffectCreate ["Colorcorrections", 1552]; 
   _tint ppEffectEnable true; 
   _blur = ppEffectCreate ["RadialBlur", 1551]; 
   _blur ppEffectEnable true; 
   _blur ppEffectAdjust [0.001,0.001,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.002, [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
   _tint ppEffectCommit 0; 
   sleep 0.1; 
   _blur ppEffectAdjust [0.002,0.002,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.004, [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
   _tint ppEffectCommit 0; 
   sleep 0.1; 
   _blur ppEffectAdjust [0.003,0.003,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.006, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ;  
   _tint ppEffectCommit 0; 
   sleep 0.1; 
   _blur ppEffectAdjust [0.004,0.004,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.008, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ;  
   _tint ppEffectCommit 0; 
   sleep 5; 
   _blur ppEffectAdjust [0.003,0.003,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.006, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ; 
   _tint ppEffectCommit 0; 
   sleep 0.1; 
   _blur ppEffectAdjust [0.002,0.002,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.004, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ; 
   _tint ppEffectCommit 0; 
   sleep 0.1; 
   _blur ppEffectAdjust [0.001,0.001,0.1,0.1]; 
   _blur ppEffectCommit 0; 
   _tint ppEffectAdjust[1, 1, -0.002, [0,0,0,0], [0,0,0,1], [0,0,0,1]] ; 
   _tint ppEffectCommit 0; 
   ppEffectDestroy _blur; 
   ppEffectDestroy _tint; 
   tpwc_ai_sup_supvisflag = 0; 
   }; 
}; 


//IF ASR AI HAS SET UNIT SKILLS, MAKE THESE THE "ORIGINALS" FOR EACH UNIT   
tpwc_ai_sup_asrskills =  
{  
sleep 3;  
while {true} do   
   {  
       {  
       _unit = _x;  
       _asr = _unit getVariable "asr_ai_sys_aiskill_configured";  
       _skillset = _unit getVariable "tpwc_skillset";  
       if ((_asr) && !(_skillset))then   
           {  
           _unit setvariable ["tpwc_originalaccuracy", _unit skill "aimingaccuracy"];    
           _unit setvariable ["tpwc_originalshake", _unit skill "aimingshake"];   
           _unit setvariable ["tpwc_originalcourage", _unit skill "courage"];    
           _unit setvariable ["tpwc_general",_unit skill "general"];   
           _unit setvariable ["tpwc_skillset", true];  
           };  
       } foreach allunits;  
   sleep 30;  
   };  
};   

///////////////// 
// RUN IT 
///////////////// 

//Spawn behaviour loop 
[] spawn tpwc_ai_sup_behaviour;  
sleep 1; 

//Spawn ASR_AI skill set loop if running ASR_AI > 1.15.1      
if (isclass (configfile >> "cfgPatches">>"asr_ai_sys_aiskill")) then   
   {  
   _asr_ai_va = getArray (configfile>>"cfgPatches">>"asr_ai_main">>"versionAr"); 
   if (_asr_ai_va select 0 >= 1 && _asr_ai_va select 1 >= 15 && _asr_ai_va select 2 >= 1) then  
       { 
       [] spawn tpwc_ai_sup_asrskills;  
       };     
   };  

//Call time critical bullet detection loop 
[tpwc_ai_sup_detect,0] call cba_fnc_addPerFrameHandler;   

};  

Probably ping Sickboy at his six updater thread.

Ah your a genius. I'll do that.

Since it can be quite great for PvP too since players can suppress each other now.

except it isn't officially MP compatible.

Share this post


Link to post
Share on other sites

Just downloaded the pbo from the OP.

And I have had some odd results:

1) I shot a bullet at a single rifleman, and he lay down like a normal AI. But the (the red dot appeared) and your script told him that he was suppressed, so he went up to kneeling position. Clearly you don't want suppressed AI to rise instead of drop.

2) If you suppress AI on the move, are they supposed to stop moving? Mine didn't.

3) AI suppressed by firing bullets past their head don't have rate of fire reduced. Does your script apply vanilla suppression effects to the AI as well?

4) There seems to be some randomness with whether suppression works or not, which on second thought is perfectly appropriate.

Lastly, I saw some bizarre behavior that I can't decisively blame on the script, but I haven't seen any of it before. I suppressed a rifleman twice, and he started sprinting away from me as fast as he could. First, I though he was just doing the usual suicidal flanking maneuver, be he ran right past me, heading for the hills. One the way, he threw two frag grenades while running, in his direction of movement. He didn't aim them at me. Secondly, when he was spraying me full auto, he ended up shooting vertically, as if he was aiming at the spots where my bullets went over his head. He would correct for recoil at all, or even aim at the correct elevation. And I think I saw bullets hitting the ground in front of him, as if they were falling from his muzzle.

Edit: Yes, something in the script is causing units to shoot straight up into the air, with the bullets spraying the ground at their feet.

This is with a Chedaki rifleman and ASR running. Could there be conflicts?

Edited by maturin

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
Sign in to follow this  

×