Jump to content
Sign in to follow this  
tpw

TPWC AI suppression system

Recommended Posts

May i ask why you think that 0.1 is rather low?

My experimental data is saying that an unit that is given "aimingAccuracy" = 0.1 is usually hitting a target at 200m and from standing stance with a single M4 burst. In average it needs 3 -5 bullets.

When you ideally face such a lowly skilled threat remember you have in average 0.3-0.5 seconds to react before being killed. Good luck ;)

Well from my experience with TPWCAS it looks to me like suppressed AI units are barely able to hit anything. And I mean - my fireteam can be 4 people and they can have a squad of 9 and if they are suppressed I can just sit there and take my time to place aimed shots at them because they start missing hard (I also play with AI skill at 0.9 in game settings - just in case).

I think increasing a lower limit will be a good idea for more testing.

Share this post


Link to post
Share on other sites

Something I like to report, might be fixed, not sure if its a bug or what, just letting you guys know, and this was using the 2.00 version

I noticed enemy AI as I was blufor when being shot at, sometimes would stand there and aim at the ball above them, at least I think

thats what they were doing, just happen to notice this but haven't tested or played enough, figured I'd say something.

Share this post


Link to post
Share on other sites
Well from my experience with TPWCAS it looks to me like suppressed AI units are barely able to hit anything. And I mean - my fireteam can be 4 people and they can have a squad of 9 and if they are suppressed I can just sit there and take my time to place aimed shots at them because they start missing hard (I also play with AI skill at 0.9 in game settings - just in case).

I think increasing a lower limit will be a good idea for more testing.

I've included the lower limit as a user configurable variable for the 2.02 release, which will be up reasonably soon.

---------- Post added at 22:29 ---------- Previous post was at 22:25 ----------

Something I like to report, might be fixed, not sure if its a bug or what, just letting you guys know, and this was using the 2.00 version

I noticed enemy AI as I was blufor when being shot at, sometimes would stand there and aim at the ball above them, at least I think

thats what they were doing, just happen to notice this but haven't tested or played enough, figured I'd say something.

Yeah I thought I saw it occasionally too. Ideally I'd use something other than attached balls. I thought about using worldtoscreen to print each units suppression status onto the screen, but quickly put it in the too bloody hard basket. Ideally, once most of us are fully happy with the suppression, the debug won't be needed so much.

Share this post


Link to post
Share on other sites
I've included the lower limit as a user configurable variable for the 2.02 release.

Best way around, so people may test and share some feedback.

Here is the updated bdetect.sqf, should cope well with 2.02.

Many additions and some rollback.

bDetect v0.64

/*
Basic bullet detection framework
Version: 0.64
Date: 03/07/2012
Author: Fabrizio_T 
Additional code: TPW 
File Name: bdetect.sqf

CHANGELOG:

-------------
Version: 0.64
-------------

* Incorporated suggestions from tpw: http://forums.bistudio.com/showthread.php?136304-TPWC-AI-suppression-system&p=2182742&viewfull=1#post2182742
* Minor optimization / fixes
* Introduced variable "bdetect_callback_mode": (String, Default "spawn") Allowed values: "call" or "spawn". It controls synchronous vs.asynchronous bdetect_callback() execution.

-------------
Version: 0.63
-------------

* Temporarily reverted from "diag_tickTime" to "time" for issues to be looked in

-------------
Version: 0.62
-------------

* Fixed bullet position handling

-------------
Version: 0.61
-------------

* Fixed problem with units eventually detecting own shots

------------
Version: 0.6
------------

* Incorporated v0.51 changes/fixes by tpw.
* Function bdetect_fnc_callback() slightly changed. See bottom of this file for example.
* Function bdetect_fnc_init() waits for 5 seconds to pass by after mission start, before activating the framework.
* Introduced function bdetect_fnc_eh_fired_add(): suitable to force -immediate- assignment of a fired EH to any unit. Syntax: [unit] call bdetect_fnc_eh_fired_add();
* Fixed function bdetect_fnc_benchmark(): internally using code spawning, not to block code execution after function call.
* Tweaked internals so that "diag_tickTime" is used instead of "time" (Thanks Ollem).
* Introduced function bdetect_fnc_eh_loop(): iteratively checks ( each "bdetect_eh_assign_cycle_wait" seconds ) for newly spawned units to assign them a 'Fired' event Handler.
* Renamed "bdetect_bullet_min_distance" to "bdetect_bullet_max_proximity"
* Introduced variable "bdetect_init_done": (Boolean). It evaulates true when framework is loaded. Usage: "waitUntil { bdetect_init_done};"
* Introduced variable "bdetect_eh_assign_cycle_wait": (seconds, Default 10). Wait duration foreach cyclic execution of bdetect_fnc_eh_loop()
* Introduced variable "bdetect_bullet_min_distance": (meters, Default 25). Bullets not having travelled this distance are ignored
* Introduced variable "bdetect_bullet_initial_min_speed": (meters / second, Default 360). Bullets initially slower than this are ignored (good for subsonic bullets skipping). 
* Introduced variable "bdetect_debug_chat": (Boolean, Default false) Show debug messages also in globalChat.
* Changed Variable "bdetect_debug_min_level" to "bdetect_debug_levels". (Array). Default [0,1,2,3,4,5,6,7,8,9]. 0-9 are reserved levels.
* Much more

------------
Version: 0.5
------------

* Framework is named "bdetect" and contained into a single file: bdetect.sqf 
* Renamed variable "bdetect_debug" to "bdetect_debug_enable"
* Introduced variables "bdetect_name" and "bdetect_version": name and version of the framework;
* Introduced function bdetect_fnc_init() to handle the framework bootstrap.
* Introduced variable "bdetect_callback" (string). It defines the name of a custom callback function to be called on a unit when it detects a close bullet (Default: "bdetect_fnc_callback").
* Functions and variable names polishing. All vars named bdetect_<varname>. All functions named bdetect_fnc_<funcname>.
* Added some missing private vars.

------------
Version: 0.4
------------

* Introduced variables "bdetect_enable" (boolean), "bdetect_debug_levels" (Number), "bdetect_skip_mags" (array).
* Variable "bdetect_enable" act as a toggle to enable / disable framework.
* Variable "bdetect_debug_levels" allows for selective display / logging of debug messages based on level.
* Introduced function bdetect_fnc_benchmark() to display performance stats.
* Added "bdetect_skip_mags", which is a blacklist of bullet types which should not trigger detection

------------
Version: 0.3
------------

* Introduced variables "bdetect_bullet_delay" (seconds) , "bdetect_bullet_max_height" (meters).
* Variable "bdetect_bullet_delay" (seconds) changes dinamycally between "bdetect_bullet_min_delay" (lower bound) and 1 (upper bound), depending on actual FPS vs "bdetect_fps_min".
* Variable "bdetect_bullet_max_height" (meters) is the maximum height for bullets, over ground. Bullets higher than this value (Default: 10) and with up vector > 0 are skipped from detection, since they are too high and diverge from ground.
* Some Code optimization.

------------
Version: 0.2
------------

* Position of bullet as SetPosASL.
* Introduced variables "bdetect_fps_min" (fps), "bdetect_bullet_max_distance" (meters), "bdetect_bullet_max_lifespan" (seconds).
* Introduced function bdetect_fnc_diag_min_fps(): in case FPS go under "bdetect_fps_min" value (Default: 25) bdetect_bullet_delay is gradually raised. 
* Function bdetect_fnc_bullet_remove() edited and renamed to bdetect_fnc_bullet_tag_remove(), since actual removal is done elsewhere.
* Bullets are removed from bdetect_fired_bullets if distance is over "bdetect_bullet_max_distance" meters or lifespan is over "bdetect_bullet_max_lifespan" seconds.

------------
Version: 0.1
------------

* First draft
*/

//BEGINNING OF FRAMEWORK CODE

// -----------------------------
// Constants
// -----------------------------

bdetect_name = "bDetect - Bullet Detection Framework"; 
bdetect_short_name = "bDetect"; 
bdetect_version = "0.64";
bdetect_init_done= false;

// -----------------------------
// Functions
// -----------------------------

bdetect_fnc_init = 
{
private [ "_msg", "_x" ];

sleep 5;

// You may override these variables
if(isNil "bdetect_enable") then { bdetect_enable = true; }; // (Boolean, Default true) Toggle to Enable / Disable bdetect altogether.
if(isNil "bdetect_debug_enable") then { bdetect_debug_enable = false; }; // (Boolean, Default false) Toggle to Enable / Disable debug messages.
if(isNil "bdetect_debug_chat") then { bdetect_debug_chat = false; }; // (Boolean, Default false) Show debug messages also in globalChat.
if(isNil "bdetect_debug_levels") then { bdetect_debug_levels = [0,1,2,3,4,5,6,7,8,9]; }; // (Array, Default [0,1,2,3,4,5,6,7,8,9]) Filter debug messages by included levels. 
if(isNil "bdetect_callback") then { bdetect_callback = "bdetect_fnc_callback"; }; // (String, Default "bdetect_fnc_callback") Name for your own callback function
if(isNil "bdetect_callback_mode") then { bdetect_callback_mode = "spawn"; }; // (String, Default "spawn") Allowed values: "call" or "spawn"
if(isNil "bdetect_fps_min") then { bdetect_fps_min = 25; }; // (Number, Default 25) The minimum FPS you wish to keep
if(isNil "bdetect_fps_calc_each_x_frames") then { bdetect_fps_calc_each_x_frames = 16; }; // (Number, Default 16) FPS check is done each "bdetect_fps_min" frames. 1 means each frame.
if(isNil "bdetect_eh_assign_cycle_wait") then { bdetect_eh_assign_cycle_wait = 10; }; // (Seconds, Default 10). Wait duration foreach cyclic execution of bdetect_fnc_eh_loop()
if(isNil "bdetect_bullet_min_delay") then { bdetect_bullet_min_delay = 0.1; }; // (Seconds, Default 0.1) Minimum time between 2 consecutive shots fired by an unit for the last bullet to be tracked. Very low values may cause lag.
if(isNil "bdetect_bullet_max_delay") then { bdetect_bullet_max_delay = 2; }; // (Seconds, Default 2)
if(isNil "bdetect_bullet_initial_min_speed") then { bdetect_bullet_initial_min_speed = 360; }; // (Meters/Second, Default 360) Bullets slower than this are ignored.
if(isNil "bdetect_bullet_max_proximity") then { bdetect_bullet_max_proximity = 10; }; // (Meters, Default 10) Maximum proximity to unit for triggering detection
if(isNil "bdetect_bullet_min_distance") then { bdetect_bullet_min_distance = 25; }; // (Meters, Default 25) Bullets having travelled less than this distance are ignored
if(isNil "bdetect_bullet_max_distance") then { bdetect_bullet_max_distance = 400; }; // (Meters, Default 400) Bullets past this distance are ignored
if(isNil "bdetect_bullet_max_lifespan") then { bdetect_bullet_max_lifespan = 0.5; }; // (Seconds, Default 0.5) Bullets living more than this are ignored
if(isNil "bdetect_bullet_max_height") then { bdetect_bullet_max_height = 6; }; // (Meters, Default 6) Bullets higher than this -and- diverging from ground are ignored

if(isNil "bdetect_skip_mags") then { // (Array) Skip these bullet types altogether
	bdetect_skip_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"  
	];  
};

// Do not edit the variables below.
if(isNil "bdetect_fired_bullets") then { bdetect_fired_bullets = []; };
if(isNil "bdetect_fps") then { bdetect_fps = bdetect_fps_min; };
if(isNil "bdetect_bullet_delay") then { bdetect_bullet_delay = bdetect_bullet_min_delay; };
if(isNil "bdetect_frame_tstamp") then { bdetect_frame_tstamp = 0; };
if(isNil "bdetect_frame_min_duration") then { bdetect_frame_min_duration = (bdetect_bullet_max_proximity * 2 * .66 / 900) max .01; };

// bullet speed converted to kmh
bdetect_bullet_initial_min_speed = bdetect_bullet_initial_min_speed * 3.6;

// compile callback name into function
bdetect_callback_compiled = call compile format["%1", bdetect_callback];

_msg = format["Starting %1 v%2.", bdetect_name, bdetect_version];
[ _msg, 0 ] call bdetect_fnc_debug;

bdetect_spawned_loop_handler = [] spawn bdetect_fnc_eh_loop;   

[bdetect_fnc_detect,0] call cba_fnc_addPerFrameHandler;   

bdetect_init_done= true;

hint format["%1 v%2 started.", bdetect_name, bdetect_version];
};

// Keep searching units for newly spawned ones and assign fired EH to them
bdetect_fnc_eh_loop =
{
private [ "_x", "_msg"];

while { true } do
{
	{ 
		[_x] call bdetect_fnc_eh_fired_add;

	} foreach allUnits;

	sleep bdetect_eh_assign_cycle_wait;
};
};

// Assign fired EH to a single unit
bdetect_fnc_eh_fired_add =
{
private ["_unit", "_msg"];

_unit = _this select 0;

if( isNil { _unit getVariable "bdetect_fired_eh" } ) then
{
	_unit setVariable ["bdetect_fired_eh", true]; 
	_unit addEventHandler ["Fired", bdetect_fnc_fired];

	if (  ( assignedVehicleRole _unit) select 0 == "Turret" && isNil { (vehicle _x) getVariable "bdetect_fired_eh" } ) then   
	{		
		(vehicle _x) setVariable ["bdetect_fired_eh", true]; 
		(vehicle _x) addeventhandler ["Fired", bdetect_fnc_fired];    
	}; 

	_msg = format["[%1] was assigned 'Fired' EH", _unit];
	[ _msg, 3 ] call bdetect_fnc_debug;
}
else
{
	_msg = format["[%1] already had an assigned 'Fired' EH", _unit];
	[ _msg, 3 ] call bdetect_fnc_debug;
};
};

// Fired EH
bdetect_fnc_fired =
{
	private ["_unit", "_muzzle", "_magazine", "_bullet", "_speed", "_msg", "_time", "_dt"];

if( bdetect_enable ) then
{
	_unit = _this select 0;
	_muzzle = _this select 2;
	_magazine = _this select 5;
	_bullet = _this select 6;
	_speed = speed _bullet;
	_time = time; //diag_tickTime

	_dt = _time - ( _unit getVariable ["bdetect_fired_time", 0] );

	if( _dt > bdetect_bullet_delay 
		&& !( _magazine in bdetect_skip_mags ) 
		&& _speed > bdetect_bullet_initial_min_speed 
	) then
	{
		_unit setVariable ["bdetect_fired_time", _time]; 

		// Append info to bullets array
		[ _bullet, _unit, _time ] call bdetect_fnc_bullet_add;

		_msg = format["[%1] Fired bullet: speed=%2, type=%3, Delay=%4", _unit, _speed, typeOf _bullet, _dt ];
		[ _msg, 2 ] call bdetect_fnc_debug;
	}
	else
	{
		_msg = format["[%1] Skipped bullet: speed=%2, type=%3, Delay=%4 [%5 - %6]", _unit, _speed, typeOf _bullet, _dt,  _time , ( _unit getVariable ["bdetect_fired_time", 0] )];
		[ _msg, 2 ] call bdetect_fnc_debug;
	};
};
};

// Time-critical detection function, to be executed per-frame
bdetect_fnc_detect =         
{        
private ["_n", "_tot", "_bullet", "_data", "_side", "_pos", "_time", "_shooter", "_blacklist", "_update_blacklist", "_dist", "_units", "_x", "_data", "_func", "_t", "_k", "_bpos", "_nul"];

_t = time; //diag_tickTime

if( bdetect_enable && (_t - bdetect_frame_tstamp) >= bdetect_frame_min_duration) then
{
	_msg = format["Frame duration=%1, min duration:%2", (_t - bdetect_frame_tstamp), bdetect_frame_min_duration ];
	[ _msg, 4 ] call bdetect_fnc_debug;

	_tot = count bdetect_fired_bullets;

	bdetect_frame_tstamp = _t;

	if ( _tot > 0 ) then 
	{ 
		if( diag_frameno % bdetect_fps_calc_each_x_frames == 0) then
		{
			call bdetect_fnc_diag_min_fps;
		};

		for "_n" from 0 to _tot - 1 step 2 do 
		{
			_bullet = bdetect_fired_bullets select _n;
			_data = bdetect_fired_bullets select (_n + 1);
			_shooter = _data select 0;
			_pos = _data select 1;
			_time = _data select 2;
			_blacklist = _data select 3;
			_update_blacklist = false;

			if( !( isnull _bullet ) ) then
			{
				_bpos = getPosATL _bullet;
				_dist = _bpos distance _pos;			
				//_msg = format["Following bullet %1. Time: %2. Distance: %3 Speed: %4. Position: %5", _bullet, _t - _time, _dist, (speed _bullet / 3.6), getPosASL _bullet];
				//[ _msg, 2 ] call bdetect_fnc_debug;
			};

			if( isNull _bullet 
				|| !(alive _bullet) 
				|| _t - _time > bdetect_bullet_max_lifespan 
				|| _dist > bdetect_bullet_max_distance	
				|| speed _bullet < bdetect_bullet_initial_min_speed // funny rebounds handling
				|| ( ( _bpos select 2) > bdetect_bullet_max_height && ( ( vectordir _bullet ) select 2 ) > 0 ) 
				) then
			{
				[_bullet] call bdetect_fnc_bullet_tag_remove;
			}
			else
			{
				if( _dist > bdetect_bullet_min_distance	) then
				{
					_units = _bpos nearEntities [ ["MAN"] , bdetect_bullet_max_proximity];

					{
						if( alive _x && !(_x in _blacklist) && _x != _shooter ) then
						{
							if( vehicle _x == _x && lifestate _x == "ALIVE") then
							{
								_blacklist = _blacklist + [_x];
								_update_blacklist = true;

								if(bdetect_callback_mode == "spawn") then {
									_nul = [_x, _bullet, _x distance _bpos, _data] spawn bdetect_callback_compiled;
								} else {
									[_x, _bullet, _x distance _bpos, _data] call bdetect_callback_compiled;
								};

								_msg = format["[%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _x, _bullet, _shooter, _x distance _bpos, _data];
								[ _msg, 9 ] call bdetect_fnc_debug;
							};
						}
						else
						{
							_msg = format["[%1] Blacklisted, bullet %2 ignored", _x, _bullet];
							[ _msg, 5 ] call bdetect_fnc_debug;
						};

					} foreach _units;

					if(_update_blacklist) then
					{
						// Update blacklist
						bdetect_fired_bullets set[ _n + 1, [_shooter, _pos, _time, _blacklist] ];
					};

					//_msg = format["bdetect_fired_bullets = %1", bdetect_fired_bullets];
					//[ _msg, 2 ] call bdetect_fnc_debug;
				};
			};
		};

		// remove dead / expired bullets
		bdetect_fired_bullets = bdetect_fired_bullets - [-1];

		//_msg = format["%1 bullets in array", count ( bdetect_fired_bullets ) / 2];
		//[ _msg, 2 ] call bdetect_fnc_debug;
	};
};
};

bdetect_fnc_diag_min_fps =
{
private ["_fps", "_msg"];

_fps = diag_fps;

_msg = format["FPS=%1, Min.FPS=%2, Prev. FPS=%3, bdetect_bullet_delay=%4)", _fps, bdetect_fps_min, bdetect_fps, bdetect_bullet_delay ];
[ _msg, 1 ] call bdetect_fnc_debug;

if( _fps < bdetect_fps_min * 1.15) then
{
	if( bdetect_bullet_delay + .15 < bdetect_bullet_max_delay && _fps < bdetect_fps_min ) then
	{
		bdetect_bullet_delay = bdetect_bullet_delay + .15;

		_msg = format["FPS down to %1. Augmenting bdetect_bullet_delay to %2", _fps, bdetect_bullet_delay];
		[ _msg, 1 ] call bdetect_fnc_debug;
	};
}
else
{
	if( ( bdetect_bullet_delay - .15 ) >= bdetect_bullet_min_delay ) then
	{
		bdetect_bullet_delay = bdetect_bullet_delay - .15;

		_msg = format["FPS up to %1. Reducing bdetect_bullet_delay to %2", _fps, bdetect_bullet_delay];
		[ _msg, 1 ] call bdetect_fnc_debug;
	};
};

bdetect_fps = _fps;
};

// Function to add a bullet to bdetect_fired_bullets 
bdetect_fnc_bullet_add = 
{
private ["_bullet", "_shooter", "_pos", "_time",  "_msg", "_n"];

_bullet = _this select 0; // bullet object
_shooter = _this select 1;	// shooter
_pos = getPosATL _bullet;	// bullet start position
_time = _this select 2;	// bullet shoot time
_n = count bdetect_fired_bullets;

bdetect_fired_bullets set [ _n,  _bullet  ];
bdetect_fired_bullets set [ _n + 1, [ _shooter, _pos, _time, [] ] ];

_msg = format["bullet %1 added", _bullet, _n / 2];
[ _msg, 2] call bdetect_fnc_debug;
};

// Function to remove a bullet from bdetect_fired_bullets 
bdetect_fnc_bullet_tag_remove = 
{
private ["_bullet", "_n", "_msg" ];

_bullet = _this select 0;
_n = bdetect_fired_bullets find _bullet;

if( _n != -1 ) then
{
	bdetect_fired_bullets set[ _n, -1 ];
	bdetect_fired_bullets set[ _n + 1, -1 ];

	_msg = format["null/expired bullet removed"];
	[ _msg, 2 ] call bdetect_fnc_debug;
};
};

// Callback function to be executed from within bdetect_fnc_detect
bdetect_fnc_callback = 
{
private [ "_unit", "_bullet", "_proximity", "_data", "_shooter", "_pos", "_time", "_msg" ];

_unit = _this select 0;		// unit being under fire
_bullet = _this select 1;	// bullet object
_proximity = _this select 2;	// distance between _bullet and _unit
_data = _this select 3;		// Array containing more data

_shooter = _data select 0; // shooter
_pos = _data select 1;	// starting position of bullet
_time = _data select 2; // starting time of bullet

_msg = format["[%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _unit, _bullet, _shooter, _proximity, _data];
[ _msg, 9 ] call bdetect_fnc_debug;
};

// function to display and log stuff (into .rpt file) level zero is intended only for builtin messages
bdetect_fnc_debug =
{
private [ "_msg", "_level"];

/*
DEBUG LEVELS: 
From 0-9 are reserved.

0 = unclassified messages
1 = FPS related messages
2 = "bdetect_fired_bullets" related messages
3 = EH related messages
4 = Frame related messages
5 = Unit blacklist messages
...
9 = Unit detection related messages
*/

_level = _this select 1;

if( bdetect_debug_enable && _level in bdetect_debug_levels) then
{
	_msg = _this select 0;

	diag_log format["%1 [%2 v%3] Frame:%4 L%5: %6", time, bdetect_short_name, bdetect_version, diag_frameno, _level, _msg ];

	if( bdetect_debug_chat ) then 
	{
		player globalchat format["%1 - %2", time, _msg ];
	};
};
};

bdetect_fnc_benchmark = 
{
private ["_cnt"];

if(isNil "bdetect_stats_max_bullets") then { bdetect_stats_max_bullets = 0;};
if(isNil "bdetect_stats_min_fps") then { bdetect_stats_min_fps = 999;};
if(isNil "bdetect_fired_bullets") then { bdetect_fired_bullets = [];};

_nul = [] spawn 
{
	sleep 5;

	while { true } do
	{
		_cnt = count ( bdetect_fired_bullets ) / 2;

		if( _cnt > bdetect_stats_max_bullets ) then { bdetect_stats_max_bullets = _cnt; };
		if( diag_fps < bdetect_stats_min_fps ) then { bdetect_stats_min_fps = diag_fps };
		hintsilent format["TIME: %1\nFPS: %2 (min: %3)\nBULLETS: %4 (max: %5)\nS.DELAY: %6 (Min FPS: %7)", time, diag_fps, bdetect_stats_min_fps, _cnt, bdetect_stats_max_bullets, bdetect_bullet_delay, bdetect_fps_min];

		sleep .1;
	};
};
};

// END OF FRAMEWORK CODE

// -----------------------------------------------------------
// Example for running the script
// -----------------------------------------------------------
// The following commented code is not part of the framework, 
// just an advice on how to run it from within another file
// -----------------------------------------------------------

/*
// load framework
call compile preprocessFileLineNumbers "bdetect.sqf";  

// First declare any optional variables whose value should be other than Default (see the defined variables in bdetect.sqf, function bdetect_fnc_init()
bdetect_debug_enable = true;
bdetect_debug_levels = [9];
bdetect_debug_chat = true;

// Then name your own unit callback function (the one that should be triggered when a bullet is close to a unit)
bdetect_callback = "my_suppression_function";

// Define your own callback function, named as above
my_suppression_function = {
private [ "_unit", "_bullet", "_proximity", "_data", "_shooter", "_pos", "_time", "_msg" ];

_unit = _this select 0;
_bullet = _this select 1;
_proximity = _this select 2;
_data = _this select 3;
_shooter = _data select 0; // enemy shooter
_pos = _data select 1;	// starting position of bullet
_time = _data select 2; // starting time of bullet

_msg = format["my_suppression_function - [%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _unit, _bullet, _shooter, _proximity, _data];
[ _msg, 9 ] call bdetect_fnc_debug;
};

// Then initialize framework
call bdetect_fnc_init;

// Wait stuff to be loaded
waitUntil { bdetect_init_done};

// finally, activate display of stats if you wish
call bdetect_fnc_benchmark; 

// All done, now put your other stuff here ...
*/

Now time for some job related issues.

See you later.

Edited by fabrizio_T

Share this post


Link to post
Share on other sites

just want to say 1st thanks very much - now fire has an effect! awesome. and i get the guys aiming up with tpw and ace and asr. only there with tpw 2.01. worth it though...

Share this post


Link to post
Share on other sites
Best way around, so people may test and share some feedback.

Here is the updated bdetect.sqf, should cope well with 2.02.

Many additions and some rollback.

bDetect v0.64

/*
Basic bullet detection framework
Version: 0.64
Date: 03/07/2012
Author: Fabrizio_T 
Additional code: TPW 
File Name: bdetect.sqf

CHANGELOG:

-------------
Version: 0.64
-------------

* Incorporated suggestions from tpw: http://forums.bistudio.com/showthread.php?136304-TPWC-AI-suppression-system&p=2182742&viewfull=1#post2182742
* Minor optimization / fixes
* Introduced variable "bdetect_callback_mode": (String, Default "spawn") Allowed values: "call" or "spawn". It controls synchronous vs.asynchronous bdetect_callback() execution.

-------------
Version: 0.63
-------------

* Temporarily reverted from "diag_tickTime" to "time" for issues to be looked in

-------------
Version: 0.62
-------------

* Fixed bullet position handling

-------------
Version: 0.61
-------------

* Fixed problem with units eventually detecting own shots

------------
Version: 0.6
------------

* Incorporated v0.51 changes/fixes by tpw.
* Function bdetect_fnc_callback() slightly changed. See bottom of this file for example.
* Function bdetect_fnc_init() waits for 5 seconds to pass by after mission start, before activating the framework.
* Introduced function bdetect_fnc_eh_fired_add(): suitable to force -immediate- assignment of a fired EH to any unit. Syntax: [unit] call bdetect_fnc_eh_fired_add();
* Fixed function bdetect_fnc_benchmark(): internally using code spawning, not to block code execution after function call.
* Tweaked internals so that "diag_tickTime" is used instead of "time" (Thanks Ollem).
* Introduced function bdetect_fnc_eh_loop(): iteratively checks ( each "bdetect_eh_assign_cycle_wait" seconds ) for newly spawned units to assign them a 'Fired' event Handler.
* Renamed "bdetect_bullet_min_distance" to "bdetect_bullet_max_proximity"
* Introduced variable "bdetect_init_done": (Boolean). It evaulates true when framework is loaded. Usage: "waitUntil { bdetect_init_done};"
* Introduced variable "bdetect_eh_assign_cycle_wait": (seconds, Default 10). Wait duration foreach cyclic execution of bdetect_fnc_eh_loop()
* Introduced variable "bdetect_bullet_min_distance": (meters, Default 25). Bullets not having travelled this distance are ignored
* Introduced variable "bdetect_bullet_initial_min_speed": (meters / second, Default 360). Bullets initially slower than this are ignored (good for subsonic bullets skipping). 
* Introduced variable "bdetect_debug_chat": (Boolean, Default false) Show debug messages also in globalChat.
* Changed Variable "bdetect_debug_min_level" to "bdetect_debug_levels". (Array). Default [0,1,2,3,4,5,6,7,8,9]. 0-9 are reserved levels.
* Much more

------------
Version: 0.5
------------

* Framework is named "bdetect" and contained into a single file: bdetect.sqf 
* Renamed variable "bdetect_debug" to "bdetect_debug_enable"
* Introduced variables "bdetect_name" and "bdetect_version": name and version of the framework;
* Introduced function bdetect_fnc_init() to handle the framework bootstrap.
* Introduced variable "bdetect_callback" (string). It defines the name of a custom callback function to be called on a unit when it detects a close bullet (Default: "bdetect_fnc_callback").
* Functions and variable names polishing. All vars named bdetect_<varname>. All functions named bdetect_fnc_<funcname>.
* Added some missing private vars.

------------
Version: 0.4
------------

* Introduced variables "bdetect_enable" (boolean), "bdetect_debug_levels" (Number), "bdetect_skip_mags" (array).
* Variable "bdetect_enable" act as a toggle to enable / disable framework.
* Variable "bdetect_debug_levels" allows for selective display / logging of debug messages based on level.
* Introduced function bdetect_fnc_benchmark() to display performance stats.
* Added "bdetect_skip_mags", which is a blacklist of bullet types which should not trigger detection

------------
Version: 0.3
------------

* Introduced variables "bdetect_bullet_delay" (seconds) , "bdetect_bullet_max_height" (meters).
* Variable "bdetect_bullet_delay" (seconds) changes dinamycally between "bdetect_bullet_min_delay" (lower bound) and 1 (upper bound), depending on actual FPS vs "bdetect_fps_min".
* Variable "bdetect_bullet_max_height" (meters) is the maximum height for bullets, over ground. Bullets higher than this value (Default: 10) and with up vector > 0 are skipped from detection, since they are too high and diverge from ground.
* Some Code optimization.

------------
Version: 0.2
------------

* Position of bullet as SetPosASL.
* Introduced variables "bdetect_fps_min" (fps), "bdetect_bullet_max_distance" (meters), "bdetect_bullet_max_lifespan" (seconds).
* Introduced function bdetect_fnc_diag_min_fps(): in case FPS go under "bdetect_fps_min" value (Default: 25) bdetect_bullet_delay is gradually raised. 
* Function bdetect_fnc_bullet_remove() edited and renamed to bdetect_fnc_bullet_tag_remove(), since actual removal is done elsewhere.
* Bullets are removed from bdetect_fired_bullets if distance is over "bdetect_bullet_max_distance" meters or lifespan is over "bdetect_bullet_max_lifespan" seconds.

------------
Version: 0.1
------------

* First draft
*/

//BEGINNING OF FRAMEWORK CODE

// -----------------------------
// Constants
// -----------------------------

bdetect_name = "bDetect - Bullet Detection Framework"; 
bdetect_short_name = "bDetect"; 
bdetect_version = "0.64";
bdetect_init_done= false;

// -----------------------------
// Functions
// -----------------------------

bdetect_fnc_init = 
{
private [ "_msg", "_x" ];

sleep 5;

// You may override these variables
if(isNil "bdetect_enable") then { bdetect_enable = true; }; // (Boolean, Default true) Toggle to Enable / Disable bdetect altogether.
if(isNil "bdetect_debug_enable") then { bdetect_debug_enable = false; }; // (Boolean, Default false) Toggle to Enable / Disable debug messages.
if(isNil "bdetect_debug_chat") then { bdetect_debug_chat = false; }; // (Boolean, Default false) Show debug messages also in globalChat.
if(isNil "bdetect_debug_levels") then { bdetect_debug_levels = [0,1,2,3,4,5,6,7,8,9]; }; // (Array, Default [0,1,2,3,4,5,6,7,8,9]) Filter debug messages by included levels. 
if(isNil "bdetect_callback") then { bdetect_callback = "bdetect_fnc_callback"; }; // (String, Default "bdetect_fnc_callback") Name for your own callback function
if(isNil "bdetect_callback_mode") then { bdetect_callback_mode = "spawn"; }; // (String, Default "spawn") Allowed values: "call" or "spawn"
if(isNil "bdetect_fps_min") then { bdetect_fps_min = 25; }; // (Number, Default 25) The minimum FPS you wish to keep
if(isNil "bdetect_fps_calc_each_x_frames") then { bdetect_fps_calc_each_x_frames = 16; }; // (Number, Default 16) FPS check is done each "bdetect_fps_min" frames. 1 means each frame.
if(isNil "bdetect_eh_assign_cycle_wait") then { bdetect_eh_assign_cycle_wait = 10; }; // (Seconds, Default 10). Wait duration foreach cyclic execution of bdetect_fnc_eh_loop()
if(isNil "bdetect_bullet_min_delay") then { bdetect_bullet_min_delay = 0.1; }; // (Seconds, Default 0.1) Minimum time between 2 consecutive shots fired by an unit for the last bullet to be tracked. Very low values may cause lag.
if(isNil "bdetect_bullet_max_delay") then { bdetect_bullet_max_delay = 2; }; // (Seconds, Default 2)
if(isNil "bdetect_bullet_initial_min_speed") then { bdetect_bullet_initial_min_speed = 360; }; // (Meters/Second, Default 360) Bullets slower than this are ignored.
if(isNil "bdetect_bullet_max_proximity") then { bdetect_bullet_max_proximity = 10; }; // (Meters, Default 10) Maximum proximity to unit for triggering detection
if(isNil "bdetect_bullet_min_distance") then { bdetect_bullet_min_distance = 25; }; // (Meters, Default 25) Bullets having travelled less than this distance are ignored
if(isNil "bdetect_bullet_max_distance") then { bdetect_bullet_max_distance = 400; }; // (Meters, Default 400) Bullets past this distance are ignored
if(isNil "bdetect_bullet_max_lifespan") then { bdetect_bullet_max_lifespan = 0.5; }; // (Seconds, Default 0.5) Bullets living more than this are ignored
if(isNil "bdetect_bullet_max_height") then { bdetect_bullet_max_height = 6; }; // (Meters, Default 6) Bullets higher than this -and- diverging from ground are ignored

if(isNil "bdetect_skip_mags") then { // (Array) Skip these bullet types altogether
	bdetect_skip_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"  
	];  
};

// Do not edit the variables below.
if(isNil "bdetect_fired_bullets") then { bdetect_fired_bullets = []; };
if(isNil "bdetect_fps") then { bdetect_fps = bdetect_fps_min; };
if(isNil "bdetect_bullet_delay") then { bdetect_bullet_delay = bdetect_bullet_min_delay; };
if(isNil "bdetect_frame_tstamp") then { bdetect_frame_tstamp = 0; };
if(isNil "bdetect_frame_min_duration") then { bdetect_frame_min_duration = (bdetect_bullet_max_proximity * 2 * .66 / 900) max .01; };

// bullet speed converted to kmh
bdetect_bullet_initial_min_speed = bdetect_bullet_initial_min_speed * 3.6;

// compile callback name into function
bdetect_callback_compiled = call compile format["%1", bdetect_callback];

_msg = format["Starting %1 v%2.", bdetect_name, bdetect_version];
[ _msg, 0 ] call bdetect_fnc_debug;

bdetect_spawned_loop_handler = [] spawn bdetect_fnc_eh_loop;   

[bdetect_fnc_detect,0] call cba_fnc_addPerFrameHandler;   

bdetect_init_done= true;

hint format["%1 v%2 started.", bdetect_name, bdetect_version];
};

// Keep searching units for newly spawned ones and assign fired EH to them
bdetect_fnc_eh_loop =
{
private [ "_x", "_msg"];

while { true } do
{
	{ 
		[_x] call bdetect_fnc_eh_fired_add;

	} foreach allUnits;

	sleep bdetect_eh_assign_cycle_wait;
};
};

// Assign fired EH to a single unit
bdetect_fnc_eh_fired_add =
{
private ["_unit", "_msg"];

_unit = _this select 0;

if( isNil { _unit getVariable "bdetect_fired_eh" } ) then
{
	_unit setVariable ["bdetect_fired_eh", true]; 
	_unit addEventHandler ["Fired", bdetect_fnc_fired];

	if (  ( assignedVehicleRole _unit) select 0 == "Turret" && isNil { (vehicle _x) getVariable "bdetect_fired_eh" } ) then   
	{		
		(vehicle _x) setVariable ["bdetect_fired_eh", true]; 
		(vehicle _x) addeventhandler ["Fired", bdetect_fnc_fired];    
	}; 

	_msg = format["[%1] was assigned 'Fired' EH", _unit];
	[ _msg, 3 ] call bdetect_fnc_debug;
}
else
{
	_msg = format["[%1] already had an assigned 'Fired' EH", _unit];
	[ _msg, 3 ] call bdetect_fnc_debug;
};
};

// Fired EH
bdetect_fnc_fired =
{
	private ["_unit", "_muzzle", "_magazine", "_bullet", "_speed", "_msg", "_time", "_dt"];

if( bdetect_enable ) then
{
	_unit = _this select 0;
	_muzzle = _this select 2;
	_magazine = _this select 5;
	_bullet = _this select 6;
	_speed = speed _bullet;
	_time = time; //diag_tickTime

	_dt = _time - ( _unit getVariable ["bdetect_fired_time", 0] );

	if( _dt > bdetect_bullet_delay 
		&& !( _magazine in bdetect_skip_mags ) 
		&& _speed > bdetect_bullet_initial_min_speed 
	) then
	{
		_unit setVariable ["bdetect_fired_time", _time]; 

		// Append info to bullets array
		[ _bullet, _unit, _time ] call bdetect_fnc_bullet_add;

		_msg = format["[%1] Fired bullet: speed=%2, type=%3, Delay=%4", _unit, _speed, typeOf _bullet, _dt ];
		[ _msg, 2 ] call bdetect_fnc_debug;
	}
	else
	{
		_msg = format["[%1] Skipped bullet: speed=%2, type=%3, Delay=%4 [%5 - %6]", _unit, _speed, typeOf _bullet, _dt,  _time , ( _unit getVariable ["bdetect_fired_time", 0] )];
		[ _msg, 2 ] call bdetect_fnc_debug;
	};
};
};

// Time-critical detection function, to be executed per-frame
bdetect_fnc_detect =         
{        
private ["_n", "_tot", "_bullet", "_data", "_side", "_pos", "_time", "_shooter", "_blacklist", "_update_blacklist", "_dist", "_units", "_x", "_data", "_func", "_t", "_k", "_bpos", "_nul"];

_t = time; //diag_tickTime

if( bdetect_enable && (_t - bdetect_frame_tstamp) >= bdetect_frame_min_duration) then
{
	_msg = format["Frame duration=%1, min duration:%2", (_t - bdetect_frame_tstamp), bdetect_frame_min_duration ];
	[ _msg, 4 ] call bdetect_fnc_debug;

	_tot = count bdetect_fired_bullets;

	bdetect_frame_tstamp = _t;

	if ( _tot > 0 ) then 
	{ 
		if( diag_frameno % bdetect_fps_calc_each_x_frames == 0) then
		{
			call bdetect_fnc_diag_min_fps;
		};

		for "_n" from 0 to _tot - 1 step 2 do 
		{
			_bullet = bdetect_fired_bullets select _n;
			_data = bdetect_fired_bullets select (_n + 1);
			_shooter = _data select 0;
			_pos = _data select 1;
			_time = _data select 2;
			_blacklist = _data select 3;
			_update_blacklist = false;

			if( !( isnull _bullet ) ) then
			{
				_bpos = getPosATL _bullet;
				_dist = _bpos distance _pos;			
				//_msg = format["Following bullet %1. Time: %2. Distance: %3 Speed: %4. Position: %5", _bullet, _t - _time, _dist, (speed _bullet / 3.6), getPosASL _bullet];
				//[ _msg, 2 ] call bdetect_fnc_debug;
			};

			if( isNull _bullet 
				|| !(alive _bullet) 
				|| _t - _time > bdetect_bullet_max_lifespan 
				|| _dist > bdetect_bullet_max_distance	
				|| speed _bullet < bdetect_bullet_initial_min_speed // funny rebounds handling
				|| ( ( _bpos select 2) > bdetect_bullet_max_height && ( ( vectordir _bullet ) select 2 ) > 0 ) 
				) then
			{
				[_bullet] call bdetect_fnc_bullet_tag_remove;
			}
			else
			{
				if( _dist > bdetect_bullet_min_distance	) then
				{
					_units = _bpos nearEntities [ ["MAN"] , bdetect_bullet_max_proximity];

					{
						if( alive _x && !(_x in _blacklist) && _x != _shooter ) then
						{
							if( vehicle _x == _x && lifestate _x == "ALIVE") then
							{
								_blacklist = _blacklist + [_x];
								_update_blacklist = true;

								if(bdetect_callback_mode == "spawn") then {
									_nul = [_x, _bullet, _x distance _bpos, _data] spawn bdetect_callback_compiled;
								} else {
									[_x, _bullet, _x distance _bpos, _data] call bdetect_callback_compiled;
								};

								_msg = format["[%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _x, _bullet, _shooter, _x distance _bpos, _data];
								[ _msg, 9 ] call bdetect_fnc_debug;
							};
						}
						else
						{
							_msg = format["[%1] Blacklisted, bullet %2 ignored", _x, _bullet];
							[ _msg, 5 ] call bdetect_fnc_debug;
						};

					} foreach _units;

					if(_update_blacklist) then
					{
						// Update blacklist
						bdetect_fired_bullets set[ _n + 1, [_shooter, _pos, _time, _blacklist] ];
					};

					//_msg = format["bdetect_fired_bullets = %1", bdetect_fired_bullets];
					//[ _msg, 2 ] call bdetect_fnc_debug;
				};
			};
		};

		// remove dead / expired bullets
		bdetect_fired_bullets = bdetect_fired_bullets - [-1];

		//_msg = format["%1 bullets in array", count ( bdetect_fired_bullets ) / 2];
		//[ _msg, 2 ] call bdetect_fnc_debug;
	};
};
};

bdetect_fnc_diag_min_fps =
{
private ["_fps", "_msg"];

_fps = diag_fps;

_msg = format["FPS=%1, Min.FPS=%2, Prev. FPS=%3, bdetect_bullet_delay=%4)", _fps, bdetect_fps_min, bdetect_fps, bdetect_bullet_delay ];
[ _msg, 1 ] call bdetect_fnc_debug;

if( _fps < bdetect_fps_min * 1.15) then
{
	if( bdetect_bullet_delay + .15 < bdetect_bullet_max_delay && _fps < bdetect_fps_min ) then
	{
		bdetect_bullet_delay = bdetect_bullet_delay + .15;

		_msg = format["FPS down to %1. Augmenting bdetect_bullet_delay to %2", _fps, bdetect_bullet_delay];
		[ _msg, 1 ] call bdetect_fnc_debug;
	};
}
else
{
	if( ( bdetect_bullet_delay - .15 ) >= bdetect_bullet_min_delay ) then
	{
		bdetect_bullet_delay = bdetect_bullet_delay - .15;

		_msg = format["FPS up to %1. Reducing bdetect_bullet_delay to %2", _fps, bdetect_bullet_delay];
		[ _msg, 1 ] call bdetect_fnc_debug;
	};
};

bdetect_fps = _fps;
};

// Function to add a bullet to bdetect_fired_bullets 
bdetect_fnc_bullet_add = 
{
private ["_bullet", "_shooter", "_pos", "_time",  "_msg", "_n"];

_bullet = _this select 0; // bullet object
_shooter = _this select 1;	// shooter
_pos = getPosATL _bullet;	// bullet start position
_time = _this select 2;	// bullet shoot time
_n = count bdetect_fired_bullets;

bdetect_fired_bullets set [ _n,  _bullet  ];
bdetect_fired_bullets set [ _n + 1, [ _shooter, _pos, _time, [] ] ];

_msg = format["bullet %1 added", _bullet, _n / 2];
[ _msg, 2] call bdetect_fnc_debug;
};

// Function to remove a bullet from bdetect_fired_bullets 
bdetect_fnc_bullet_tag_remove = 
{
private ["_bullet", "_n", "_msg" ];

_bullet = _this select 0;
_n = bdetect_fired_bullets find _bullet;

if( _n != -1 ) then
{
	bdetect_fired_bullets set[ _n, -1 ];
	bdetect_fired_bullets set[ _n + 1, -1 ];

	_msg = format["null/expired bullet removed"];
	[ _msg, 2 ] call bdetect_fnc_debug;
};
};

// Callback function to be executed from within bdetect_fnc_detect
bdetect_fnc_callback = 
{
private [ "_unit", "_bullet", "_proximity", "_data", "_shooter", "_pos", "_time", "_msg" ];

_unit = _this select 0;		// unit being under fire
_bullet = _this select 1;	// bullet object
_proximity = _this select 2;	// distance between _bullet and _unit
_data = _this select 3;		// Array containing more data

_shooter = _data select 0; // shooter
_pos = _data select 1;	// starting position of bullet
_time = _data select 2; // starting time of bullet

_msg = format["[%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _unit, _bullet, _shooter, _proximity, _data];
[ _msg, 9 ] call bdetect_fnc_debug;
};

// function to display and log stuff (into .rpt file) level zero is intended only for builtin messages
bdetect_fnc_debug =
{
private [ "_msg", "_level"];

/*
DEBUG LEVELS: 
From 0-9 are reserved.

0 = unclassified messages
1 = FPS related messages
2 = "bdetect_fired_bullets" related messages
3 = EH related messages
4 = Frame related messages
5 = Unit blacklist messages
...
9 = Unit detection related messages
*/

_level = _this select 1;

if( bdetect_debug_enable && _level in bdetect_debug_levels) then
{
	_msg = _this select 0;

	diag_log format["%1 [%2 v%3] Frame:%4 L%5: %6", time, bdetect_short_name, bdetect_version, diag_frameno, _level, _msg ];

	if( bdetect_debug_chat ) then 
	{
		player globalchat format["%1 - %2", time, _msg ];
	};
};
};

bdetect_fnc_benchmark = 
{
private ["_cnt"];

if(isNil "bdetect_stats_max_bullets") then { bdetect_stats_max_bullets = 0;};
if(isNil "bdetect_stats_min_fps") then { bdetect_stats_min_fps = 999;};
if(isNil "bdetect_fired_bullets") then { bdetect_fired_bullets = [];};

_nul = [] spawn 
{
	sleep 5;

	while { true } do
	{
		_cnt = count ( bdetect_fired_bullets ) / 2;

		if( _cnt > bdetect_stats_max_bullets ) then { bdetect_stats_max_bullets = _cnt; };
		if( diag_fps < bdetect_stats_min_fps ) then { bdetect_stats_min_fps = diag_fps };
		hintsilent format["TIME: %1\nFPS: %2 (min: %3)\nBULLETS: %4 (max: %5)\nS.DELAY: %6 (Min FPS: %7)", time, diag_fps, bdetect_stats_min_fps, _cnt, bdetect_stats_max_bullets, bdetect_bullet_delay, bdetect_fps_min];

		sleep .1;
	};
};
};

// END OF FRAMEWORK CODE

// -----------------------------------------------------------
// Example for running the script
// -----------------------------------------------------------
// The following commented code is not part of the framework, 
// just an advice on how to run it from within another file
// -----------------------------------------------------------

/*
// load framework
call compile preprocessFileLineNumbers "bdetect.sqf";  

// First declare any optional variables whose value should be other than Default (see the defined variables in bdetect.sqf, function bdetect_fnc_init()
bdetect_debug_enable = true;
bdetect_debug_levels = [9];
bdetect_debug_chat = true;

// Then name your own unit callback function (the one that should be triggered when a bullet is close to a unit)
bdetect_callback = "my_suppression_function";

// Define your own callback function, named as above
my_suppression_function = {
private [ "_unit", "_bullet", "_proximity", "_data", "_shooter", "_pos", "_time", "_msg" ];

_unit = _this select 0;
_bullet = _this select 1;
_proximity = _this select 2;
_data = _this select 3;
_shooter = _data select 0; // enemy shooter
_pos = _data select 1;	// starting position of bullet
_time = _data select 2; // starting time of bullet

_msg = format["my_suppression_function - [%1] close to bullet %2 fired by %3, proximity=%4m, data=%5", _unit, _bullet, _shooter, _proximity, _data];
[ _msg, 9 ] call bdetect_fnc_debug;
};

// Then initialize framework
call bdetect_fnc_init;

// Wait stuff to be loaded
waitUntil { bdetect_init_done};

// finally, activate display of stats if you wish
call bdetect_fnc_benchmark; 

// All done, now put your other stuff here ...
*/

Now time for some job related issues.

See you later.

Awesome, incorporating it now

Changed line 334 to

_blacklist set [_blacklist,_x];

This will gain an extra 0.0000000000000000000001 fps

Share this post


Link to post
Share on other sites
Awesome, incorporating it now

Changed line 334 to

_blacklist set [_blacklist,_x];

This will gain an extra 0.0000000000000000000001 fps

I don't think it would work.

Maybe

_blacklist set [ count _blacklist, _x];

However should be very marginal (blacklisting is maybe 10% of detections, detections are about 1% of whole checking).

There's plenty of room for optimization, so far i'm concerned about reliability and features.

Squeezing off some more fps should be possibile once the framework is considered mature enough.

By the way however v0.64 is a bit faster than v0.63, due to more aggressive FPS balancing.

On my system it runs about 2-3 FPS faster in low FPS situations.

Edited by fabrizio_T

Share this post


Link to post
Share on other sites

Last night I had some time to play around with this addon and I love it! Great job and as previously said this part is really missing from BIS AI routines...

However after bumping up the "bdetect_bullet_max_distance" and "bdetect_bullet_max_lifespan" for sniping purposes it feels quite wierd that the AI instantly knows your position and turns around in a split second and starts to return fire. I mean one singel shot from ~1000 m distance by a sniper in a ghillie suit is not easy to detect especially if you are engaged from the back.

Would be nice if the reveal part could be optional set in the user config as well, I cut and paste what I edited in the script version...

...
//AI REVEAL SHOOTER
tpwcas_reveal = 1;
...

       ...
       if (_shooterside getFriend ( side _unit) < 0.6 ) then 
       {
           _ebc = _ebc + 1;
           _unit setvariable ["tpwcas_ebc", _ebc];
           if (tpwcas_reveal == 1) then
           {
               _unit reveal [_shooter, 3];   
           };
        };
        ...

This along with Robalos ASR-AI is must have for me, once again thanks for making and sharing!

/KC

Edited by KeyCat

Share this post


Link to post
Share on other sites
i get the guys aiming up with tpw and ace and asr. only there with tpw 2.01. worth it though...

+1 ASR_AI with ACE and TPWC_Suppression 2.00beta / LOS 1.0 script versions

Not all units are affected.

Share this post


Link to post
Share on other sites

Ok I've had a gutful of coding, here's the latest version before I hit the sack

TPWCAS 2.02b: http://filesonly.com/download.php?file=166TPWC_AI_SUPPRESS_202.zip

  • Uses bDetect 0.64
  • User configurable minimum skill values
  • User configurable reveal value ( 0 = unit knows nothing about shooter, 4 = everything about shooter is revealed to unit).

Knock yourselves out, and tell me about how flawed it is in 8 hours time :)

Share this post


Link to post
Share on other sites

Hello there

I'm new here and I've been following this thread from the beginning. Since I have no scripting skills whatsoever I haven't had any reason to post. But I've noticed something that may be a bug. I've been using a side-counting trigger for awhile to keep track of the unit numbers in missions.

Activation: Anybody Repeatedly

Condition: time % 2 > 1;

On Act: hint format ["West: %1\nEast: %2\nCiv: %3", west countSide thislist, east countSide thislist, civilian countSide thislist];

Now what I find is that if I set tpwcas_debug=1, then once bdetect is called the civilian count immediately jumps to a figure just over 3 times the total of east/west unit numbers on the map, even though I have not placed any civilian units on the map to begin with. Then once shooting starts the civ count increases continuously even after one side is annihilated. When it reaches somewhere around 3000+ the game starts to freeze very briefly every couple of seconds. If I set debug to 0 this does not occur, but then of course I'm unable to observe the coloured discs. I've run the game with various combinations of mods including asr and have removed all in turn to see if I could pinpoint any incompatibility, but it really does seem that it stems from tpwc and bdetect. Of course I might be misinterpreting something else, but using just the pbo (instead of the script and turning off debug) I cannot run the mod for more than 10 minutes, whereas before tpwc and bdetect were combined I was able to have battles that lasted 30+ minutes with no problems. Of course tpwc with bdetect may not be designed to run in debugging mode for extended times, so that might be the problem. Hope this is of help.

Share this post


Link to post
Share on other sites
I don't think it would work.

Maybe

_blacklist set [ count _blacklist, _x];

However should be very marginal (blacklisting is maybe 10% of detections, detections are about 1% of whole checking).

There's plenty of room for optimization, so far i'm concerned about reliability and features.

Squeezing off some more fps should be possibile once the framework is considered mature enough.

By the way however v0.64 is a bit faster than v0.63, due to more aggressive FPS balancing.

On my system it runs about 2-3 FPS faster in low FPS situations.

_blacklist set [ count _blacklist, _x]; = what I actually meant to write. Brain is fading badly, time for bed!

---------- Post added at 23:57 ---------- Previous post was at 23:52 ----------

Hello there

I'm new here and I've been following this thread from the beginning. Since I have no scripting skills whatsoever I haven't had any reason to post. But I've noticed something that may be a bug. I've been using a side-counting trigger for awhile to keep track of the unit numbers in missions.

Activation: Anybody Repeatedly

Condition: time % 2 > 1;

On Act: hint format ["West: %1\nEast: %2\nCiv: %3", west countSide thislist, east countSide thislist, civilian countSide thislist];

Now what I find is that if I set tpwcas_debug=1, then once bdetect is called the civilian count immediately jumps to a figure just over 3 times the total of east/west unit numbers on the map, even though I have not placed any civilian units on the map to begin with. Then once shooting starts the civ count increases continuously even after one side is annihilated. When it reaches somewhere around 3000+ the game starts to freeze very briefly every couple of seconds. If I set debug to 0 this does not occur, but then of course I'm unable to observe the coloured discs. I've run the game with various combinations of mods including asr and have removed all in turn to see if I could pinpoint any incompatibility, but it really does seem that it stems from tpwc and bdetect. Of course I might be misinterpreting something else, but using just the pbo (instead of the script and turning off debug) I cannot run the mod for more than 10 minutes, whereas before tpwc and bdetect were combined I was able to have battles that lasted 30+ minutes with no problems. Of course tpwc with bdetect may not be designed to run in debugging mode for extended times, so that might be the problem. Hope this is of help.

Very interesting. I wonder if the balls are counted as civilians? Because there are actually 3 balls for every unit on the map. This bastard debugging code is more trouble than it's worth!!! I will look into it tomorrow, and thanks tadanobu

OH, AND WELCOME TO THE FORUM!

Edited by tpw

Share this post


Link to post
Share on other sites
Ok I've had a gutful of coding, here's the latest version before I hit the sack

TPWCAS 2.02b: http://filesonly.com/download.php?file=166TPWC_AI_SUPPRESS_202.zip

  • Uses bDetect 0.64
  • User configurable minimum skill values
  • User configurable reveal value ( 0 = unit knows nothing about shooter, 4 = everything about shooter is revealed to unit).

Knock yourselves out, and tell me about how flawed it is in 8 hours time :)

Thanks again for your hard work :p

Share this post


Link to post
Share on other sites
Ok I've had a gutful of coding, here's the latest version before I hit the sack

TPWCAS 2.02b: http://filesonly.com/download.php?file=166TPWC_AI_SUPPRESS_202.zip

  • Uses bDetect 0.64
  • User configurable minimum skill values
  • User configurable reveal value ( 0 = unit knows nothing about shooter, 4 = everything about shooter is revealed to unit).

Knock yourselves out, and tell me about how flawed it is in 8 hours time :)

I still love you but I've got 2 questions:

1) Can you stop using that file service? Because it forces me to wait 30 seconds and it has a capcha (Mediafire is much better alternative).

2) How exactly does tpwcas_reveal work? If tpwcas_reveal = 4 then a supressed AI will instantly know where you are?

What's the purpose of this, besides extra challenge? Can you explain all the levels between 0 and 4 in more detail?

I guess that was a bit more than 2 questions.

Share this post


Link to post
Share on other sites
2) How exactly does tpwcas_reveal work? If tpwcas_reveal = 4 then a supressed AI will instantly know where you are?

reveal=4 means unit gains exact knowledge of type and position of the revealed one.

reveal=1.5 means reveal basically just its side.

The rest is inbetween.

The purpose is helping AI units in identifying targets. Vanilla AI is not that clever regarding that.

Since a unidentified target won't be attacked, this can be a major problem, especially if it's close and in line of sight.

I think these settings are being refined / finetuned by Coulum, so expect them to eventually change.

Please see here for some comments:

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

Edited by fabrizio_T

Share this post


Link to post
Share on other sites

Ahaaaa! So that solves the issue of AI with downs syndrome, when they will aim directly onto an enemy but will never fire. That's great.

Share this post


Link to post
Share on other sites

I got performance drop with the latest version after a few minutes of a firefight... a few seconds pause kind of stutter... tried to defrag, still no go. Also removed the debugging option in userconfig, still no go

Share this post


Link to post
Share on other sites
Ok I've had a gutful of coding, here's the latest version before I hit the sack

TPWCAS 2.02b:

The pace at which you and F release new version makes it very hard for me too keep up with testing :-)

Minor bug at line 290:

tpwcas_filter = 

should be

tpwcas_fnc_filter = 

Share this post


Link to post
Share on other sites

Playing around with the script some more I found in bdetect there is an area of commented code at the bottom:

// END OF FRAMEWORK CODE

// -----------------------------------------------------------

// Example for running the script

// -----------------------------------------------------------

// The following commented code is not part of the framework,

// just an advice on how to run it from within another file

// -----------------------------------------------------------

/*

// load framework

call compile preprocessFileLineNumbers "bdetect.sqf";

// First declare any optional variables whose value should be other than Default (see the defined variables in bdetect.sqf, function bdetect_fnc_init()

bdetect_debug_enable = true;

bdetect_debug_levels = [9];

bdetect_debug_chat = true;

etc

I've now commented each line of this area in the script version and part of the problem that I mentioned in earlier post has been solved. Although I still get the initial civ count as 3 x total of east/west units on map, the civ counter no longer increments as it did.

Again hope this helps.

Edited by tadanobu
Mistake

Share this post


Link to post
Share on other sites
Playing around with the script some more I found in bdetect there is an area of commented code at the bottom:

// END OF FRAMEWORK CODE

// -----------------------------------------------------------

// Example for running the script

// -----------------------------------------------------------

// The following commented code is not part of the framework,

// just an advice on how to run it from within another file

// -----------------------------------------------------------

/*

// load framework

call compile preprocessFileLineNumbers "bdetect.sqf";

// First declare any optional variables whose value should be other than Default (see the defined variables in bdetect.sqf, function bdetect_fnc_init()

bdetect_debug_enable = true;

bdetect_debug_levels = [9];

bdetect_debug_chat = true;

etc

I've now commented each line of this area in the script version and part of the problem that I mentioned in earlier post has been solved. Although I still get the initial civ count as 3 x total of east/west units on map, the civ counter no longer increments as it did.

Again hope this helps.

Those lines should remain commented (they already are), they are just an example for implementation.

bDetect is already started at the bottom of tpwc_ai_suppress202.sqf as you can see:

//CALL BDETECT
call compile preprocessFileLineNumbers "bdetect064.sqf";
bdetect_skip_mags = tpwcas_mags;
bdetect_debug_enable = false;
bdetect_callback = "tpwcas_fnc_localbullets";
call bdetect_fnc_init;
waitUntil { bdetect_init_done};

To solve the problem i think you'll have to wait for tpw intervention.

Share this post


Link to post
Share on other sites

Lol shows what I know about scripting. Dont think what I did made any difference. My apologies for presuming that the mistake lay there. Played some more and noticed that the problem arises after a unit dies. The civ count drops by 3 with the first fatality, then starts to increase incrementally from that point on. Damn hope I haven't posted prematurely this time and that this info is at least helpful.

Share this post


Link to post
Share on other sites

I confirm the issue portraied by tadanobu and (maybe) Mr_Centipede exists.

Too many balls around. I think tpw will solve easily.

Also i noticed that red suppression balls still appear upon corpses.

Share this post


Link to post
Share on other sites

I have been following the development of this with great interest, but being away from home have been unable to test for myself.

A couple of ideas that I wanted to pass on when considering Real Life effects

1. Incoming bullet cracks only get really scary when you realize they are close, you don`t realize they are close until you see them hit the ground near you, you or friends. I think the 25 m radius is probably about right. One thing you may want to add is casualties to massively up the affect of suppression. So I guess what I am saying is light suppression slows you but you still end up crawling about, returning fire etc. Effective suppression is when you start taking casualties, the effects of this are completely different to taking a few rounds overhead and hitting your belt buckles. People cease returning fire, focus on the casualties and need to be well led to recover from the immediate effects. More experienced troops are affected less by this than green ones.

- So possibly add an extra suppression affect for nearby casualties.

2. If you are in vehicles you generally are only aware of rounds when they hit the vehicle, Sound proofing in military vehicles is not good and there is so much background noise that you generally are unaware of rounds passing near, they have to be real close or hit. The bigger and the louder the vehicle the less the effect of suppression. Just try suppressing an MBT crew with an MG...you will just make them angry. Equally guys sitting in an APC will not be suppressed so easily as those in a light vehicle. Vehicle casualties are again key here.

- Less suppression on armored vehicles, but casualties key.

3. Aircraft do not even know they are being suppressed until you hit them, again aircraft noise over powers the effects of bullet cracks. Seeing tracer coming up at you is difficult, even at night. You do get suppressed when you hear them hit, normally meaning that you move, shift attack heading etc. Seeing your wing man explode, well that's a different matter.

- suppression of aircraft through casualties in the group.

Fear in combat comes from the senses: Sight, Sound, Smell, Touch - If you remove any one or more of these, the sense of what you are perceiving is markedly reduced. If all four are present the effects can be debilitating. Some individuals are less affected than others both during and after the combat. These effects in combat be over come with training and experience. Key is the management of the effects after the event.

Edited by UGLY58

Share this post


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

×