Jump to content
Sign in to follow this  
tpw

TPWC AI suppression system

Recommended Posts

CBA

—

Ace

Acex

Acex RU

Ai mods used (these selected pbo’s) parts from SLX, GL4 & Zeus

St Movement

TPWC ai Suppress

No problems at all…

So it is conflicting with something I think, but not with these above, everything went really well in short mission, no problems at all..

Will do some more soon..

Share this post


Link to post
Share on other sites

Thanks for the detailed bug reports and the kind words everyone, much appreciated. Maybe this mod is crawling out of the swamp towards usability after all.

@Robalo - thanks very much for the ASR_AI tips. I will try to integrate them in and as you say, save myself a loop.

@jubxxxjub - "just doesn't work" doesn't tell me much. Are units not being suppressed? Are you not seeing debug balls? A bit more info will help me to help you.

@Coulum - I think we might need to look at the skill code a bit further, because it seems that a few bullets are rapidly causing unit skills to drop to around the 0.1 mark. Maybe just a simple percentage based drop (ie one bullet drops 5% of a given skill). And a simple percentage based skill regain too.

Share this post


Link to post
Share on other sites
CBA

—

Ace

Acex

Acex RU

Ai mods used (these selected pbo’s) parts from SLX, GL4 & Zeus

St Movement

TPWC ai Suppress

No problems at all…

So it is conflicting with something I think, but not with these above, everything went really well in short mission, no problems at all..

Will do some more soon..

My experience with bird watching AI is when they throw smoke grenades or attempting to throw 1. The ai will start looking up the sky and spin, but this was not due to this suppression mod. Maybe you could try to check on it.

Share this post


Link to post
Share on other sites

@jubxxxjub - "just doesn't work" doesn't tell me much. Are units not being suppressed? Are you not seeing debug balls? A bit more info will help me to help you.

The fact MP is not (or better very very limited) working on Dedicated is caused by the delay in bullet detection.

I did some more detailed MP testing yesterday and posted the results in fabrizio_T's seperate bDetect thread.

The concept itself works, but for Dedicated server some additional work is needed.

I do have some ideas which may or may not work: I'll look into this.

NOTE: Make sure the current code/PBO is only running on the server, not on any client in case of MP testing.

Share this post


Link to post
Share on other sites
@Coulum - I think we might need to look at the skill code a bit further, because it seems that a few bullets are rapidly causing unit skills to drop to around the 0.1 mark. Maybe just a simple percentage based drop (ie one bullet drops 5% of a given skill). And a simple percentage based skill regain too.

Okay I quickly whipped off this. It will drop a units skills By rougly 5% (give or take dependning on the units ability) for every shot. This kind of system will mean that units will be pretty hard to suppress quickly when concerning skill. And high skill units are very hard to suppress. Don't know if thats good or bad. Keep in mind that, with ASR at least, many units like takistani militia will start off with skill close to the "0.1 mark". The min a unit skill can go is 0.05 to prevent ground shooting - which no one has witnessed lately right?

I also made it so the amount of info a unit gains about the shooter varies depending on the distance the shooter is to the unit - But personally I prefer just to turn off the reveal part all together, simply because of the way the ai seems to be able to instantaneously pinpoint a muzzleflash after having the slightest bit of reveal/knowsabout.

Here it is...

/*    
TPWC AI SUPPRESSION    

Authors: TPW && -Coulum- && fabrizio_T   
Additional code: Ollem   
Version: 2.04beta  
Last modified: 20120705 
Requires: CBA, bDetect 
Disclaimer: Feel free to use and modify this code, on the proviso that you post back changes and improvements so that everyone can benefit from them, and acknowledge the original authors in any derivative works. 
*/    

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

//DELAY BEFORE SUPPRESSION FUNCTIONS START. ALLOWS TIME FOR OTHER AI MODS TO SET UNIT SKILLS 
tpwcas_sleep = 2; 

//DEBUGGING. WILL DISPLAY COLOURED BALLS OVER ANY SUPPRESSED UNITS. SET TO 1 FOR DEBUGGING 
tpwcas_debug = 1; 

//BULLET IGNORE RADIUS (M). BULLETS FROM A SHOOTER CLOSER THAN THIS WILL NOT SUPPRESS.  
tpwcas_ir = 25; 

//SHOT THRESHOLD. MORE SHOTS THAN THIS WILL CAUSE UNIT TO DROP/CRAWL 
tpwcas_st = 10; 

//STARTUP HINT 0 = NO HINT, 1 = HINT 
tpwcas_hint = 1; 

//PLAYER SUPPRESSION SHAKE. 0 = NO SUPPRESSION, 1 = SUPPRESSION     
tpwcas_playershake = 1; 

//PLAYER SUPPRESSION VISUALS. 0 = NO SUPPRESSION, 1 = SUPPRESSION     
tpwcas_playervis = 1; 

//PISTOL AND SMG AMMO TO IGNORE. ADD CUSTOM AMMO (EG SUPPRESSED) OR CHANGE TO TASTE.   
tpwcas_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"   
];  

//AI SKILL SUPPRESSION. 0 = SKILLS WILL NOT BE CHANGED, ONLY STANCE. 1 = SKILLS AND STANCE CHANGED UNDER SUPPRESSION 
tpwcas_skillsup = 1; 

//MINIMUM SKILL VALUE, NONE OF A UNIT'S SKILLS WILL DROP BELOW THIS UNDER SUPPRESSION 
tpwcas_minskill = 0.05; 

//REVEAL VALUE WHEN SUPPRESSED. 0 = NO REVEALING. 0.1 = SUPPRESSED UNIT KNOWS NOTHING ABOUT SHOOTER. 4 = UNIT KNOWS THE SHOOTER'S SIDE, POSTION, SHOE SIZE ETC 
tpwcas_reveal = 1.5; 

//MAXIMUM BULLET DISTANCE (m). A BULLET FURTHER THAN THIS FROM ITS SHOOTER WILL NOT SUPPRESS. SET LARGER IF YOU PLAN ON DOING A LOT OF SNIPING - BUT MAY IMPACT PERFORMANCE
tpwcas_maxdist = 600;


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

//DECLARE PRIVATE VARIABLES    
private ["_stanceregain","_skillregain","_unit","_shots","_originalaccuracy","_originalshake","_originalcourage","_general","_ball1","_ball2","_ball3","_skillset","_asr","_tint","_blur","_x","_ppmod","_ppmodifier"]; 

//INITIAL FILTERED UNIT ARRAY = ALL UNITS 
tpwcas_filtered_units = allunits; 

//WAIT 
sleep tpwcas_sleep;    

//START HINT       
if (tpwcas_hint == 1) then 
{    
0 = [] spawn 
	{   
	hintsilent "TPWC AI Suppress 2.04beta Active";    
	sleep 3;    
	hintsilent "";
	};    
}; 


//////////// 
//FUNCTIONS 
//////////// 

/*
MAIN LOOP
Every 1.5 sec:
- Assigns initial variables to each unit if they are not yet assigned
- Checks suppression state of unit and applies appropriate stance and skill changes
*/

tpwcas_fnc_main_loop = 
{   
while {true} do    
	{
	tpwcas_supvisflag = 0;   
		{   
		_unit  = _x;   
		_stanceregain = _unit getvariable ["tpwcas_stanceregain", -1];
		_skillregain = _unit getvariable ["tpwcas_skillregain", -1]; 			

		//SET INITIAL PARAMETERS FOR EACH UNIT   
		if (_stanceregain == -1) then        
			{    
			_unit setvariable ["asr_ai_sys_aiskill_configured", false];     
			_unit setvariable ["tpwcas_skillset", false]; 
			_unit setvariable ["tpwcas_originalaccuracy", _unit skill "aimingaccuracy"];      
			_unit setvariable ["tpwcas_originalshake",  _unit skill "aimingshake"];     
			_unit setvariable ["tpwcas_originalcourage", _unit skill "courage"];      
			_unit setvariable ["tpwcas_general", _unit skill "general"];     
			_unit setvariable ["tpwcas_stanceregain", time];      
			_unit setvariable ["tpwcas_skillregain", time];    

			//SET UP COLOURED DEBUGGING BALLS 
			if (tpwcas_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 ["tpwcas_sup1ball",_ball1];  
				_ball1 hideobject true;   

				_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 ["tpwcas_sup2ball",_ball2];  
				_ball2 hideobject true;   

				_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 ["tpwcas_sup3ball",_ball3];  
				_ball3 hideobject true; 
				};   
			};    



		//IF UNIT STANCE IS UNSUPPRESSED   
		if ( time >= _stanceregain) then        
			{ 
			_unit setunitpos "auto";                     
			_unit setvariable ["tpwcas_supstate",0];  
			_unit setvariable ["tpwcas_bc",0];     
			_unit setvariable ["tpwcas_ebc",0]; 

			//GRADUAL RETURN OF COURAGE 
			_originalcourage = _unit getvariable "tpwcas_originalcourage";      
			_general = _unit getvariable "tpwcas_general";  
			if((_unit skill "courage") < (_originalcourage - 0.05)) then       
				{       
				_unit setskill ["courage",(_unit skill "courage")+(_general)*(0.1)];        
				}      
				else 
				{ 
				//BACK TO NORMAL 
				_unit setskill ["courage",_originalcourage]; 
				_unit setvariable ["tpwcas_stanceregain", time + 10]; 
				};     
			};   

		//IF UNIT SKILLS ARE UNSUPPRESSED   
		if (time >= _skillregain) then       
			{   
			_originalaccuracy = _unit getvariable "tpwcas_originalaccuracy";         
			_originalshake = _unit getvariable "tpwcas_originalshake";                  
			_originalcourage = _unit getvariable "tpwcas_originalcourage";      
			_general = _unit getvariable "tpwcas_general";            
			//GRADUAL RETURN OF ACCURACY 
			if((_unit skill "aimingaccuracy") < _originalaccuracy) then       
				{     
				_unit setskill ["aimingaccuracy",(_unit skill "aimingaccuracy")+((_originalaccuracy-(_unit skill "aimingaccuracy"))*.075)];        
				};     
			//GRADUAL REDUCTION OF SHAKE     
			if((_unit skill "aimingshake") < _originalshake) then       
				{       
				_unit setskill ["aimingshake",(_unit skill "aimingshake")+((_originalshake-(_unit skill "aimingshake"))*.075)];       
				};  
			//BACK TO NORMAL     
			if     (((_unit skill "aimingshake") > (_originalshake - 0.05)) &&    ((_unit skill "aimingaccuracy") > (_originalaccuracy - 0.05))) then  
				{ 
				_unit setskill ["aimingshake",_originalshake]; 
				_unit setskill ["aimingaccuracy",_originalaccuracy]; 
				_unit setvariable ["tpwcas_skillregain", time + 10]; 
				};     
			};  

		//UNIT CHANGES FOR DIFFERENT SUPPRESSION 
		switch ( _unit getvariable "tpwcas_supstate" ) do  
			{  
			case 1: //IF ANY BULLETS NEAR UNIT  
				{  
				//CROUCH IF NOT PRONE 
				if ((_unit call CBA_fnc_getunitanim) select 0 != "prone") then  
					{ 
					_unit setunitpos "middle";     
					}; 
				};  

			case 2: //IF ENEMY BULLETS NEAR UNIT  
				{ 
				//CROUCH IF NOT PRONE 
				if ((_unit call CBA_fnc_getunitanim) select 0 != "prone") then  
					{ 
					_unit setunitpos "middle";     
					}; 
				//SKILL MODIFICATION 
				if (tpwcas_skillsup == 1) then 
					{ 
					_originalaccuracy = _unit getvariable "tpwcas_originalaccuracy";        
					_originalshake = _unit getvariable "tpwcas_originalshake";      
					_originalcourage = _unit getvariable "tpwcas_originalcourage";       
					_general = _unit getvariable "tpwcas_general";     
					_shots = _unit getvariable "tpwcas_ebc";     
					_newaccuracy = (_unit skill "aimingaccuracy")-(_shots*(1-_general)*(1-_originalcourage)*.01);
					_newshake = (_unit skill "aimingshake")-(_shots*(1-_general)*(1-_originalcourage)*.01);
					_newcourage = (_unit skill "courage")-(_shots*(1-_general)*(1-_originalcourage)*.02); 
					if (_newaccuracy < tpwcas_minskill) then  
						{ 
						_newaccuracy = tpwcas_minskill; 
						}; 
					if (_newshake < tpwcas_minskill) then  
						{ 
						_newshake = tpwcas_minskill; 
						}; 
					if (_newcourage < tpwcas_minskill) then  
						{ 
						_newcourage = tpwcas_minskill; 
						};     
					_unit setskill ["aimingaccuracy",_newaccuracy];         
					_unit setskill ["aimingshake",_newshake];        
					_unit setskill ["courage",_newcourage];  
					};     
				//PLAYER CAMERA SHAKE  
				if ((isplayer unit) && (tpwcas_playershake == 1)) then    
					{    
					addCamShake [1.5 - (skill player),(random 4)-((_unit getvariable "tpwcas_general")+(_unit getvariable "tpwcas_originalcourage")) , 2.5]   
					};     
				};  

			case 3: //IF UNIT IS SUPPRESSED BY MULTIPLE ENEMY BULLETS   
				{ 
				//GO PRONE 
				_unit setunitpos "down";     
				_unit forcespeed -1;  
				//SKILL MODIFICATION 
				if (tpwcas_skillsup == 1) then 
					{ 
					_originalaccuracy = _unit getvariable "tpwcas_originalaccuracy";        
					_originalshake = _unit getvariable "tpwcas_originalshake";      
					_originalcourage = _unit getvariable "tpwcas_originalcourage";       
					_general = _unit getvariable "tpwcas_general";     
					_shots = _unit getvariable "tpwcas_ebc"; 
					_newaccuracy = (_unit skill "aimingaccuracy")-(_shots*(1-_general)*(1-_originalcourage)*.01);
					_newshake = (_unit skill "aimingshake")-(_shots*(1-_general)*(1-_originalcourage)*.01);
					_newcourage = (_unit skill "courage")-(_shots*(1-_general)*(1-_originalcourage)*.02); 
					if (_newaccuracy < tpwcas_minskill) then  
						{ 
						_newaccuracy = tpwcas_minskill; 
						}; 
					if (_newshake < tpwcas_minskill) then  
						{ 
						_newshake = tpwcas_minskill; 
						}; 
					if (_newcourage < tpwcas_minskill) then  
						{ 
						_newcourage = tpwcas_minskill; 
						};     
					_unit setskill ["aimingaccuracy",_newaccuracy];         
					_unit setskill ["aimingshake",_newshake];        
					_unit setskill ["courage",_newcourage];   
					}; 
				//PLAYER CAMERA SHAKE AND FX 
				if (isplayer _unit) then     
					{   
					if (tpwcas_playershake == 1) then  
						{ 
						addCamShake [2 - (skill _unit),(random 6)-((_unit getvariable "tpwcas_general")+(_unit getvariable "tpwcas_originalcourage")) , 5]   
						}; 
					if (tpwcas_playervis == 1) then  
						{     
						[] spawn tpwcas_fnc_visuals;   
						}; 
					};   
				}; 
			};
		} foreach tpwcas_filtered_units; 
	sleep 1.5;      
	};   
};  

/*
UNIT FILTER
Every 5 sec:
- Checks whether unit is combatant, alive and uninjured, within 1000m of player
- Units meeting these criteria are put into a filtered units array which is used by the main loop
*/

tpwcas_fnc_filter =  
{ 
while {true} do 
	{ 
	tpwcas_filtered_units = []; 
		{ 
		if  
		(
		(vehicle _x == _x) && 
		(lifestate _x == "ALIVE") &&  
		(side _x != civilian) &&  
		(_x distance player < 1000) 
		) then 
			{ 
			tpwcas_filtered_units set [count tpwcas_filtered_units,_x] 
			}; 
		} foreach allunits; 
	sleep 5; 
	}; 
}; 


/*
DEBUG BALL HANDLER
Every 2 sec:
- Displays appropriate coloured debug ball depending on unit's suppression state
- Hides balls for unsuppressed or injured units
- Removes balls from dead units (!)
*/
tpwcas_fnc_ballhandler = 
{ 
while {true} do  
	{ 
		{ 
		_unit = _x; 
		//DISPLAY OR HIDE DEBUG BALLS AS APPROPRIATE     
		_ball1 = _unit getvariable "tpwcas_sup1ball";    
		_ball2 = _unit getvariable "tpwcas_sup2ball";    
		_ball3 = _unit getvariable "tpwcas_sup3ball";   

		switch ( _unit getvariable "tpwcas_supstate" ) do  
			{  
			case 1:   
				{  
				tpwcas_ballstatus = [_ball1,false,_ball2,true,_ball3,true];  
				};  
			case 2:  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,false,_ball3,true];  
				};  
			case 3:  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,false];  
				};  
			default  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,true];  
				};  
			};  

		if (lifestate _unit != "ALIVE") then  
			{ 
			tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,true];  
			};     

		tpwcas_ballstatus call  
		{ 
		(_this select 0) hideobject (_this select 1); 
		(_this select 2) hideobject (_this select 3); 
		(_this select 4) hideobject (_this select 5); 
		}; 

		if ( isDedicated ) then  
			{  
			[-1, {(_this select 0) hideobject (_this select 1);(_this select 2) hideobject (_this select 3);(_this select 4) hideobject (_this select 5);}, tpwcas_ballstatus] call CBA_fnc_globalExecute;  
			};  
		} foreach allunits; 

		//REMOVE DEBUG BALLS FROM DEAD AI   
		{   
		_unit = _x;   
		_ball1 = _unit getvariable "tpwcas_sup1ball";   
		if ( !(_ball1 == objNull) ) then    
			{     
			detach _ball1;    
			deleteVehicle _ball1;   
			_unit setvariable ["tpwcas_sup1ball",nil];           
			};   
		_ball2 = _unit getvariable "tpwcas_sup2ball";   
		if ( !(_ball2 == objNull) ) then    
			{     
			detach _ball2;    
			deleteVehicle _ball2;   
			_unit setvariable ["tpwcas_sup2ball",nil];           
			};   
		_ball3 = _unit getvariable "tpwcas_sup3ball";   
		if ( !(_ball3 == objNull) ) then    
			{     
			detach _ball3;    
			deleteVehicle _ball3;   
			_unit setvariable ["tpwcas_sup3ball",nil];           
			};   
		} foreach allDead;  
	sleep 2;     
	};         
};   


/*
BLUR PLAYER VISION WHEN SUPPRESSED 
- Called from the main loop
- Creates radial blur and gamma darkening to simulate tunnel vision
- Is flagged so only one instance can run at a time
*/

tpwcas_fnc_visuals =    
{  
if (tpwcas_supvisflag == 0) then    
	{  
	tpwcas_supvisflag = 1;       
	_tint = ppEffectCreate ["Colorcorrections", 1552];   
	_tint ppEffectEnable true;   
	_blur = ppEffectCreate ["RadialBlur", 1551];   
	_blur ppEffectEnable true;   
	_ppmodifier = 0.001; 

		{ 
		_ppmod = _ppmodifier * _x; 
		_blur ppEffectAdjust [_ppmod,_ppmod,0.1,0.1];  
		_blur ppEffectCommit 0;  
		_tint ppEffectAdjust[1, 1, (-5 * _ppmod), [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
		_tint ppEffectCommit 0;  
		sleep 0.1;      
		} foreach [1,2,3,4,5]; 

	sleep 5;   

		{ 
		_ppmod = _ppmodifier * _x; 
		_blur ppEffectAdjust [_ppmod,_ppmod,0.1,0.1];  
		_blur ppEffectCommit 0;  
		_tint ppEffectAdjust[1, 1, (-5 * _ppmod), [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
		_tint ppEffectCommit 0;  
		sleep 0.1;      
		} foreach [5,4,3,2,1];  

	ppEffectDestroy _blur;   
	ppEffectDestroy _tint;   
	tpwcas_supvisflag = 0;   
	};   
};   


/*
UPDATE ASR SKILLS
Every 30 sec:
- Checks whether ASR has set the unit's skills
- Updates the "original" unsuppressed skill settings for each unit
*/

tpwcas_fnc_asrskills =    
{    
sleep 3;    
while {true} do     
	{    
		{    
		_unit = _x;    
		_asr = _unit getVariable "asr_ai_sys_aiskill_configured";    
		_skillset = _unit getVariable "tpwcas_skillset";    
		if ((_asr) && !(_skillset))then     
			{    
			_unit setvariable ["tpwcas_originalaccuracy", _unit skill "aimingaccuracy"];      
			_unit setvariable ["tpwcas_originalshake", _unit skill "aimingshake"];     
			_unit setvariable ["tpwcas_originalcourage", _unit skill "courage"];      
			_unit setvariable ["tpwcas_general",_unit skill "general"];     
			_unit setvariable ["tpwcas_skillset", true];    
			};    
		} foreach allunits;    
	sleep 30;    
	};    
};    


/*
BDETECT CALLBACK TO ADD TO EACH UNIT'S LOCAL BULLET COUNT AND SUPPRESSION STATUS 
- called/spawned from bDetect
- increments a unit's enemy and total bullet count
- assigns supression status based on these bullet counts
*/

tpwcas_fnc_localbullets =  
{ 
private [ "_unit","_data","_shooter","_shooterside","_bc","_ebc"]; 

_unit = _this select 0; //suppressed unit 
_data = _this select 3; // 
_shooter = _data select 0; //shooter 
_shooterside = side _shooter; //side of shooter 

_bc = _unit getvariable "tpwcas_bc"; //total bullet count 
_ebc = _unit getvariable "tpwcas_ebc"; //enemy bullet count 
_bc = _bc + 1; 
_unit setvariable ["tpwcas_skillregain", time + 2 + random 3];        
_unit setvariable ["tpwcas_stanceregain", time + 5 + random 5];   
_unit setvariable ["tpwcas_bc", _bc]; 
_unit setvariable ["tpwcas_supstate",1]; 

if (_shooterside getFriend ( side _unit) < 0.6 ) then  
	{ 
	_ebc = _ebc + 1; 
	_unit setvariable ["tpwcas_ebc", _ebc]; 
	if (tpwcas_reveal > 0) then 
		{
		_unit reveal [_shooter, (tpwcas_reveal/((_shooter distance _unit)*.01))]; 
		};
	}; 

if (_ebc > 0) then  
	{ 
	_unit setvariable ["tpwcas_supstate",2]; 
	}; 

if (_ebc > tpwcas_st) then  
	{ 
	_unit setvariable ["tpwcas_supstate",3]; 
	}; 
};  


//////////// 
//RUN IT ALL 
//////////// 

//CALL BDETECT 
call compile preprocessFileLineNumbers "bdetect066.sqf"; 
bdetect_bullet_skip_mags = tpwcas_mags; 
bdetect_bullet_min_distance =  tpwcas_ir;
bdetect_bullet_max_distance = tpwcas_maxdist;
bdetect_debug_enable = false; 
bdetect_callback = "tpwcas_fnc_localbullets"; 
sleep 2;
call bdetect_fnc_init; 
waitUntil { bdetect_init_done}; 

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


//RUN THE REST 
[] spawn tpwcas_fnc_filter; 
[] spawn tpwcas_fnc_main_loop; 
if (tpwcas_debug == 1) then      
   { 
   [] spawn tpwcas_fnc_ballhandler; 
   }; 

@everyone, Please let me know if this is closer/further from what you are looking for and I can tweak it more.

Share this post


Link to post
Share on other sites
My experience with bird watching AI is when they throw smoke grenades or attempting to throw 1. The ai will start looking up the sky and spin, but this was not due to this suppression mod. Maybe you could try to check on it.

I might give disabling this feature in ASR a tilt and see what happens.

Share this post


Link to post
Share on other sites

where is this your talking about in the code so that I can turn it off like you say you do...........................I also made it so the amount of info a unit gains about the shooter varies depending on the distance the shooter is to the unit - But personally I prefer just to turn off the reveal part all together, simply because of the way the ai seems to be able to instantaneously pinpoint a muzzleflash after having the slightest bit of reveal/knowsabout.

Share this post


Link to post
Share on other sites

You must be psychic Coulum. I wrote something similar in my lunch break, but haven't tested it out yet.

Units are suppressed by 2.5% per shot, or 5% if there are nearby friendly casualties. Unsuppressed units regain 5% skill per 1.5 sec.

Skill decrease is moved off to its own function tpwcas_fnc_decskill, and skill increase to tpwcas_fnc_incskill. It's easy to make changes to these functions.

I tried to keep the calculations very simple to keep things fast. Have a look and let me know if this is a useful basis. You're the AI skill magician, I just tried to create a simpler framework. I've generally cleaned the code up too.

/*    
TPWC AI SUPPRESSION    

Authors: TPW && -Coulum- && fabrizio_T   
Additional code: Ollem   
Version: 2.05beta  
Last modified: 20120706 
Requires: CBA, bDetect 
Disclaimer: Feel free to use and modify this code, on the proviso that you post back changes and improvements so that everyone can benefit from them, and acknowledge the original authors in any derivative works. 
*/    

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

//DELAY BEFORE SUPPRESSION FUNCTIONS START. ALLOWS TIME FOR OTHER MODS TO INITIALISE ETC. 
tpwcas_sleep = 2; 

//DEBUGGING. WILL DISPLAY COLOURED BALLS OVER ANY SUPPRESSED UNITS. SET TO 1 FOR DEBUGGING. 
tpwcas_debug = 1; 

//BULLET IGNORE RADIUS (M). BULLETS FROM A SHOOTER CLOSER THAN THIS WILL NOT SUPPRESS.  
tpwcas_ir = 25; 

//SHOT THRESHOLD. MORE SHOTS THAN THIS WILL CAUSE UNIT TO DROP/CRAWL. 
tpwcas_st = 10; 

//STARTUP HINT (TPWCAS & BDETECT). 0 = NO HINT, 1 = HINT. 
tpwcas_hint = 1; 

//PLAYER SUPPRESSION SHAKE. 0 = NO SUPPRESSION, 1 = SUPPRESSION.    
tpwcas_playershake = 1; 

//PLAYER SUPPRESSION VISUALS. 0 = NO SUPPRESSION, 1 = SUPPRESSION.     
tpwcas_playervis = 1; 

//PISTOL AND SMG AMMO TO IGNORE. ADD CUSTOM AMMO (EG SUPPRESSED) OR CHANGE TO TASTE.   
tpwcas_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"   
];  

//AI SKILL SUPPRESSION. 0 = SKILLS WILL NOT BE CHANGED, ONLY STANCE. 1 = SKILLS AND STANCE CHANGED UNDER SUPPRESSION. 
tpwcas_skillsup = 1; 

//MINIMUM SKILL VALUE, NONE OF A UNIT'S SKILLS WILL DROP BELOW THIS UNDER SUPPRESSION. 
tpwcas_minskill = 0.05; 

//REVEAL VALUE WHEN SUPPRESSED. 0 = REVEAL DISABLED. <1 = SUPPRESSED UNIT KNOWS NOTHING ABOUT SHOOTER. 4 = UNIT KNOWS THE SHOOTER'S SIDE, POSITION, SHOE SIZE ETC. 
tpwcas_reveal = 1.25; 

//MAXIMUM BULLET DISTANCE (m). A BULLET FURTHER THAN THIS FROM ITS SHOOTER WILL NOT SUPPRESS. SET LARGER IF YOU PLAN ON DOING A LOT OF SNIPING - BUT MAY IMPACT PERFORMANCE.
tpwcas_maxdist = 600;


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

//INITIAL FILTERED UNIT ARRAY = ALL UNITS 
tpwcas_filtered_units = allunits; 

//WAIT 
sleep tpwcas_sleep;    

//START HINT       
if (tpwcas_hint == 1) then 
{    
0 = [] spawn 
	{   
	hintsilent "TPWCAS 2.05b Active";    
	sleep 3;    
	hintsilent "";
	};    
}; 


//////////// 
//FUNCTIONS 
//////////// 

/*
MAIN LOOP
Every 1.5 sec:
- Assigns initial variables to each unit if they are not yet assigned
- Checks suppression state of unit and applies appropriate stance and skill changes
*/

tpwcas_fnc_main_loop = 
{
private ["_stanceregain","_skillregain","_unit","_ball1","_ball2","_ball3","_x"];	

while {true} do    
	{
	tpwcas_supvisflag = 0;   
		{   
		_unit  = _x;  
		_stanceregain = _unit getvariable ["tpwcas_stanceregain", -1];
		_skillregain = _unit getvariable ["tpwcas_skillregain", -1]; 			

		//SET INITIAL PARAMETERS FOR EACH UNIT   
		if (_stanceregain == -1) then        
			{ 
			//SET ASR AI SKILLS IF ASR AI IS RUNNNING
			if (!isNil "asr_ai_sys_aiskill_fnc_SetUnitSkill") then 
				{
				[_unit] call asr_ai_sys_aiskill_fnc_SetUnitSkill;
				};	

			_unit setvariable ["tpwcas_originalaccuracy", _unit skill "aimingaccuracy"];      
			_unit setvariable ["tpwcas_originalshake",  _unit skill "aimingshake"];     
			_unit setvariable ["tpwcas_originalcourage", _unit skill "courage"];      
			_unit setvariable ["tpwcas_general", _unit skill "general"];     
			_unit setvariable ["tpwcas_stanceregain", time];      
			_unit setvariable ["tpwcas_skillregain", time]; 

			//SET UP COLOURED DEBUGGING BALLS 
			if (tpwcas_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)"]; //green  
				_ball1 attachTo [_unit,[0,0,2]];    
				_unit setvariable ["tpwcas_sup1ball",_ball1];  
				_ball1 hideobject true;   

				_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 ["tpwcas_sup2ball",_ball2];  
				_ball2 hideobject true;   

				_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 ["tpwcas_sup3ball",_ball3];  
				_ball3 hideobject true; 
				};   
			};    

		//IF UNIT STANCE IS UNSUPPRESSED   
		if ( time >= _stanceregain) then        
			{ 
			_unit setunitpos "auto";                     
			_unit setvariable ["tpwcas_supstate",0];  
			_unit setvariable ["tpwcas_bulletcount",0];     
			_unit setvariable ["tpwcas_enemybulletcount",0]; 
			_unit setvariable ["tpwcas_stanceregain", time + 10]; 
			};   

		//IF UNIT SKILLS ARE UNSUPPRESSED   
		if (time >= _skillregain) then       
			{
			[_unit] call tpwcas_fnc_incskill;				
			};  

		//UNIT CHANGES FOR DIFFERENT SUPPRESSION 
		switch ( _unit getvariable "tpwcas_supstate" ) do  
			{  
			case 1: //IF ANY BULLETS NEAR UNIT  
				{  
				//CROUCH IF NOT PRONE 
				if ((_unit call CBA_fnc_getunitanim) select 0 != "prone") then  
					{ 
					_unit setunitpos "middle";     
					}; 
				};  

			case 2: //IF ENEMY BULLETS NEAR UNIT  
				{ 
				//CROUCH IF NOT PRONE 
				if ((_unit call CBA_fnc_getunitanim) select 0 != "prone") then  
					{ 
					_unit setunitpos "middle";     
					}; 
				//SKILL MODIFICATION 
				if (tpwcas_skillsup == 1) then 
					{ 
					[_unit] call tpwcas_fnc_decskill;
					};     
				//PLAYER CAMERA SHAKE  
				if ((isplayer unit) && (tpwcas_playershake == 1)) then    
					{    
					addCamShake [1.5 - (skill player),(random 4)-((_unit getvariable "tpwcas_general")+(_unit getvariable "tpwcas_originalcourage")) , 2.5]   
					};     
				};  

			case 3: //IF UNIT IS SUPPRESSED BY MULTIPLE ENEMY BULLETS   
				{ 
				//GO PRONE 
				_unit setunitpos "down";     
				_unit forcespeed -1;  
				//SKILL MODIFICATION 
				if (tpwcas_skillsup == 1) then 
					{ 
					[_unit] call tpwcas_fnc_decskill;
					};
				//PLAYER CAMERA SHAKE AND FX 
				if (isplayer _unit) then     
					{   
					if (tpwcas_playershake == 1) then  
						{ 
						addCamShake [2 - (skill _unit),(random 6)-((_unit getvariable "tpwcas_general")+(_unit getvariable "tpwcas_originalcourage")) , 5]   
						}; 
					if (tpwcas_playervis == 1) then  
						{     
						[] spawn tpwcas_fnc_visuals;   
						}; 
					};   
				}; 
			};
		} foreach tpwcas_filtered_units; 
	sleep 1.5;      
	};   
};  

/*
UNIT FILTER
Every 5 sec:
- Checks whether unit is combatant, alive and uninjured, within 1000m of player
- Units meeting these criteria are put into a filtered units array which is used by the main loop to minimise overhead
*/

tpwcas_fnc_filter =  
{
private ["_x"];	

while {true} do 
	{ 
	tpwcas_filtered_units = []; 
		{ 
		if  
		(
		(vehicle _x == _x) && 
		(lifestate _x == "ALIVE") &&  
		(side _x != civilian) &&  
		(_x distance player < 1000) 
		) then 
			{ 
			tpwcas_filtered_units set [count tpwcas_filtered_units,_x]; 
			}; 
		} foreach allunits; 
	sleep 5; 
	}; 
}; 


/*
DEBUG BALL HANDLER
Every 2 sec:
- Displays appropriate coloured debug ball depending on unit's suppression state
- Hides balls for unsuppressed or injured units
- Removes balls from dead units (!)
*/
tpwcas_fnc_ballhandler = 
{
private ["_unit","_x","_ball1","_ball2","_ball3"]; 

while {true} do  
	{ 
		{ 
		_unit = _x; 
		//DISPLAY OR HIDE DEBUG BALLS AS APPROPRIATE     
		_ball1 = _unit getvariable "tpwcas_sup1ball";    
		_ball2 = _unit getvariable "tpwcas_sup2ball";    
		_ball3 = _unit getvariable "tpwcas_sup3ball";   

		switch ( _unit getvariable "tpwcas_supstate" ) do  
			{  
			case 1:   
				{  
				tpwcas_ballstatus = [_ball1,false,_ball2,true,_ball3,true];  
				};  
			case 2:  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,false,_ball3,true];  
				};  
			case 3:  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,false];  
				};  
			default  
				{  
				tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,true];  
				};  
			};  

		if (lifestate _unit != "ALIVE") then  
			{ 
			tpwcas_ballstatus = [_ball1,true,_ball2,true,_ball3,true];  
			};     

		tpwcas_ballstatus call  
		{ 
		(_this select 0) hideobject (_this select 1); 
		(_this select 2) hideobject (_this select 3); 
		(_this select 4) hideobject (_this select 5); 
		}; 

		if ( isDedicated ) then  
			{  
			[-1, {(_this select 0) hideobject (_this select 1);(_this select 2) hideobject (_this select 3);(_this select 4) hideobject (_this select 5);}, tpwcas_ballstatus] call CBA_fnc_globalExecute;  
			};  
		} foreach allunits; 

		//REMOVE DEBUG BALLS FROM DEAD AI   
		{   
		_unit = _x;   
		_ball1 = _unit getvariable "tpwcas_sup1ball";   
		if ( !(_ball1 == objNull) ) then    
			{     
			detach _ball1;    
			deleteVehicle _ball1;   
			_unit setvariable ["tpwcas_sup1ball",nil];           
			};   
		_ball2 = _unit getvariable "tpwcas_sup2ball";   
		if ( !(_ball2 == objNull) ) then    
			{     
			detach _ball2;    
			deleteVehicle _ball2;   
			_unit setvariable ["tpwcas_sup2ball",nil];           
			};   
		_ball3 = _unit getvariable "tpwcas_sup3ball";   
		if ( !(_ball3 == objNull) ) then    
			{     
			detach _ball3;    
			deleteVehicle _ball3;   
			_unit setvariable ["tpwcas_sup3ball",nil];           
			};   
		} foreach allDead;  
	sleep 2;     
	};         
};   


/*
BLUR PLAYER VISION WHEN SUPPRESSED 
- Called from the main loop
- Creates radial blur and gamma darkening to simulate tunnel vision
- Is flagged so only one instance can run at a time
*/

tpwcas_fnc_visuals =    
{
private ["_x","_blur","_tint","_ppmod","_ppmodifier"];

if (tpwcas_supvisflag == 0) then    
	{  
	tpwcas_supvisflag = 1;       
	_tint = ppEffectCreate ["Colorcorrections", 1552];   
	_tint ppEffectEnable true;   
	_blur = ppEffectCreate ["RadialBlur", 1551];   
	_blur ppEffectEnable true;   
	_ppmodifier = 0.001; 

		{ 
		_ppmod = _ppmodifier * _x; 
		_blur ppEffectAdjust [_ppmod,_ppmod,0.1,0.1];  
		_blur ppEffectCommit 0;  
		_tint ppEffectAdjust[1, 1, (-5 * _ppmod), [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
		_tint ppEffectCommit 0;  
		sleep 0.1;      
		} foreach [1,2,3,4,5]; 

	sleep 5;   

		{ 
		_ppmod = _ppmodifier * _x; 
		_blur ppEffectAdjust [_ppmod,_ppmod,0.1,0.1];  
		_blur ppEffectCommit 0;  
		_tint ppEffectAdjust[1, 1, (-5 * _ppmod), [0,0,0,0], [0,0,0,1], [0,0,0,1]]; 
		_tint ppEffectCommit 0;  
		sleep 0.1;      
		} foreach [5,4,3,2,1];  

	ppEffectDestroy _blur;   
	ppEffectDestroy _tint;   
	tpwcas_supvisflag = 0;   
	};   
};  

/*
DECREASE UNIT SKILLS
- called from main loop
- aiming shake, aiming accuracy and courage decreased by 2.5% per enemy bullet, or 5% if there are nearby casualties
- these skills won't fall below the value set in twpcas_minskill
*/

tpwcas_fnc_decskill =
{
private [ "_x","_unit","_originalaccuracy","_originalshake","_originalcourage","_shots","_newaccuracy","_newshake","_newcourage","_nearunits","_cas","_dec"];

_unit = _this select 0;

//ANY FRIENDLY CASUALTIES WITHIN 20m OF UNIT
_nearunits = nearestobjects [_unit,["Man"],20];
_cas = 0;
	{
	if ((side _x == side _unit) && (lifestate _x != "ALIVE")) then 
		{
		_cas = _cas + 1;
		};
	} foreach _nearunits;

if (_cas == 0) then 
	{
	_dec = 0.025; //2.5% decrease
	}
	else
	{
	_dec = 0.05; //5% decrease
	};

_originalaccuracy = _unit getvariable "tpwcas_originalaccuracy";        
_originalshake = _unit getvariable "tpwcas_originalshake";      
_originalcourage = _unit getvariable "tpwcas_originalcourage";       
_shots = _unit getvariable "tpwcas_enemybulletcount";     

_newaccuracy = _originalaccuracy - ((_originalaccuracy * _dec) * _shots); 
_newshake = _originalshake - ((_originalshake * _dec) * _shots); 
_newcourage = _originalcourage - ((_originalcourage * _dec) * _shots); 

if (_newaccuracy < tpwcas_minskill) then  
	{ 
	_newaccuracy = tpwcas_minskill; 
	}; 
if (_newshake < tpwcas_minskill) then  
	{ 
	_newshake = tpwcas_minskill; 
	}; 
if (_newcourage < tpwcas_minskill) then  
	{ 
	_newcourage = tpwcas_minskill; 
	};     
_unit setskill ["aimingaccuracy",_newaccuracy];         
_unit setskill ["aimingshake",_newshake];        
_unit setskill ["courage",_newcourage];  
};


/*
INCREASE UNIT SKILLS
- called from main loop
- aiming shake, aiming accuracy and courage increase by 5%
*/

tpwcas_fnc_incskill = 
{
private ["_unit","_originalaccuracy","_originalshake","_originalcourage","_currentaccuracy","_currentshake","_currentcourage","_newaccuracy","_newshake","_newcourage","_inc"];

_unit = _this select 0;
_originalaccuracy = _unit getvariable "tpwcas_originalaccuracy";        
_originalshake = _unit getvariable "tpwcas_originalshake";      
_originalcourage = _unit getvariable "tpwcas_originalcourage"; 

_currentaccuracy = _unit skill "aimingaccuracy"; 
_currentshake = _unit skill "aimingshake"; 
_currentcourage = _unit skill "courage"; 

_inc = 0.05; //5% increment

if (_currentaccuracy < _originalaccuracy) then 
	{
	//INCREMENT SKILLS
	_newaccuracy = _currentaccuracy + (_originalaccuracy * _inc);
	_newshake = _currentshake + (_originalshake * _inc); 
	_newcourage = _currentcourage + (_originalcourage * _inc); 	

	_unit setskill ["aimingaccuracy",_newaccuracy];         
	_unit setskill ["aimingshake",_newshake];        
	_unit setskill ["courage",_newcourage];  
	}
	else
	{
	//RESET SKILLS
	_unit setskill ["aimingaccuracy",_originalaccuracy];         
	_unit setskill ["aimingshake",_originalshake];        
	_unit setskill ["courage",_originalcourage];  
	_unit setvariable ["tpwcas_skillregain", time + 10];
	};
};

/*
BDETECT CALLBACK TO ADD TO EACH UNIT'S LOCAL BULLET COUNT AND SUPPRESSION STATUS 
- called/spawned from bDetect
- increments a unit's enemy and total bullet count
- assigns supression status based on these bullet counts
- minimal calculation, to keep it fast
*/

tpwcas_fnc_localbullets =  
{ 
private [ "_unit","_data","_shooter","_shooterside","_bulletcount","_enemybulletcount"]; 

_unit = _this select 0; //suppressed unit 
_data = _this select 3; //bullet data 
_shooter = _data select 0; //shooter 
_shooterside = side _shooter; //side of shooter 

_bulletcount = _unit getvariable "tpwcas_bulletcount"; //total bullet count 
_enemybulletcount = _unit getvariable "tpwcas_enemybulletcount"; //enemy bullet count 
_bulletcount = _bulletcount + 1; 
_unit setvariable ["tpwcas_skillregain", time + 2 + random 3];        
_unit setvariable ["tpwcas_stanceregain", time + 8 + random 5];   
_unit setvariable ["tpwcas_bulletcount", _bulletcount]; 
_unit setvariable ["tpwcas_supstate",1]; 

if (_shooterside getFriend ( side _unit) < 0.6 ) then  
	{ 
	_enemybulletcount = _enemybulletcount + 1; 
	_unit setvariable ["tpwcas_enemybulletcount", _enemybulletcount]; 
	if (tpwcas_reveal > 0) then 
		{
		_unit reveal [_shooter, tpwcas_reveal]; 
		};
	}; 

if (_enemybulletcount > 0) then  
	{ 
	_unit setvariable ["tpwcas_supstate",2]; 
	}; 

if (_enemybulletcount > tpwcas_st) then  
	{ 
	_unit setvariable ["tpwcas_supstate",3]; 
	}; 
};  

//////////// 
//RUN IT ALL 
//////////// 

//CALL BDETECT 
call compile preprocessFileLineNumbers "\scripts\bdetect067.sqf"; 
bdetect_bullet_skip_mags = tpwcas_mags; 
//bdetect_bullet_min_distance =  tpwcas_ir;
bdetect_bullet_max_distance = tpwcas_maxdist;
//bdetect_debug_enable = false; 
if (tpwcas_hint == 1) then 
{
bdetect_startup_hint = false;
};
bdetect_callback = "tpwcas_fnc_localbullets"; 
sleep 2;
call bdetect_fnc_init; 
waitUntil { bdetect_init_done}; 

//RUN THE REST 

[] spawn tpwcas_fnc_filter; 
[] spawn tpwcas_fnc_main_loop; 
if (tpwcas_debug == 1) then      
   { 
   [] spawn tpwcas_fnc_ballhandler; 
   };  

---------- Post added at 15:26 ---------- Previous post was at 15:25 ----------

where is this your talking about in the code so that I can turn it off like you say you do...........................I also made it so the amount of info a unit gains about the shooter varies depending on the distance the shooter is to the unit - But personally I prefer just to turn off the reveal part all together, simply because of the way the ai seems to be able to instantaneously pinpoint a muzzleflash after having the slightest bit of reveal/knowsabout.

tpwcas_reveal = 0 will fully disable the reveal stuff

Edited by tpw

Share this post


Link to post
Share on other sites

One point I forgot to mention - in yesterday's tests I repeatedly got the impression that AI which were behind cover & suppressed get up rather too early after the rate of suppressing fire drops or stops altogether. They seem very sluggish & make too-easy targets, at least for a human.

This was strongly in contrast to the behaviour of unsuppressed units at similar distances (all tests were with with TPW_AI_LOS running alongside TPWC_AIS & the latest asr_ai) - they are considerably more dangerous than vanilla. Suggests to me that it might be useful to look at implementing some sort of correlation between skill recovery & return to auto-stance, so they don't get up & just crouch or even stand upright waiting to be shot.

I'll run some more tests sometime today with the new scripts.

Share this post


Link to post
Share on other sites
One point I forgot to mention - in yesterday's tests I repeatedly got the impression that AI which were behind cover & suppressed get up rather too early after the rate of suppressing fire drops or stops altogether. They seem very sluggish & make too-easy targets, at least for a human.

This was strongly in contrast to the behaviour of unsuppressed units at similar distances (all tests were with with TPW_AI_LOS running alongside TPWC_AIS & the latest asr_ai) - they are considerably more dangerous than vanilla. Suggests to me that it might be useful to look at implementing some sort of correlation between skill recovery & return to auto-stance, so they don't get up & just crouch or even stand upright waiting to be shot.

I'll run some more tests sometime today with the new scripts.

Well the way things are at present, units regain their stance between 5 - 10 seconds after suppression stops. And they start regaining their skills 2 - 5 seconds after suppression stops. Basically they should not regain stance without at least a good percentage of their skills back.

One thing to consider is that depending on other mods, various FSMs may take over and override crouch/prone. I've seen plenty of heavily suppressed units with yellow/red debug balls standing up, when using ASR_AI.

This is the code in tpwcas_fnc_localbullets:

_unit setvariable ["tpwcas_skillregain", time + 2 + random 3];        
_unit setvariable ["tpwcas_stanceregain", time + 5 + random 5];

It's trivial to extend the amount of time taken until units regain stance. I don't put too much extra calculation into this function because it's called per frame, and we want to keep that smooth.

Edited by tpw

Share this post


Link to post
Share on other sites
Well the way things are at present, units regain their stance between 5 - 10 seconds after suppression stops. And they start regaining their skills 2 - 5 seconds after suppression stops. Basically they should not regain stance without at least a good percentage of their skills back.

One thing to consider is that depending on other mods, various FSMs may take over and override crouch/prone. I've seen plenty of heavily suppressed units with yellow/red debug balls standing up, when using ASR_AI.

This is the code in tpwcas_fnc_localbullets:

_unit setvariable ["tpwcas_skillregain", time + 2 + random 3];        
_unit setvariable ["tpwcas_stanceregain", time + 5 + random 5];

It's trivial to extend the amount of time taken until units regain stance. I don't put too much extra calculation into this function because it's called per frame, and we want to keep that smooth.

Thanks, tpw.

Hmm - if I understand this correctly, a small proportion of units will regain stance at 5 seconds, yet only just be starting to regain skills. Could calculate the distribution easily, but don't have time currently.

Interesting point about asr-ai, I'll retest without it & see if I notice a difference, albeit subjective.

Share this post


Link to post
Share on other sites

Short skirmish mission.. Using Beta 94444 and Ace, as before, just with a few more mods added (random mods)

Still running fine, no air shooting even with smoke grenades deployed.

Few shots of me the player being suppressed and others, no problems, ran great.

1

2

3

4

5

6

7

8

Share this post


Link to post
Share on other sites
Short skirmish mission.. Using Beta 94444 and Ace, as before, just with a few more mods added (random mods)

Still running fine, no air shooting even with smoke grenades deployed.

Few shots of me the player being suppressed and others, no problems, ran great.

1

2

3

4

5

6

7

8

Great to hear that it's finally becoming useful ChrisB. Thanks for the pix.

---------- Post added at 21:30 ---------- Previous post was at 20:57 ----------

If anyone is game, here is a build of 2.05.

Changelog:

  • Code cleanup and optimisation.
  • Private variable declarations for each function.
  • Simplified skills modification, will not head to 0 as quickly.
  • Units are more easily suppressed if there are friendly casualties within 20m.
  • Simplified ASR AI skill recognition.
  • bDetect startup hint will not be shown if TPWCAS startup hint is not shown.
  • bDetect 0.67 (modified to allow units to suppress when shooting uphill).

I consider this more of a test for a new skill modification framework which Coulum can wave his magic wand over. On the other hand, I tested it a lot this evening and I have yet to see any AI dodginess as reported in earlier versions.

TPWCAS 2.05b: http://filesonly.com/download.php?file=198TPWC_AI_SUPPRESS_205.zip

Share this post


Link to post
Share on other sites

Been having fun with 2.05 script, 0.67 bdetect. No problems to report.

Share this post


Link to post
Share on other sites
Been having fun with 2.05 script, 0.67 bdetect. No problems to report.

Good.

---------- Post added at 12:18 ---------- Previous post was at 12:13 ----------

I am thinking about porting this mod into .fsm.

It should be feasible. Maybe in the next weeks i will do a try, now vacancy is over.

Glad to see that TPWCAS and bDetect are both looking stable.

Share this post


Link to post
Share on other sites
I am thinking about porting this mod into .fsm
Can't enjoy PerFrameHandler if you go FSM (at least I don't see how, as the logic running in PerFrame, is the only logic that seems to make sense as FSM).

FSM is also scheduled and the FSM scheduler is depending on AI performance, so it exhibits similar issues (e.g timing) as spawned SQF code.

Share this post


Link to post
Share on other sites
Can't enjoy PerFrameHandler if you go FSM (at least I don't see how, as the logic running in PerFrame, is the only logic that seems to make sense as FSM).

FSM is also scheduled and the FSM scheduler is depending on AI performance, so it exhibits similar issues (e.g timing) as spawned SQF code.

Sorry, what i said wasn't clear.

I was thinking about porting suppression routine on .fsm, i think it would suit well.

Obviously bullet detection should be still handled by bDetect as it is.

Logic would be:

bDetect detection event -> spawn of per-unit .fsm handling suppression, if not already existing -> queuing / injecting into .fsm of any further events till some sort of timeout ( so we haven't to deal with spawning / terminating .fsm too frequently ).

Share this post


Link to post
Share on other sites

Aww, got me confused there with the two threads, roger :)

Share this post


Link to post
Share on other sites

This is incredible; a layer of realism/immersion I've been waiting on for years!

Big thanks for all the hard work.

Share this post


Link to post
Share on other sites
If anyone is game, here is a build of 2.05.

Tested this just now with same 3 missions as before, 2-4 times each. CBA 1.006pre, TPW_LOS, ASR_ai 1.15.1_test5, same COSLX files.

First time I ran "Trial by Fire" my MG kept having bouts of refusing to fire. When I got killed because if that I switched to Flashpoint v114 Podagrsk - played 5 times various weapons including the Mod 0 MG, nary a glitch. "Pinned Down" was no problem either. Went back to Trial by Fire & that went smoothly, so I guess it may have been some random glitch. Will test it again tomorrow, this time also, if I have time, logging average FPS with/without the TPWC_AIS & LOS, then with just one, then the other, then with both.

No birdwatching, no strange transitions, AOK apart from the first run of Trial by Fire.

Looking good, mate :)

Share this post


Link to post
Share on other sites
Tested this just now with same 3 missions as before, 2-4 times each. CBA 1.006pre, TPW_LOS, ASR_ai 1.15.1_test5, same COSLX files.

First time I ran "Trial by Fire" my MG kept having bouts of refusing to fire. When I got killed because if that I switched to Flashpoint v114 Podagrsk - played 5 times various weapons including the Mod 0 MG, nary a glitch. "Pinned Down" was no problem either. Went back to Trial by Fire & that went smoothly, so I guess it may have been some random glitch. Will test it again tomorrow, this time also, if I have time, logging average FPS with/without the TPWC_AIS & LOS, then with just one, then the other, then with both.

No birdwatching, no strange transitions, AOK apart from the first run of Trial by Fire.

Looking good, mate :)

Awesome, very encouraging news. Thanks enormously for all the stress testing of the mod, I'm too busy coding to play.

Share this post


Link to post
Share on other sites

No birdwatching, no strange transitions, AOK apart from the first run of Trial by Fire.

Yep, I can confirm that birdwatching is gone and overall peformance is better. Great work tpw and fabrizio! :rthumb:

Share this post


Link to post
Share on other sites

@tpw:

had finally the time to take a quick look to latest TPWCAS code, looking good, maybe the debug balls code may be streamlined.

A minor hint:

In tpwcas_fnc_decskill() you have blocks such as:

_newaccuracy = _originalaccuracy - ((_originalaccuracy * _dec) * _shots);
...
if (_newaccuracy < tpwcas_minskill) then  
{ 
_newaccuracy = tpwcas_minskill; 
};

you can compact them into something like:

_newaccuracy = ( _originalaccuracy - ( ( _originalaccuracy * _dec ) * _shots ) ) max tpwcas_minskill; 

"max" picks the maximum of 2 values: e.g. "1 max 2 = 2", good to set lower bounds, while "min" is the complimentary : e.g. "1 min 2 = 1".

---

Finally, a quick'n'dirty candidate function to do debugging seperately, so that workflow may be kept almost debug free.

It handles both balloons and some markers to track units and their side on map.

Only 1 balloon per-unit created.

I hope hot having done mistakes here, please double check.

Function spawn a own internal loop, running each 1 seconds.

It uses _x getvariable "tpwcas_supstate" as base for balloon color.

Usage: call tpwcas_fnc_debug_visual;

NOTE: Round markers on map and BLACK balloons mean unit is fleeing.

Hope it's useful.

// Some visual debug
tpwcas_fnc_debug_visual = 
{
private ["_handle"];

_handle = [] spawn 
{
	private ["_ball", "_marker", "_level", "_x", "_nul", "_color"];

	while { true } do
	{
		{
			if( isNil { _x getVariable "tpwcas_debug_ball" } ) then
			{
				_ball = "Sign_sphere25cm_EP1" createvehicle getposatl _x;  
				_ball setObjectTexture [0,"#(argb,8,8,3)color(0.99,0.99,0.99,0.7,ca)"];  // white
				_ball attachTo [_x,[0,0,2]];   
				_ball hideobject true;  

				if( (side _x) getFriend WEST < 0.6 ) then { _color = "ColorRed"; } else { _color = "ColorBlue"; };

				_marker = createMarker[ format["tpwcas_markers_%1", _x], position _x];
				_marker setMarkerShape "ICON";
				_marker setMarkerType "mil_triangle";
				_marker setMarkerColor _color;

				_x setVariable ["tpwcas_debug_ball", _ball ];
				_x setVariable ["tpwcas_debug_marker", _marker ];
			}
			else
			{
				_ball = _x getVariable "tpwcas_debug_ball";
				_marker = _x getVariable "tpwcas_debug_marker";
			};

			_marker setMarkerPos (position _x);

			if( fleeing _x) then 
			{
				_marker setMarkerType "mil_dot";
			}
			else
			{
				_marker setMarkerType "mil_triangle";
				_marker setMarkerDir (getDir _x);
			};

			if( !( isNull _x ) && alive _x) then // better to double check for unit being alive ...
			{
				_level = _x  getvariable ["tpwcas_supstate", 0];

				switch ( true ) do
				{
					case ( fleeing _x ): {  
						_ball hideobject false;  
						_ball setObjectTexture [0,"#(argb,8,8,3)color(0.0,0.0,0.0,0.9,ca)"];  // black
					};

					case ( _level == 0 ): {  
						_ball hideobject true;  
					};

					case ( _level == 1 ): {  
						_ball hideobject false; 
						_ball setObjectTexture [0,"#(argb,8,8,3)color(0.1,0.9,0.1,0.7,ca)"];  // green
					};

					case ( _level == 2): {  
						_ball hideobject false; 
						_ball setObjectTexture [0,"#(argb,8,8,3)color(0.9,0.9,0.1,0.7,ca)"]; //yellow
					};

					case ( _level == 3 ): {  
						_ball hideobject false; 
						_ball setObjectTexture [0,"#(argb,8,8,3)color(0.9,0.1,0.1,0.7,ca)"]; //red  
					};
				};
			};

		} foreach allUnits;

		{
			if( ! ( isNil { _x getVariable "tpwcas_debug_ball" } ) ) then
			{
				deleteVehicle ( _x getVariable "tpwcas_debug_ball" );
				deleteMarker( _x getVariable "tpwcas_debug_marker" );
			};

		} foreach allDead;

		sleep 1;
	};
};

_handle
};

Edited by fabrizio_T

Share this post


Link to post
Share on other sites
@tpw:

had finally the time to take a quick look to latest TPWCAS code, looking good, maybe the debug balls code may be streamlined.

A minor hint:

In tpwcas_fnc_decskill() you have blocks such as:

_newaccuracy = _originalaccuracy - ((_originalaccuracy * _dec) * _shots);
...
if (_newaccuracy < tpwcas_minskill) then  
{ 
_newaccuracy = tpwcas_minskill; 
};

you can compact them into something like:

_newaccuracy = ( _originalaccuracy - ( ( _originalaccuracy * _dec ) * _shots ) ) max tpwcas_minskill; 

"max" picks the maximum of 2 values: e.g. "1 max 2 = 2", good to set lower bounds, while "min" is the complimentary : e.g. "1 min 2 = 1".

Nice one! Putting that in now!

Share this post


Link to post
Share on other sites
Awesome, very encouraging news. Thanks enormously for all the stress testing of the mod, I'm too busy coding to play.

NP, it's a genuine pleasure; especially as the development long ago went out of reach as far as my coding knowledge goes.

With the LOS stuff & Robalo's work on asr_ai, AI combat in this game is changing beyond recognition :yay:

Share this post


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

×