Jump to content
Sign in to follow this  
tpw

TPWC AI suppression system

Recommended Posts

No way, but thanks for making me smile with the whole face :D I learned a lot about scripting from the best modding gang which is the ACE team, but there's still so much ...

The link above provides the only addon that changed since ASR_AI v1.15.1, will probably make an official 1.15.2 update soon.

---------- Post added at 15:55 ---------- Previous post was at 15:49 ----------

I did not even scratch that danger fsm yet, but was planning to, esp. to see if the AI can be made to react to spawned ammo (magic arty ?). Hope to have a look at it soon.

Well for the love of god please do something with the danger.fsm...

On a related note, your modified aiskills is set to query a unit's tpws_suppressedstance right? Currently that can be either 0 or 1. My latest development stuff can have tpwc_suppressedstance as 0, 1, 2 or 3 depending on the severity of the suppression. How will this affect your current implementation?

---------- Post added at 23:15 ---------- Previous post was at 23:04 ----------

Had a bad day tpw? If you dont appreciate input, best just to ignore it.

Sorry PVP if that came across as too harsh. I'm well aware of your knowledge and contributions to this forum. I do appreciate your input, I keep thanking you for it, but also feel that I keep having to justify my decisions too. We worked hard to present a mod that people would find useful, and it does get frustrating when it appears that you think the approach taken is totally invalid.

Of course there is more than one way to do this. I'll explore the alternatives if the general consensus is that this mod is deeply flawed.

Share this post


Link to post
Share on other sites
because some people play arma to feel like a god.

Make it on by default then and an option to turn it off for people who like to cheat :rolleyes:

If anything it will only teach players to stay in cover/avoid staying under fire and that suppression fire works both ways

The shake shouldn't be like some earthquake of course. But on the level with defaul BIS suppression shake. Just enough to stop you from sniping the enemy while suppressed.

Share this post


Link to post
Share on other sites
The shake shouldn't be like some earthquake of course. But on the level with defaul BIS suppression shake. Just enough to stop you from sniping the enemy while suppressed.

Hey metalcraze, heres the script with camera shake/ sway stuff. If you haven't already, try it our and let us know if it feels natural or too much like an earthquake.

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.01 20120625
*/ 

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

//Suppression mode. 1 = basic , 2 = light, 3 = full stance / skills modification    
tpwc_ai_sup_mode = 3;   

//Delay before suppression functions start. Allows time for other AI mods to set unit skills 
tpwc_ai_sup_sleep = 5; 

//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;  

//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 {sleep 3; hintsilent "TPWC AI Suppress 1.01 Active"; sleep 3; hintsilent ""}; 
};    


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

//Basic version 
tpwc_ai_sup_basic =     
{   
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", diag_ticktime];  
           _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;          
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
           _unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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    
                   {   
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];   
                   _shots = _unit getvariable "tpwc_supshots";   
                   _unit setvariable ["tpwc_supshots", _shots + _bc];   
                   _shots = _unit getvariable "tpwc_supshots";  
                   _unit setunitpos "middle"; 
                   _unit setvariable ["tpwc_suppressedstance", 1]; 
                   if (tpwc_ai_sup_debug == 1) then  
                       { 
                       _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                       };             
                   if (_shots > tpwc_ai_sup_st) then   
                       {  
                       _unit setunitpos "down";  
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

//Lite version 
tpwc_ai_sup_ai_sup_lite =     
{    
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", 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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;              
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
           _unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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_stanceregain", diag_ticktime + 10];   
                       _shots = _unit getvariable "tpwc_supshots";   
                       _unit setvariable ["tpwc_supshots", _shots + _bc];   
                       _unit setunitpos "middle"; 
                       _unit setvariable ["tpwc_suppressedstance", 1];                         
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then    
                           { 
                           _shots = _unit getvariable "tpwc_supshots";  
                           if (tpwc_ai_sup_debug == 1) then  
                               { 
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                               }; 
                           if (_shots > tpwc_ai_sup_st) then   
                               {  
                               _unit setunitpos "down";  
                               };   
                           };    
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

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

       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 ( 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.003)];     
               }   
               else  
               {  
               if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
                   {
                   _unit setbehaviour str(_unit getvariable "tpwc_combatmode");
                   _unit setvariable ["tpwc_combatmode", "unchanged"]; 
                   };
               _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];       
               };  
           };   

       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"))*.01)];     
               };   
           if((_unit skill "aimingshake") < _originalshake) then    
               {    
               _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.01)];    
               };  
           if (((_unit skill "aimingshake") > (_originalshake - 0.1)) && ((_unit skill "aimingaccuracy") > (_originalaccuracy - 0.1))) then   
               {  
               _unit setvariable ["tpwc_skillregain", diag_ticktime + 10];  
               }  
           };   

       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];    
                       _shots = _unit getvariable "tpwc_supshots";    
                       _unit setvariable ["tpwc_supshots", _shots + _bc];    
                       _unit setunitpos "middle";    
                       _unit setvariable ["tpwc_suppressedstance", 1];     
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
                           {
                           _unit setvariable ["tpwc_combatmode", behaviour _unit]; 
                           _unit setbehaviour "COMBAT";    
                           _shots = _unit getvariable "tpwc_supshots";   
                           _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
                           _originalshake = _unit getvariable "tpwc_originalshake";   
                           _originalcourage = _unit getvariable "tpwc_originalcourage";    
                           _general = _unit getvariable "tpwc_general";  
                           _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 == player) then 
               {
               addcamshake [(0.55/((player skill "aimingaccuracy")+(player skill "general"))) ,((random 6) - ((_unit skill "general")+(_unit skill "courage"))) ,(2.5 - ((player skill "aimingaccuracy")+(_unit skill "courage")))];
               };     
                           if (tpwc_ai_sup_debug == 1) then   
                               {  
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false;  
                               };                          
                           if (_shots > tpwc_ai_sup_st) then    
                               {   
                               _unit setunitpos "down";   
                               };    
                           };     
                       };    
                   };    
               };    
           };    
       };     
   } foreach allunits;    
};    

//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; 
   }; 
};  

//CALL APPROPRIATE FUNCTION USING PER FRAME EVENTHANDLER 
if (tpwc_ai_sup_mode == 1) then  
   { 
   [tpwc_ai_sup_basic,0] call cba_fnc_addPerFrameHandler; 
   };   
if (tpwc_ai_sup_mode == 2) then  
   { 
   [tpwc_ai_sup_lite,0] call cba_fnc_addPerFrameHandler; 
   };  
if (tpwc_ai_sup_mode == 3) then  
   {
   //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; 
           };    
       }; 
   [tpwc_ai_sup_full,0] call cba_fnc_addPerFrameHandler;  
   };  

Share this post


Link to post
Share on other sites
Well for the love of god please do something with the danger.fsm...

On a related note, your modified aiskills is set to query a unit's tpws_suppressedstance right? Currently that can be either 0 or 1. My latest development stuff can have tpwc_suppressedstance as 0, 1, 2 or 3 depending on the severity of the suppression. How will this affect your current implementation?

Well, good thing I did not rush the 1.15.2 update :) I'll make it a "> 0" check. It was checking if "== 1" then skip stance change in the latest pbo I provided here.

Share this post


Link to post
Share on other sites
Well, good thing I did not rush the 1.15.2 update :) I'll make it a "> 0" check. It was checking if "== 1" then skip stance change in the latest pbo I provided here.

Thanks Robalo, much appreciated.

Share this post


Link to post
Share on other sites

will this be put up at Six's updater? I'm foreseeing this mod will be constantly updated similar to Robalo's ASR AI.

Share this post


Link to post
Share on other sites

Tested. It looks like a slight wavering (like a "drunk" effect). I think it will be better if it will have smaller waving radius but quicker waving (like a shake) because it can only be noticed when not looking down the sights - because when looking there's already slight random wavering due to breathing.

Share this post


Link to post
Share on other sites

Congrats on the creation of this mod, Tpw! Definitely going to keep this snuggled close by along with ASR AI when me and my guys co-op.

"makes it harder to get a bead on an enemy when you're shaking like a dog shitting peach pips." One of THE best descriptions of suppression I've ever heard! lol

Share this post


Link to post
Share on other sites

Amazing job guys!

I didn't have time to look into the code and i was wondering if the addon version it's only server-side or clients have to install it too...Any tests on MP environment?

Cheers

Share this post


Link to post
Share on other sites
Tested. It looks like a slight wavering (like a "drunk" effect). I think it will be better if it will have smaller waving radius but quicker waving (like a shake) because it can only be noticed when not looking down the sights - because when looking there's already slight random wavering due to breathing.

Thanks. I've made three new versions with different "sway". If you or anyone else has the time or will, it would be great if you could tell me which you think is best.

Version 1

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.01 20120625
*/ 

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

//Suppression mode. 1 = basic , 2 = light, 3 = full stance / skills modification    
tpwc_ai_sup_mode = 3;   

//Delay before suppression functions start. Allows time for other AI mods to set unit skills 
tpwc_ai_sup_sleep = 5; 

//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;  

//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 {sleep 3; hintsilent "TPWC AI Suppress 1.01 Active"; sleep 3; hintsilent ""}; 
};    


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

//Basic version 
tpwc_ai_sup_basic =     
{   
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", diag_ticktime];  
           _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;          
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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    
                   {   
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];   
                   _shots = _unit getvariable "tpwc_supshots";   
                   _unit setvariable ["tpwc_supshots", _shots + _bc];   
                   _shots = _unit getvariable "tpwc_supshots";  
                   _unit setunitpos "middle"; 
				_unit setvariable ["tpwc_suppressedstance", 1]; 
                   if (tpwc_ai_sup_debug == 1) then  
                       { 
                       _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                       };             
                   if (_shots > tpwc_ai_sup_st) then   
                       {  
                       _unit setunitpos "down";  
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

//Lite version 
tpwc_ai_sup_ai_sup_lite =     
{    
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", 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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;              
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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_stanceregain", diag_ticktime + 10];   
                       _shots = _unit getvariable "tpwc_supshots";   
                       _unit setvariable ["tpwc_supshots", _shots + _bc];   
                       _unit setunitpos "middle"; 
					_unit setvariable ["tpwc_suppressedstance", 1]; 						
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then    
                           { 
                           _shots = _unit getvariable "tpwc_supshots";  
                           if (tpwc_ai_sup_debug == 1) then  
                               { 
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                               }; 
                           if (_shots > tpwc_ai_sup_st) then   
                               {  
                               _unit setunitpos "down";  
                               };   
                           };    
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

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

       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 ( 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.003)];     
               }   
               else  
               {  
			if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
				{
				_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
				_unit setvariable ["tpwc_combatmode", "unchanged"]; 
				};
			_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];       
               };  
           };   

       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"))*.01)];     
               };   
           if((_unit skill "aimingshake") < _originalshake) then    
               {    
               _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.01)];    
               };  
           if (((_unit skill "aimingshake") > (_originalshake - 0.1)) && ((_unit skill "aimingaccuracy") > (_originalaccuracy - 0.1))) then   
               {  
               _unit setvariable ["tpwc_skillregain", diag_ticktime + 10];  
               }  
           };   

       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];    
                       _shots = _unit getvariable "tpwc_supshots";    
                       _unit setvariable ["tpwc_supshots", _shots + _bc];    
                       _unit setunitpos "middle";    
					_unit setvariable ["tpwc_suppressedstance", 1]; 	
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
						{
                           _unit setvariable ["tpwc_combatmode", behaviour _unit]; 
						_unit setbehaviour "COMBAT";	
                           _shots = _unit getvariable "tpwc_supshots";   
                           _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
                           _originalshake = _unit getvariable "tpwc_originalshake";   
                           _originalcourage = _unit getvariable "tpwc_originalcourage";    
                           _general = _unit getvariable "tpwc_general";  
                           _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 == player) then 
			{
			addcamshake [.75,((random 6) - ((_unit skill "general")+(_unit skill "courage"))) ,3.5];
			};	 
                           if (tpwc_ai_sup_debug == 1) then   
                               {  
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false;  
                               };                          
                           if (_shots > tpwc_ai_sup_st) then    
                               {   
                               _unit setunitpos "down";   
                               };    
                           };     
                       };    
                   };    
               };    
           };    
       };     
   } foreach allunits;    
};    

//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; 
   }; 
};  

//CALL APPROPRIATE FUNCTION USING PER FRAME EVENTHANDLER 
if (tpwc_ai_sup_mode == 1) then  
   { 
   [tpwc_ai_sup_basic,0] call cba_fnc_addPerFrameHandler; 
   };   
if (tpwc_ai_sup_mode == 2) then  
   { 
   [tpwc_ai_sup_lite,0] call cba_fnc_addPerFrameHandler; 
   };  
if (tpwc_ai_sup_mode == 3) then  
   {
//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; 
		};	
	}; 
   [tpwc_ai_sup_full,0] call cba_fnc_addPerFrameHandler;  
   }; 

Version 2

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.01 20120625
*/ 

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

//Suppression mode. 1 = basic , 2 = light, 3 = full stance / skills modification    
tpwc_ai_sup_mode = 3;   

//Delay before suppression functions start. Allows time for other AI mods to set unit skills 
tpwc_ai_sup_sleep = 5; 

//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;  

//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 {sleep 3; hintsilent "TPWC AI Suppress 1.01 Active"; sleep 3; hintsilent ""}; 
};    


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

//Basic version 
tpwc_ai_sup_basic =     
{   
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", diag_ticktime];  
           _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;          
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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    
                   {   
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];   
                   _shots = _unit getvariable "tpwc_supshots";   
                   _unit setvariable ["tpwc_supshots", _shots + _bc];   
                   _shots = _unit getvariable "tpwc_supshots";  
                   _unit setunitpos "middle"; 
				_unit setvariable ["tpwc_suppressedstance", 1]; 
                   if (tpwc_ai_sup_debug == 1) then  
                       { 
                       _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                       };             
                   if (_shots > tpwc_ai_sup_st) then   
                       {  
                       _unit setunitpos "down";  
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

//Lite version 
tpwc_ai_sup_ai_sup_lite =     
{    
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", 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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;              
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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_stanceregain", diag_ticktime + 10];   
                       _shots = _unit getvariable "tpwc_supshots";   
                       _unit setvariable ["tpwc_supshots", _shots + _bc];   
                       _unit setunitpos "middle"; 
					_unit setvariable ["tpwc_suppressedstance", 1]; 						
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then    
                           { 
                           _shots = _unit getvariable "tpwc_supshots";  
                           if (tpwc_ai_sup_debug == 1) then  
                               { 
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                               }; 
                           if (_shots > tpwc_ai_sup_st) then   
                               {  
                               _unit setunitpos "down";  
                               };   
                           };    
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

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

       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 ( 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.003)];     
               }   
               else  
               {  
			if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
				{
				_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
				_unit setvariable ["tpwc_combatmode", "unchanged"]; 
				};
			_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];       
               };  
           };   

       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"))*.01)];     
               };   
           if((_unit skill "aimingshake") < _originalshake) then    
               {    
               _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.01)];    
               };  
           if (((_unit skill "aimingshake") > (_originalshake - 0.1)) && ((_unit skill "aimingaccuracy") > (_originalaccuracy - 0.1))) then   
               {  
               _unit setvariable ["tpwc_skillregain", diag_ticktime + 10];  
               }  
           };   

       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];    
                       _shots = _unit getvariable "tpwc_supshots";    
                       _unit setvariable ["tpwc_supshots", _shots + _bc];    
                       _unit setunitpos "middle";    
					_unit setvariable ["tpwc_suppressedstance", 1]; 	
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
						{
                           _unit setvariable ["tpwc_combatmode", behaviour _unit]; 
						_unit setbehaviour "COMBAT";	
                           _shots = _unit getvariable "tpwc_supshots";   
                           _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
                           _originalshake = _unit getvariable "tpwc_originalshake";   
                           _originalcourage = _unit getvariable "tpwc_originalcourage";    
                           _general = _unit getvariable "tpwc_general";  
                           _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 == player) then 
			{
			addcamshake [.5,((random 6) - ((_unit skill "general")+(_unit skill "courage"))) ,4.5];
			};	 
                           if (tpwc_ai_sup_debug == 1) then   
                               {  
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false;  
                               };                          
                           if (_shots > tpwc_ai_sup_st) then    
                               {   
                               _unit setunitpos "down";   
                               };    
                           };     
                       };    
                   };    
               };    
           };    
       };     
   } foreach allunits;    
};    

//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; 
   }; 
};  

//CALL APPROPRIATE FUNCTION USING PER FRAME EVENTHANDLER 
if (tpwc_ai_sup_mode == 1) then  
   { 
   [tpwc_ai_sup_basic,0] call cba_fnc_addPerFrameHandler; 
   };   
if (tpwc_ai_sup_mode == 2) then  
   { 
   [tpwc_ai_sup_lite,0] call cba_fnc_addPerFrameHandler; 
   };  
if (tpwc_ai_sup_mode == 3) then  
   {
//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; 
		};	
	}; 
   [tpwc_ai_sup_full,0] call cba_fnc_addPerFrameHandler;  
   }; 

Version 3

/* 
TPWC AI SUPPRESSION 

Authors: TPW & -Coulum- 
1.01 20120625
*/ 

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

//Suppression mode. 1 = basic , 2 = light, 3 = full stance / skills modification    
tpwc_ai_sup_mode = 3;   

//Delay before suppression functions start. Allows time for other AI mods to set unit skills 
tpwc_ai_sup_sleep = 5; 

//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;  

//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 {sleep 3; hintsilent "TPWC AI Suppress 1.01 Active"; sleep 3; hintsilent ""}; 
};    


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

//Basic version 
tpwc_ai_sup_basic =     
{   
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", diag_ticktime];  
           _unit addeventhandler ["fired",{tpwc_ai_sup_fired = _this select 0;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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;          
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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    
                   {   
                   _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];   
                   _shots = _unit getvariable "tpwc_supshots";   
                   _unit setvariable ["tpwc_supshots", _shots + _bc];   
                   _shots = _unit getvariable "tpwc_supshots";  
                   _unit setunitpos "middle"; 
				_unit setvariable ["tpwc_suppressedstance", 1]; 
                   if (tpwc_ai_sup_debug == 1) then  
                       { 
                       _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                       };             
                   if (_shots > tpwc_ai_sup_st) then   
                       {  
                       _unit setunitpos "down";  
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

//Lite version 
tpwc_ai_sup_ai_sup_lite =     
{    
   {   
   if (alive _x) then    
       { 
       _unit = _x;      
       _stanceregain = _unit getvariable ["tpwc_stanceregain", -1];  

       if (_stanceregain == -1) then    
           {      
           _unit setvariable ["tpwc_stanceregain", 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 ( diag_ticktime >= _stanceregain) then    
           {  
           _ball = _unit getvariable "tpwc_supball"; _ball hideobject true;              
           _unit setvariable ["tpwc_supshots", 0];   
           _unit setunitpos "auto";  
		_unit setvariable ["tpwc_suppressedstance", 0]; 
           _unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];  
           };  

       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_stanceregain", diag_ticktime + 10];   
                       _shots = _unit getvariable "tpwc_supshots";   
                       _unit setvariable ["tpwc_supshots", _shots + _bc];   
                       _unit setunitpos "middle"; 
					_unit setvariable ["tpwc_suppressedstance", 1]; 						
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then    
                           { 
                           _shots = _unit getvariable "tpwc_supshots";  
                           if (tpwc_ai_sup_debug == 1) then  
                               { 
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false; 
                               }; 
                           if (_shots > tpwc_ai_sup_st) then   
                               {  
                               _unit setunitpos "down";  
                               };   
                           };    
                       };   
                   };   
               };   
           };   
       };    
   } foreach allunits;   
};   

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

       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 ( 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.003)];     
               }   
               else  
               {  
			if (_unit getvariable "tpwc_combatmode" != "unchanged") then 
				{
				_unit setbehaviour str(_unit getvariable "tpwc_combatmode");
				_unit setvariable ["tpwc_combatmode", "unchanged"]; 
				};
			_unit setvariable ["tpwc_stanceregain", diag_ticktime + 10];       
               };  
           };   

       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"))*.01)];     
               };   
           if((_unit skill "aimingshake") < _originalshake) then    
               {    
               _unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.01)];    
               };  
           if (((_unit skill "aimingshake") > (_originalshake - 0.1)) && ((_unit skill "aimingaccuracy") > (_originalaccuracy - 0.1))) then   
               {  
               _unit setvariable ["tpwc_skillregain", diag_ticktime + 10];  
               }  
           };   

       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];    
                       _shots = _unit getvariable "tpwc_supshots";    
                       _unit setvariable ["tpwc_supshots", _shots + _bc];    
                       _unit setunitpos "middle";    
					_unit setvariable ["tpwc_suppressedstance", 1]; 	
                       if ((side tpwc_ai_sup_fired != side _unit) && (vehicle _unit == _unit)) then
						{
                           _unit setvariable ["tpwc_combatmode", behaviour _unit]; 
						_unit setbehaviour "COMBAT";	
                           _shots = _unit getvariable "tpwc_supshots";   
                           _originalaccuracy = _unit getvariable "tpwc_originalaccuracy";     
                           _originalshake = _unit getvariable "tpwc_originalshake";   
                           _originalcourage = _unit getvariable "tpwc_originalcourage";    
                           _general = _unit getvariable "tpwc_general";  
                           _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 == player) then 
			{
			addcamshake [1.25,((random 6) - ((_unit skill "general")+(_unit skill "courage"))) ,4];
			};	 
                           if (tpwc_ai_sup_debug == 1) then   
                               {  
                               _ball = _unit getvariable "tpwc_supball";_ball hideobject false;  
                               };                          
                           if (_shots > tpwc_ai_sup_st) then    
                               {   
                               _unit setunitpos "down";   
                               };    
                           };     
                       };    
                   };    
               };    
           };    
       };     
   } foreach allunits;    
};    

//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; 
   }; 
};  

//CALL APPROPRIATE FUNCTION USING PER FRAME EVENTHANDLER 
if (tpwc_ai_sup_mode == 1) then  
   { 
   [tpwc_ai_sup_basic,0] call cba_fnc_addPerFrameHandler; 
   };   
if (tpwc_ai_sup_mode == 2) then  
   { 
   [tpwc_ai_sup_lite,0] call cba_fnc_addPerFrameHandler; 
   };  
if (tpwc_ai_sup_mode == 3) then  
   {
//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; 
		};	
	}; 
   [tpwc_ai_sup_full,0] call cba_fnc_addPerFrameHandler;  
   }; 

great job colum! work with beta too?

Thank you, but congragulations should mostly go to tpw. He's the mastermind behind this. I see know reason why it shouldn't work with the latest beta.

I didn't have time to look into the code and i was wondering if the addon version it's only server-side or clients have to install it too...Any tests on MP environment?

Cheers

I think I speak for both of us when I say that we don't know much about making addons multiplayer compatible. My guess is the best bet is to use the script version on the dedicated server alone. But really I have zip knowledge on that kind of stuff. If anyone knows how we would go about this please share. No MP tests have been performed to my knowledge.

Share this post


Link to post
Share on other sites

Don't try the pbo version.

As Coulum said, try the script, making sure it's executed server-side only.

Share this post


Link to post
Share on other sites

Hello tpw!

First thanks for this great mod and second sorrry for my bad english i come from Europe Austria.

My problem is when i play on a dedicated server the units are crouch/kneel perfect but the unit will NO return to the previous stance, and second the units are not going in the drop/crawl position?

I tested only with your mod (the script version and the pbo version) it's not work by me.

In Singleplayer works perfect.

I hope you know what i mean. What can i do?

Regards Mike

Share this post


Link to post
Share on other sites

I think I speak for both of us when I say that we don't know much about making addons multiplayer compatible. My guess is the best bet is to use the script version on the dedicated server alone. But really I have zip knowledge on that kind of stuff. If anyone knows how we would go about this please share. No MP tests have been performed to my knowledge.

I dared to test this awesome piece of AI code in MP setting on a dedicated server and based on my very preliminary test results I can confirm it works in MP :yay:

I just added "if (isServer || isDedicated) then {" tailed by "};" around the code and bingo...

(I only ran the latest-sway-3 code in combination with ASR_AI 1.15.2 manually patched code)

Make sure you start the script on the server.

(The only thing I can't tell yet is what happens to AI part of a player's group: as far as I know they are local to the players client, so there the AI surpress may not work.. on the other hand, if so, I don't see how ASR_AI could work for those either)

Edited by Ollem

Share this post


Link to post
Share on other sites

Thanks for this much-needed script !!!!

will this be put up at Six's updater? I'm foreseeing this mod will be constantly updated similar to Robalo's ASR AI.
Great to know, if it's catching fire it's most likely my wife burning it down for overplaying this awesome game. :D
"makes it harder to get a bead on an enemy when you're shaking like a dog shitting peach pips." One of THE best descriptions of suppression I've ever heard! lol

+1 to the above :p

Share this post


Link to post
Share on other sites
I dared to test this awesome piece of AI code in MP setting on a dedicated server and based on my very preliminary test results I can confirm it works in MP

I just added "if (isServer || isDedicated) then {" taled by "};" around the code and bingo...

(I only ran the latest-sway-3 code in combination with ASR_AI 1.15.2 manually patched code)

Make sure you start the script on the server.

(The only thing I can't tell yet is what happens to AI part of a player's group: as far as I know they are local to the players client, so there the AI surpress may not work.. on the other hand, if so, I don't see how ASR_AI could work for those either)

Awesome, thanks for your testing Ollem. And you just put all the script into

(isServer || isDedicated) then {"HERE"};

??

It would be sweet if that's all that needed to be done. If anyone else has the time to try this as well it would be much appreciated - especially investigating whether soldiers in the players squad will benefit from the script.

First thanks for this great mod and second sorrry for my bad english i come from Europe Austria.

My problem is when i play on a dedicated server the units are crouch/kneel perfect but the unit will NO return to the previous stance, and second the units are not going in the drop/crawl position?

I tested only with your mod (the script version and the pbo version) it's not work by me.

In Singleplayer works perfect.

I hope you know what i mean. What can i do?

Regards Mike

Hi Mike, right now the mod is really for sp only. When it was created it was made for sp so it is not surprising that it doesn't work. Maybe try what Ollem said by wrapping the entire script in "if (isServer || isDedicated) then {" PUT IT HERE "};". Otherwise I am sorry but I can't help much more, as I don't have the knowledge or tools to orient/test this for mp. I am not sure, but I don't think tpw does either.

will this be put up at Six's updater? I'm foreseeing this mod will be constantly updated similar to Robalo's ASR AI.

I'll look into it, if tpw hasn't already. I know I personally would love to see it on the six updater as well.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

The "if { isServer ... " check is also safely useable in SP:

http://community.bistudio.com/wiki/isServer :

isServer: Returns true if the machine is either a server in a multiplayer game or if it is running a singleplayer game.

isDedicated: Return true if the machine (executing the command) is a dedicated server.

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.

Share this post


Link to post
Share on other sites

Version 2 is the best. Of course some tweaking may be needed.

What may help is the visual effect similar to Bohemia's one. And to not annoy the player with it going off after each bullet you may kick it in only after each 3rd one or so.

Overall this is a good indication to player that if you are getting suppressed repeatedly - maybe it's time to switch position :>

Share this post


Link to post
Share on other sites

Have a look at my development script a couple of posts ago, which has some blurring applied when a unit is suppressed by more than 5 bullets

Version 2 is the best. Of course some tweaking may be needed.

What may help is the visual effect similar to Bohemia's one. And to not annoy the player with it going off after each bullet you may kick it in only after each 3rd one or so.

Overall this is a good indication to player that if you are getting suppressed repeatedly - maybe it's time to switch position :>

Share this post


Link to post
Share on other sites

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.

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. With debug mode active, setting up an AI squad and shooting at them from a vehicle doesn't make the suppression indicators appear, and the units behave, as best I can tell, normally. I first noticed it when strafing with an AH-6J, but I've tested it with HMMWV M2s and M1A1s and the behavior (or lack thereof) is consistent. No suppressive effects from vehicle guns; hop out of the vehicle and fire a few shots over their heads, however, and everything works as expected: indicators appear and the units hit the deck. This is, as I said, true of all modes.

...but otherwise, this is the way the game should've worked from the beginning. Excellent job.

Edited by count_roland

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.

Share this post


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

×