Jump to content
Sign in to follow this  
-Coulum-

Ai suppression script help

Recommended Posts

ooooh! I've never heard of cba_fnc_addPerFrameHandler but if you could help me out with implementing it when/if you have time or point me towards some documentation that would be awesome. What exactly does the cba_fnc_addPerFrameHandler do?

I'd be lying if I said that I knew how it worked , you'll have to talk to Sickboy about it. The documentation is essentially non-existent apart from https://dev-heaven.net/docs/cba/files/common/fnc_addPerFrameHandler-sqf.html#CBA_fnc_addPerFrameHandler. I know everything I know by looking at a foggy breath script that Falcon_565 (with help from Nouber Nou who helped invent it) concocted from my breath fog parameters here: http://forums.bistudio.com/showthread.php?113653-Simple-Breath-Fog-Script&p=2094486&viewfull=1#post2094486. All I know is that running breath fog on all units on a map would probably cripple the computer if not for cba_fnc_addperframehandler.

Here's a very quick test script which works for any unit on the map. An unintended side effect is that the unit reacts to its own bullets.

//UNITS WILL DROP IF SHOT AT 
// Original code idea by -Couloumb-
// TPW 20120616 

private ["_unit","_near","_bc","_sup"]; 

//Start hint
sleep 1;
hintsilent "TPW / Coulum suppress active";

//Main function
tpw_sup =  
{ 
   {
_unit = _x; 
if !(isplayer _unit) then 
	{
	_nextTime = _unit getVariable ["NextTime", -1]; 
	if(_nextTime == -1) then {_unit setVariable ["NextTime", diag_tickTime]};
	if(diag_tickTime >= _nextTime) then {_unit setVariable ["Suppressed", 0]}; 
	_bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]);
	if (_bc > 0) then 
		{
		_unit setVariable ["NextTime", diag_tickTime + 5];
		_unit setVariable ["Suppressed", _bc];
		};

	_sup = _unit getVariable "Suppressed";

	if (_sup > 0) then 
		{
		_unit setunitpos "down";
		hint format ["%1 suppressed",(name _unit)];	
		} else 
		{
		_unit setunitpos "auto";
		hint format ["%1 not suppressed",(name _unit)];	
		};
	};
   } forEach allUnits;
}; 

[tpw_sup,0.01] call cba_fnc_addPerFrameHandler;

Edited by tpw

Share this post


Link to post
Share on other sites
An unintended side effect is that the unit reacts to its own bullets.

Caveat - as yet, I'm massively ignorant about how to use EHs; however:

Could you used the "fired" EH to exclude the firing unit from the script? That EH won't work if the unit is firing from a vehicle according to the BiKi, but as I haven't time to do any testing for at least a week I don't know how your script would work on tank gunners, etc., anyway.

"Fired near" might be an alternative, which would prevent the firing unit suppressing nearby team-mates, although in CQB it might have unwonted effects.

Proper suppression would be a major boost to gameplay. Many thanks to all the people working on this for sharing.

Edited by Orcinus

Share this post


Link to post
Share on other sites

Thanks Orcinus! Here's an improved version in which units don't "auto suppress". I've also finessed it a little so that if a couple of bullets whiz by then a unit might drop to a knee. If more than 5 bullets in a 5 second period then they hit the deck.

Even without -Coulum-'s additonal skills modification code, this already makes gameplay a bit more interesting. A unit under a hail of fire simply stays down!

The fact that fast bullets are not always detected within the specified radius actually adds a little randomness.

// UNITS WILL DROP IF SHOT AT 
// Original code idea by -Coulum-
// TPW 20120617 

private ["_unit","_near","_bc","_shots","_id","_randid"]; 

//Start hint
sleep 1;
hintsilent "TPW / -Coulum- suppress active";

//Main function
tpw_sup =  
{ 
   {
_unit = _x; 
if !(isplayer _unit) then 
	{
	_nextTime = _unit getVariable ["NextTime", -1]; 
	if (_nextTime == -1) then 
		{
		_unit setVariable ["NextTime", diag_tickTime];
		_randid = round random 1000;
		_unit setvariable ["ID", _randid];
		_unit addeventhandler ["Fired",{tpw_fired = (_this select 0) getvariable "ID"}];
		};
	if (diag_tickTime >= _nextTime) then {_unit setVariable ["Shots", 0]}; 
	_id = _unit getVariable "ID";
	_bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]);
	if ((_bc > 0) and !(tpw_fired == _id))then 
		{
		_unit setVariable ["NextTime", diag_tickTime + 3 + random 5];
		_shots = _unit getVariable "Shots";
		_unit setVariable ["Shots", _shots + _bc];
		};

	_shots = _unit getVariable "Shots";
	if (_shots == 0) then {_unit setunitpos "auto"};
	if (_shots > 0) then {_unit setunitpos "middle"};
	if (_shots > 5) then {_unit setunitpos "down"};

	};
} forEach allunits;
}; 

[tpw_sup,0] call cba_fnc_addPerFrameHandler;

Edited by tpw

Share this post


Link to post
Share on other sites

Thanks tpw for the example on how to use the cba thing. I tried it with a single unit on the map and it worked great. But when I tried this with a moderate number of units (40) it brought my computer to its knees. I got 2 fps without any fighting going on... do you get that or am I doing something wrong?

I tried changing the delay (or at least I think I did by changing [tpw_sup,0] call cba_fnc_addPerFrameHandler; to [tpw_sup,5] call cba_fnc_addPerFrameHandler;)but All it did was result in lag spiking every 5 seconds.

Either way, being a scripting noob, I have some questions about your script if you don't mind answering them. Don't feel you have to, and be warned they are extremely noobish:)

1. Why did you use diag_timetick and _nexttime, instead of sleep?

2.

_randid = round random 1000; 

What exactly is the point of the making randid and the random number? Oh! is that so when the script repeats itself tpw_fired won't be the same as ID which is a whole new random number, if the unit has fired. I see now!

3.Why doesn't tpw_fired effect other units. Isn't it global, meaning that if one unit fires, tpw_fired will be set for all units?

Thanks!

Also, I could be wrong, but the way you have it, it would be impossible to suppress a unit that is shooting right? Because if a unit fires, tpw_fired and ID will be the same, meaning that the bullets are not counted and stances not applied.

Even without -Coulum-'s additonal skills modification code, this already makes gameplay a bit more interesting. A unit under a hail of fire simply stays down!

Yes but I have found some limitations.

Units that are fleeing refuse to change stance, and units that are "stuck" to cover (When you command a squad an L would appear where there are possible sticking points) also refuse to change stance, which is unfortunate because I wanted units to appear to be ducking down behind cover when under fire... Oh well.

Ontop of that, quick bullets are less likely to be detected, and therefore are less effective at suppression. This is somewhat a good thing, as most slow bullets are bigger which would make them have more of a suppressive effect in reality (slow fifty cal vs fast 5.56). The problems occur when you get into pistols and sub mg's. A silenced pistol will suppress someone all the time due to the bullets slow speed but in reality a silenced pistol would cause the least suppression.

I was also going to say that units that fire also suppress itself was a problem, but you and Orcinus seem to have solved that problem already (man I spent all day at work pondering how it could be done and you come and make it look easy!)

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Hi -coulum-.

Like I said previously, cba_fnc_addPerFrameHandler is a bit of a black art, trial and error affair to me, so in all probablilty I've just implemented the whole thing wrong. I only put the code ideas up there for consideration, not a finished product! Oh, and sleep commands are not compatible with cba_fnc_addPerFrameHandle, hence the diag_ticktime.

I tried the script with about 60 units on Aliabad taking pot shots at each other. I switched on an fps counter and sat back. With the identical mission, it ran at about 45 fps without the script, and maybe 40-42 fps with it. Not too bac considering the amount of bullets flying and how poor my computer is. You are only calling the script the once right? It doesn't need to be called for each unit.

I'm not at all sure that my fired event handler is the most effective solution, but it was the only one I could think of. The idea is that tpw_fired is a global variable available to all units, but one which changes depending on who just fired their weapon. At some stage, each unit is assigned a random ID, which lasts for the duration of play. Let's say a unit was setvariabled an ID of 123. When he fires, tpw_fired becomes 123. So if the script catches bullets around unit 123, and tpw_fired is 123, then it assumes that at least some of those bullets are from 123's weapon, and doesn't suppress 123. If an enemy with ID 456 is also firing at 123, then it's down to which event handler is fired first. But because the whole thing happens so quickly 456 can still definitely suppress the firing unit 123 because at some stage tpw_fired will be 456. As I said, probably not elegant.

Other problems: setunitpos does not change the stance of units who've been commanded into a stance or position. That's not a limitation of the script, it's a limitation of setunitpos. Not sure how to get around it.

You've also identified the problem of bullet speed. A faster projectile is simply harder to "catch" inside the specified volume around the player. The only real way around it is to make the volume bigger, but then that means units will be suppressed from bullets passing a long way away from them. So I'm not sure how to proceed there.

Lastly, I think you've correctly identified the biggest problem - I am a shit coder.

Edited by tpw

Share this post


Link to post
Share on other sites

Thanks for showing me how to add an EH to a script, as opposed to looking cluelessly at previously-completed scripts :)

I thought some more about this over breakfast. Maybe firedNear would be better? - according to the BiKi, max range is "~69m" so a smaller range could be used to exclude nearby allies (only, or obviously CQB would be even more FU'd than in vanilla).

Also thought about suppression of a unit that is firing - tpw's post seems to confirm that timing is the key. In any event, IRL would, say, a soldier with even an LMG be aware of bullets passing whilst firing? I've never heard an MG IRL, but a shotgun blast from a few m away is pretty damned loud. I guess the interval between bursts plus the rate of passing bullets plus timing factors in the script will determine whether the unit is suppressed. Less of an issue for units with non-auto firing weapons, perhaps. In any event, perfection isn't necessary, as long as the proportion of units that do not react is reasonably small. Hell, even a 50% efficiency would be a huge improvement.

Other problems: setunitpos does not change the stance of units who've been commanded into a stance or position. That's not a limitation of the script, it's a limitation of setunitpos. Not sure how to get around it.

Is it possible use setunitpos Auto before the setunitpos down or setunitpos middle

e.g.

_shots = _unit getVariable "Shots";
       if (_shots == 0) then {_unit setunitpos "auto"};
       if (_shots > 0) then {{_unit setunitpos "auto"};{_unit setunitpos "middle"}};
       if (_shots > 5) then {{_unit setunitpos "auto"};{_unit setunitpos "down"}}; 

Probably syntax wrong, but anyway..

I'm >90% certain it can be done. IIRC Gibson's fine Gib_Copy_My_Stance does override previous stance commands issued to a unit via the normal menu.

Heh, if you're a "shit coder" I'm a donkey :D

The stuff you are doing with Coulomb here & with SaOK et al on LOS (to mention just 2 projects) is really innovative, greatly needed, & most importantly it is all going in the right directions.

EDIT: Also think it should be possible to exclude silenced weapons. A check on what the unit is firing would best (quickest? - easiest, anyway) be done by Cfg class if there is a separate class for 'silenced' (or whatever), otherwise excluding via an array of classnames. Skipping the script for that unit if so would reduce CPU load a bit, but only if a lot of units are using silenced weapons.

Edited by Orcinus

Share this post


Link to post
Share on other sites

Thanks for the encouragement mate!

Setunitpos really is subordinate to player issued stance commands unfortunately. CMS actually doesn't override stance commands (I know, I looked closely a few days ago). From Gib's readme:

The scripts Detect Changes in the player's stance and issue updated stance rules to the

players group.Any unit in the players group that is under stance rule "AUTO",

'Keep Low' in menu 7,will act on these rule changes.Any unit that has been given any

other stance rule via menu 7 will retain those rules over those issued by the scripts.

Great idea re silenced weapons, I will look into it.

I'll look a bit further into firednear, it might also help with the baove point.

Thanks again Orcinus, your help and feedback is valuable, and exactly why I like being part of this community.

Share this post


Link to post
Share on other sites

My pleasure, glad to be of some small assistance.

SetUnitPos - hmm - but that should not be a problem with the AI other than in a player's group (apart from squads following mission-designer waypoint-mediated commands like stealth plus crawl, which form a fairly limited sub-set); and the player can always tell their units to drop down or crouch. As I almost always use CMS, I rarely use the menu 7 options and so 'my' units simply get switched between CMS and auto, whether individually or as a group.

I would have no problem at all if this development ends up as one best to be used in combination with CMS. Anyone who differs could use it standalone (mod or script) & accept that they have to give stance orders to any of their units not in auto mode. Even with those limitations unresolved, it would still be a big boost to game-play quality :D

Also occurs to me that it might be worth at least coordinating with Robalo at some stage, given the cool stance-changing enhancements he's developing for ASR_AI. Would be a great pity if there was an irreconcilable conflict.

Back to work!

Share this post


Link to post
Share on other sites
Like I said previously, cba_fnc_addPerFrameHandler is a bit of a black art, trial and error affair to me, so in all probablilty I've just implemented the whole thing wrong. I only put the code ideas up there for consideration, not a finished product! Oh, and sleep commands are not compatible with cba_fnc_addPerFrameHandle, hence the diag_ticktime.

I see.

I tried the script with about 60 units on Aliabad taking pot shots at each other. I switched on an fps counter and sat back. With the identical mission, it ran at about 45 fps without the script, and maybe 40-42 fps with it. Not too bac considering the amount of bullets flying and how poor my computer is. You are only calling the script the once right? It doesn't need to be called for each unit.

I feel like an idiot. Yeah I was calling it for every unit. But I see now its already foreach allunits at the end. Damn I feel stupid. [edit]Okay I feel pretty dumb. I still can't get this to work even when I call it once. In my init I have

nul = [] execvm "tpwsuppress.sqf";

Then in the tpwsuppress.sqf I have copied your script. When I start the mission I am notified that "tpw / -Coulum- suppress active", but my shots don't seem to affect the ai... I have CBA, CBA_A2, and CBA_OA running. Am I missing something?[/edit][edit2]aha! I found out why it wasn't working. When I changed the line

if ((_bc > 0) and !(tpw_fired == _id))then  

to

if ((_bc > 0) and (tpw_fired != _id))then  

It started working like a charm. I have no idea why that was or why it would work with you but not me, but I have gotten it to work. And it works great! very good job tpw!

I'm not at all sure that my fired event handler is the most effective solution, but it was the only one I could think of. The idea is that tpw_fired is a global variable available to all units, but one which changes depending on who just fired their weapon. At some stage, each unit is assigned a random ID, which lasts for the duration of play. Let's say a unit was setvariabled an ID of 123. When he fires, tpw_fired becomes 123. So if the script catches bullets around unit 123, and tpw_fired is 123, then it assumes that at least some of those bullets are from 123's weapon, and doesn't suppress 123. If an enemy with ID 456 is also firing at 123, then it's down to which event handler is fired first. But because the whole thing happens so quickly 456 can still definitely suppress the firing unit 123 because at some stage tpw_fired will be 456. As I said, probably not elegant.

I see, this makes so much more sense now that you explained it. Thanks.

You've also identified the problem of bullet speed. A faster projectile is simply harder to "catch" inside the specified volume around the player. The only real way around it is to make the volume bigger, but then that means units will be suppressed from bullets passing a long way away from them. So I'm not sure how to proceed there.

Well like you said earlier, bullet speed does add a bit of randomness which is good. The only time I see it being a problem is when pistol rounds are more effective than rifle rounds. Maybe making it so that a bullet is only counted if it is going over a certain speed would eliminate that problem.

Lastly, I think you've correctly identified the biggest problem - I am a shit coder.

Hell No! Not at all man. In no way am I trying to say that. I am the shit coder. And thanks alot for answering all my questions. I am learning a ton in this thread thanks to you. You've done a great job.

I thought some more about this over breakfast. Maybe firedNear would be better? - according to the BiKi, max range is "~69m" so a smaller range could be used to exclude nearby allies (only, or obviously CQB would be even more FU'd than in vanilla).

Good idea. I am not sure how it would be done though...

Also occurs to me that it might be worth at least coordinating with Robalo at some stage, given the cool stance-changing enhancements he's developing for ASR_AI. Would be a great pity if there was an irreconcilable conflict.

Yes good point. I believe the stances in this would overide any stances ASR assigns, because I believe he sets stance using setunitposweak.

I tried to keep scripts as simple and optimized as possible. There should not be any noticeable impact on performance.

There are limits to how many animations are processed and this not only saves performance but also makes it less predictable. I am OK with sometimes AI doing stupid things because humans do them too.

How I do it ? I'm plugging into the AnimDone EH, detect if a unit knows about enemies, if yes, select "Middle" stance with setUnitPosWeak, otherwise revert to "AUTO".

There's a special case if the animation was a stop and the unit is carrying MG, AR or sniper rifle, then selects the prone stance.

This is the lowest priority way so all other methods take over when it comes to player commanding AI stance, scripted setUnitPos or the game's default "micro-AI" when AI is close to things.

--edit--

Here's an idea. It probably wouldn't be too good if suppression was applied for ai in CQB. It would look bad if a unit were to go prone right infront of an enemy. So maybe something that detects whether there are nearby units, like this

// UNITS WILL DROP IF SHOT AT  
// Original code idea by -Coulum- 
// TPW 20120617  

private ["_unit","_near","_bc","_shots","_id","_randid","_nearestenemy","_distancetoenemy"];  

//Start hint 
sleep 1; 
hintsilent "TPW / -Coulum- suppress active"; 

//Main function 
tpw_sup =   
{  
   { 
   _unit = _x;  
   if !(isplayer _unit) then  
/////////////////////////////////added this
       {_nearestenemy = _unit findnearestenemy (getposatl _unit);
         _distancetoenemy = _unit distance _nearestenemy;
         if (_distancetoenemy > 25) then 
	{ 
/////////////////////////////////
              _nextTime = _unit getVariable ["NextTime", -1];  
               if (_nextTime == -1) then  
                      { 
                      _unit setVariable ["NextTime", diag_tickTime]; 
                      _randid = round random 1000; 
                      _unit setvariable ["ID", _randid]; 
                      _unit addeventhandler ["Fired",{tpw_fired = (_this select 0) getvariable "ID"}]; 
           }; 
       if (diag_tickTime >= _nextTime) then {_unit setVariable ["Shots", 0]};  
       _id = _unit getVariable "ID"; 
       _bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]); 
       if ((_bc > 0) and !(tpw_fired == _id))then  
           { 
           _unit setVariable ["NextTime", diag_tickTime + 3 + random 5]; 
           _shots = _unit getVariable "Shots"; 
           _unit setVariable ["Shots", _shots + _bc]; 
           }; 

       _shots = _unit getVariable "Shots"; 
       if (_shots == 0) then {_unit setunitpos "auto"}; 
       if (_shots > 0) then {_unit setunitpos "middle"}; 
       if (_shots > 5) then {_unit setunitpos "down"}; 
         };   
       }; 
   } forEach allunits; 
};  

[tpw_sup,0] call cba_fnc_addPerFrameHandler;  

It should make it so no suppression effects are applied if the unit is 25 metres or less away from a known enemy.

Anyways, I've gotta get some work done but hopefully I'll get some time to attempt some new stuff later.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Hi -Coulum-

Firstly, I hereby assert my right to the title of shittiest coder in this thread, so let's close that topic :)

nearestEnemy is a really good idea - but perhaps nearestObjects might be better?

nearestObjects [[i]firer[/i], ["Man"], 25]

would enable all units within 25 m to be excluded, so the firing unit's allies wouldn't get suppressed at any time (by the firing unit, that is). Allies more than 25 m away might, but that is far from unrealistic, & might reduce friendly fire casualties. To cut down the CPU time, perhaps only run nearestObjects on group leaders. That may result in failure to exclude some units, but could be worth it in terms of reducing CPU load. Either approach would certainly be better than firedNear which, the more I consider it, I suspect would not work at all well.

Lastly:

-apologies for getting your name wrong earlier. That's what comes with trying to catch up with Arma while dealing with way too many work emails.

- thanks for your initiative with this - having the idea is more than 50% of the battle, The creativity of people here continually surprises and delights me.

- and as for anyone learning a lot, that definitely includes me.

Cheers

Orcinus

Share this post


Link to post
Share on other sites
nearestEnemy is a really good idea - but perhaps nearestObjects might be better?

nearestObjects [firer, ["Man"], 25]

would enable all units within 25 m to be excluded, so the firing unit's allies wouldn't get suppressed at any time (by the firing unit, that is). Allies more than 25 m away might, but that is far from unrealistic, & might reduce friendly fire casualties. To cut down the CPU time, perhaps only run nearestObjects on group leaders. That may result in failure to exclude some units, but could be worth it in terms of reducing CPU load. Either approach would certainly be better than firedNear which, the more I consider it, I suspect would not work at all well.

Well if you made it so any "men" near a unit caused that unit to be impervious to suppression basically everyone on the map would be unsepressable as long as they have a buddy beside them. I just suggested that if an enemy is 25 m away that would make it so no Suppression effects would be dealt in order to not messup CQB behaviour like that in tpw's LOS addon. It would prevent an enemy from going prone 5 metres away from you when they should just turn and blast your head off...

But I think you are on to something. Would it be possible to have a fired eventhandler that defines the shooter as, lets say "shooter", and then use nearestObjects to detect if any units are close to "shooter". Then units that test positive for being close will not suffer from suppression effects. I don't know I am going to have to try and test it out when I get on my computer.

Lastly:

-apologies for getting your name wrong earlier. That's what comes with trying to catch up with Arma while dealing with way too many work emails.

- thanks for your initiative with this - having the idea is more than 50% of the battle, The creativity of people here continually surprises and delights me.

- and as for anyone learning a lot, that definitely includes me.

-Pfft, its not my real name. Know worries, I don't care.

-I'd say more like 5% but thanks anyways:) thank you (and tpw of course) for contributing to it so much.

-and me too!

Edited by -Coulum-

Share this post


Link to post
Share on other sites
Well if you made it so any "men" near a unit caused that unit to be impervious to suppression basically everyone on the map would be unsepressable as long as they have a buddy beside them. I just suggested that if an enemy is 25 m away that would make it so no Suppression effects would be dealt in order to not messup CQB behaviour like that in tpw's LOS addon. It would prevent an enemy from going prone 5 metres away from you when they should just turn and blast your head off...

But I think you are on to something. Would it ber possible to have a fired eventhandler that defines the shooter as, lets say "shooter", and then use nearestObjects to detect if any units are close to "shooter". Then units that test positive for being close will not suffer from suppression effects. I don't know I am going to have to try and test it out when I get on my computer.

That's exactly what I was trying to convey, however imperfectly. What I thought nearestObjects would achieve, rather than nearestEnemy, would be to enable exclusion of all units <25 m from the firer (or his group leader, perhaps) from suppression by that firer's bullets - and only from suppression by that firer; not that the firing unit becomes impervious to suppression (apologies if my inexperience with scripting led to confusion).

AIUI, the only difference between using nearestEnemy and nearestObjects would be that allies <25m away would be excluded from suppression by the firing unit's bullets as well as enemies. Or have I completely misunderstood how nearestObjects works?

Share this post


Link to post
Share on other sites

No confusion at all, Initially I was just suggesting nearest enemy for a seperate reason, totally unrelated to "friendly suppression". But your idea is really great I am giving it a try right now.

Share this post


Link to post
Share on other sites
No confusion at all, Initially I was just suggesting nearest enemy for a seperate reason, totally unrelated to "friendly suppression". But your idea is really great I am giving it a try right now.

Cool :) - but I'll have to wait til tomorrow to see the result, I have a conf call in less than six hours time & I need some sleep first!

Share this post


Link to post
Share on other sites

Yeah it might be a good idea to get some sleep then. See ya later.

--edit--7:31

Ah I was hopeing I could still catch you but I guess you'll see this in six hours..

It worked!

here's what I used..

// UNITS WILL DROP IF SHOT AT   
// Original code idea by -Coulum-  
// TPW 20120617   

private ["_unit","_near","_bc","_shots","_id","_randid","_nearestenemy","_distoenemy","distoshooter"];   

//Start hint  
sleep 1;  
hintsilent "TPW / -Coulum- suppress active";  

//Main function  
tpw_sup =    
{   
   { 
   _unit = _x;   
  	_nearestenemy = _unit findnearestenemy (getposatl _unit); 
       _distoenemy = _unit distance _nearestenemy; 
       if (_distoenemy > 25) then  
       {  

              _nextTime = _unit getVariable ["NextTime", -1];   
               if (_nextTime == -1) then   
                      {  
                      _unit setVariable ["NextTime", diag_tickTime];    
                      _unit addeventhandler ["Fired",{shooter = (_this select 0)}];  
           };  
       if (diag_tickTime >= _nextTime) then {_unit setVariable ["Shots", 0]};     
       _bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]);  
       _distoshooter = _unit distance shooter;
if ((_bc > 0) and _distoshooter >15)then   
           {  
           _unit setVariable ["NextTime", diag_tickTime + 3 + random 5];  
           _shots = _unit getVariable "Shots";  
           _unit setVariable ["Shots", _shots + _bc];  
           };  

       _shots = _unit getVariable "Shots";  
       if (_shots == 0) then {_unit setunitpos "auto"};  
       if (_shots > 0) then {_unit setunitpos "middle";};  
       if (_shots > 5) then {_unit setunitpos "down";};  
         };    
   } forEach allunits;  
};   

[tpw_sup,0.05] call cba_fnc_addPerFrameHandler;  

Instead of using Nearbyunits I actually just measured the distance from the unit in question to the shooter. If the distance whas more than 15 metres apply suppression otherwise don't. Haven't tried it in a big fight yet but with just a few units it works fine. Great work Orcinus.

I have a feeling that the nearestobject method might be more efficient so I am going to try that as well.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Great to see this whole thing really getting some legs - Coulum- (by the way, I'm with Orcinus, I keep going to spell it Coulomb as per my high school physics)! I think there's a bit of refinement required if you want to bring distance calculations into effect.

The way you've implemented findnearestenemy is all fine as long as the nearest enemy is actually shooting at the unit in question. Here's a scenario: There's an enemy 20m away not shooting at the unit, and another 60m away who is. The shots from the 60m enemy won't suppress the unit because of the nearby enemy.

I'm at work at present, which gives me ample opportunity to think about a solution, but not to code it.

Share this post


Link to post
Share on other sites
(by the way, I'm with Orcinus, I keep going to spell it Coulomb as per my high school physics)!

No prob, I got the idea for Coulum from physics class anyways. Beats me why I had to try and be creative and spell it differently.

The way you've implemented findnearestenemy is all fine as long as the nearest enemy is actually shooting at the unit in question. Here's a scenario: There's an enemy 20m away not shooting at the unit, and another 60m away who is. The shots from the 60m enemy won't suppress the unit because of the nearby enemy.

Yeah well I gues that's where It comes down to personal preference. You and a buddy are against an ai. Your buddy is 60m from the ai and you are 20m. If the ai were to get suppressed by your buddy, it would look weird to you - You are in close combat with the ai and all the sudden he decides to go prone instead of shoot you. That's all the findnearestenemy distance was meant to do. Prevent these suppression effects from ruining the ai at close combat.

I'm at work at present, which gives me ample opportunity to think about a solution, but not to code it.

Ha I know exactly what you mean.

Edited by -Coulum-

Share this post


Link to post
Share on other sites

Hey, i've been following this thoroughly, not contributing though (you don't wanna mess with me on the "shittiest coder" contest). Just throwing an idea/question out there: Problem with the solution you chose is if i try and flank the enemy, get close to it and have my buddy suppress him, it won't be suppressed cause i'm too close, right? So why not use a knowsabout, to be sure that the unit doesn't get suppressed when there's a close enemy, only if it knows that enemy is close?

Or would this end up with a CPU overload?

Share this post


Link to post
Share on other sites

Yeah well I gues that's where It comes down to personal preference. You and a buddy are against an ai. Your buddy is 60m from the ai and you are 20m. If the ai were to get suppressed by your buddy, it would look weird to you - You are in close combat with the ai and all the sudden he decides to go prone instead of shoot you. That's all the findnearestenemy distance was meant to do. Prevent these suppression effects from ruining the ai at close combat..

I would have thought that an enemy ducking/going prone because he's being shot at is the point of the exercise, regardless of who's shooting him!

Anyway, I think that between us all we have some basic framework in place, which can be modified to suit individual tastes.

Share this post


Link to post
Share on other sites
Hey, i've been following this thoroughly, not contributing though (you don't wanna mess with me on the "shittiest coder" contest). Just throwing an idea/question out there: Problem with the solution you chose is if i try and flank the enemy, get close to it and have my buddy suppress him, it won't be suppressed cause i'm too close, right? So why not use a knowsabout, to be sure that the unit doesn't get suppressed when there's a close enemy, only if it knows that enemy is close?

Or would this end up with a CPU overload?

The distance is already only measured to the closest enemy the unit knows about so what you suggest is how it should work as is. But you bring up a good point. If your suppressing an enemy and then assault them you wouldn't want them to all the sudden pop up because you are 25 metres away from them. Even if they do know about you the whole point of suppression is to keep the enemy down so when you get into CQB you can take them out before they have the to get up and return fire. So I guess your right tpw, this should be taken out. The only thing I worry about would be having unit crawling up to me in close combat because he is suppressed, which would look kind of weird. But I guess that sort of thing probably won't happen much. I updated the script without the distance to enemy measurements. It will also mean one less distance measurement for the computer to complete which is good.

// UNITS WILL DROP IF SHOT AT   
// Original code idea by -Coulum-  
// TPW 20120617   

private ["_unit","_near","_bc","_shots","_id","_randid","_nearestenemy","_distoenemy","_distoshooter"];   

//Start hint  
sleep 1;  
hintsilent "TPW / -Coulum- / Orcinus suppress active";  

//Main function  
tpw_sup =    
{   
   { 
   _unit = _x;   
              _nextTime = _unit getVariable ["NextTime", -1];   
               if (_nextTime == -1) then   
                      {  
                      _unit setVariable ["NextTime", diag_tickTime];    
                      _unit addeventhandler ["Fired",{shooter = (_this select 0)}];  
           };  
       if (diag_tickTime >= _nextTime) then {_unit setVariable ["Shots", 0]};     
       _bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]);  
       _distoshooter = _unit distance shooter;
   if ((_bc > 0) and _distoshooter >15)then   
           {  
           _unit setVariable ["NextTime", diag_tickTime + 3 + random 5];  
           _shots = _unit getVariable "Shots";  
           _unit setVariable ["Shots", _shots + _bc];  
           };  

       _shots = _unit getVariable "Shots";  
       if (_shots == 0) then {_unit setunitpos "auto"};  
       if (_shots > 0) then {_unit setunitpos "middle";};  
       if (_shots > 5) then {_unit setunitpos "down";};     
   } forEach allunits;  
};   

[tpw_sup,0.05] call cba_fnc_addPerFrameHandler;  

This is the code using nearestobject. It is very intesive compared to the one using distance. There is a very noticeable fps drop but I figured I'd show it anyways for anyone interested.

// UNITS WILL DROP IF SHOT AT   
// Original code idea by -Coulum-  
// TPW 20120617   

private ["_unit","_near","_bc","_shots","_id","_randid","_nonsuppressables"];   

//Start hint  
sleep 1;  
hintsilent "TPW / -Coulum- / Orcinus suppress active";  

//Main function  
tpw_sup =    
{   
   { 
   _unit = _x;   
            _nextTime = _unit getVariable ["NextTime", -1];   
               if (_nextTime == -1) then   
                      {  
                      _unit setVariable ["NextTime", diag_tickTime];    
                      _unit addeventhandler ["Fired",{shooter = (_this select 0)}];  
           };  
       if (diag_tickTime >= _nextTime) then {_unit setVariable ["Shots", 0]};     
       _bc = count ((getposatl _unit) nearobjects ["Bulletbase",10]);  
       _nonsuppressables = nearestObjects [(getposatl shooter), "MAN", 15];;
if ((_bc > 0) and _unit in _nonsuppressables)then   
           {  
           _unit setVariable ["NextTime", diag_tickTime + 3 + random 5];  
           _shots = _unit getVariable "Shots";  
           _unit setVariable ["Shots", _shots + _bc];  
           };  

       _shots = _unit getVariable "Shots";  
       if (_shots == 0) then {_unit setunitpos "auto"};  
       if (_shots > 0) then {_unit setunitpos "middle";hint format ["%1 is suppressed",(name _unit)];};  
       if (_shots > 5) then {_unit setunitpos "down";hint format ["%1 is suppressed",(name _unit)];};     
   } forEach allunits;  
};   

[tpw_sup,0] call cba_fnc_addPerFrameHandler;  

Edited by -Coulum-

Share this post


Link to post
Share on other sites

I've got an idea brewing to actually make the fired eventhandler setvariable each bullet so that the bullet contains the information about who shot it. Then if a unit detects any bullets, the info can be used to determine who shot each bullet and from how far away. Might or might not make the CPU explode, but the only way is to try it. If it works it should address the issues from the previous posts, because the unit could be set to ignore bullets from friendlies, or from nearby enemies etc etc.

Share this post


Link to post
Share on other sites
I've got an idea brewing to actually make the fired eventhandler setvariable each bullet so that the bullet contains the information about who shot it. Then if a unit detects any bullets, the info can be used to determine who shot each bullet and from how far away. Might or might not make the CPU explode, but the only way is to try it. If it works it should address the issues from the previous posts, because the unit could be set to ignore bullets from friendlies, or from nearby enemies etc etc.

I was thinking that awhile ago but didn't know how it could be done. I am very unfamiliar with set/get variable. If you did this would each bullet "remember" its shooter for the entirity of its life time or would it simply be until another unit fires. If the former this would be much better than what we have now (as there are some "problems" that occur when many units are firing at the same time - eventually there are more bullets being fired than the fired eventhandler can keep up with resulting in friendly suppression). Good luck to you, I'm hitting the sack.

Share this post


Link to post
Share on other sites
I was thinking that awhile ago but didn't know how it could be done. I am very unfamiliar with set/get variable. If you did this would each bullet "remember" its shooter for the entirity of its life time or would it simply be until another unit fires. If the former this would be much better than what we have now (as there are some "problems" that occur when many units are firing at the same time - eventually there are more bullets being fired than the fired eventhandler can keep up with resulting in friendly suppression). Good luck to you, I'm hitting the sack.

Should be the former. I will have something for when you wake up.

Share this post


Link to post
Share on other sites

Are these newer scripts deem functional? Would you mind update the first post and teach us how to run the scripts? Thank you

Share this post


Link to post
Share on other sites
Should be the former. I will have something for when you wake up.

Awesome! But Now I won't be able to fall asleep. See you later.

Are these newer scripts deem functional? Would you mind update the first post and teach us how to run the scripts? Thank you

I wouldn't say there is a finished product yet but the scripts are definitely functional. I will update the first post first thing when I wake up.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×