Jump to content
fn_Quiksilver

Get artillery firing position in computer

Recommended Posts

Hi guys,

 

I'm trying to return the position on the map where the artillery operator has selected with his mouse prior to clicking Fire.

 

On regular map this is fine with onMapSingleClick but with artillery computer it is slightly different?

 

I am guessing the target (where the user clicks on the artillery computer) is some kind of map control and I could get the map position of the control?

 

Will post solution here if/when found.

Share this post


Link to post
Share on other sites

Did you ever find out how to achieve this ?

 

Just looked into this myself but have no idea at the moment.

 

Id like to find out what map position the player has selected in the artillery computer each time he clicks on the targeting map.

 

Does anyone know how to achieve this ?

 

Cheers.

Share this post


Link to post
Share on other sites

Hi,

I failed to pick the exact coordinate on this specific map. you can grab the grid coordinates with an 100 m precision...

 

0 = [] spawn {  
  disableSerialization;   
  private "_ctrl";   
  while {true} do {   
    waitUntil {_ctrl = ({ if !(isNull (_x displayCtrl 510)) exitWith {_x}; displayNull } forEach allDisplays) displayCtrl 510; !isNull _ctrl};   
    systemChat "Artillery computer opened";   
    _eh = (findDisplay -1) displayAddEventHandler ["mouseButtonDown","
    systemChat ctrlText (findDisplay -1 displayCtrl 504)"];
    waitUntil {isNull _ctrl};
    (findDisplay -1) displayRemoveEventHandler ["mouseButtonDown",_eh];
    sleep 0.1;
    systemChat "Artillery computer closed";   
  };  
};

 

The control is 504 for the displayed grid. You can grab the distance with #505 and direction with #508, but direction is round to degree, so the precision is not fair for medium and long distances.

I haven't better so far.

Share this post


Link to post
Share on other sites

Finally, I got it!

 

0 = [] spawn {
  disableSerialization;  
  private "_displ";
  while {true} do {    
    waitUntil {_displ = ({ if !(isNull (_x displayCtrl 510)) exitWith {_x}; displayNull } forEach allDisplays) displayCtrl 510; !isNull _displ};  
    systemChat "Artillery computer opened";
    _eh = (findDisplay -1 displayCtrl 500) ctrlAddEventHandler ["mouseButtonDown","
      systemChat str ((_this select 0) ctrlMapScreenToWorld [_this select 2,_this select 3])
    "];
    waitUntil {isNull _displ};
    (findDisplay -1 displayCtrl 500) ctrlRemoveEventHandler ["mouseButtonDown",_eh];
    systemChat "Artillery computer closed";  
  };
};

 

  • Like 3

Share this post


Link to post
Share on other sites
23 hours ago, cb65 said:

Did you ever find out how to achieve this ?

 

Just looked into this myself but have no idea at the moment.

 

Id like to find out what map position the player has selected in the artillery computer each time he clicks on the targeting map.

 

Does anyone know how to achieve this ?

 

Cheers.

 

Interesting

 

What are you planning on to use it for? 

Share this post


Link to post
Share on other sites
5 hours ago, pierremgi said:

Finally, I got it!

 


0 = [] spawn {
  disableSerialization;  
  private "_displ";
  while {true} do {    
    waitUntil {_displ = ({ if !(isNull (_x displayCtrl 510)) exitWith {_x}; displayNull } forEach allDisplays) displayCtrl 510; !isNull _displ};  
    systemChat "Artillery computer opened";
    _eh = (findDisplay -1 displayCtrl 500) ctrlAddEventHandler ["mouseButtonDown","
      systemChat str ((_this select 0) ctrlMapScreenToWorld [_this select 2,_this select 3])
    "];
    waitUntil {isNull _displ};
    (findDisplay -1) ctrlRemoveEventHandler ["mouseButtonDown",_eh];
    systemChat "Artillery computer closed";  
  };
};

 

 

Thanks very much pierremgi i'll have a play around with that code today mate.

 

1 hour ago, Crielaard said:

 

Interesting

 

What are you planning on to use it for? 

 

@Crielaard I am just playing around with ideas on ways to try and prevent artillery players from firing where they shouldn't.

 

One way I've worked out is to use a Fired eventhandler on the artillery unit and keep checking each projectiles distance to safe areas and if the projectile goes within 50-100m of a safe area it gets deleted before it hits.

 

Thanks again,

 

Cheers.

Share this post


Link to post
Share on other sites

@pierremgi your code works perfectly except I'm getting this script error when I exit the artillery computer and then when I go back into the artillery computer the code has stopped working because of the error.

 

12:33:56 Error in expression <Until {isNull _displ};
(findDisplay -1) ctrlRemoveEventHandler ["mouseButtonDown>
12:33:56   Error position: <ctrlRemoveEventHandler ["mouseButtonDown>
12:33:56   Error ctrlremoveeventhandler: Type Display (dialog), expected Control

 

Any chance you could look into that mate ?

 

I'm not up to speed when it comes to RscDisplays.

 

Thanks again for putting in the time and effort on this.

 

Cheers.

Share this post


Link to post
Share on other sites

Corrected in my post: Read: (findDisplay -1 displayCtrl 500) ctrlRemoveEventHandler.... at the end of the script.

  • Like 1

Share this post


Link to post
Share on other sites

Neat solution @pierremgi!

 

 

6 hours ago, cb65 said:

One way I've worked out is to use a Fired eventhandler on the artillery unit and keep checking each projectiles distance to safe areas and if the projectile goes within 50-100m of a safe area it gets deleted before it hits.

 

Just be aware that 50-100m isn't much, considering arty shells in game can travel 300-810m/s.

 

Cheers

  • Like 2

Share this post


Link to post
Share on other sites
1 hour ago, pierremgi said:

Corrected in my post: Read: (findDisplay -1 displayCtrl 500) ctrlRemoveEventHandler.... at the end of the script.

 

thanks mate I actually noticed that myself but didn't trust my instincts.

 

45 minutes ago, Grumpy Old Man said:

Neat solution @pierremgi!

 

 

 

Just be aware that 50-100m isn't much, considering arty shells in game can travel 300-810m/s.

 

Cheers

 

Yeah sometimes the projectiles, usually the first projectile, the eventhandler doesn't seem to work but its only sometimes.

 

Have to play around with it some more. Here's my Fired eventhandler code.

 

Spoiler

// addEventHandler code.

_mortar = _this select 0;

_mortar addEventHandler ["fired",{[(_this select 0),(_this select 6)] execVM "fired.sqf";}];

// fired.sqf code:

sleep 1;

private ["_mortar","_projectile","_gunner","_side","_base","_text"];

_mortar = _this select 0;
_projectile = _this select 1;

_gunner = gunner _mortar;
_side = side _gunner;

_base = objNull;

if (_side == west) then {_base = flageast;} else {_base = flagwest;};

while {(alive _projectile)} do {
    _pos = _projectile distance2D _base;
    if (_pos < 100) then {
	    deleteVehicle _projectile;
	    _text = parseText format ["<t size='1.25' color='#FF0000'>ATTENTION!<br/><br/></t><t size='1.25' color='#e5b348'>Projectile has been destroyed you cannot fire on your enemies main base.</t>"];
		_text remoteExec ["hint", _gunner];
		sleep 10;
		"" remoteExec ["hint", _gunner];
	};
    sleep 1;
};

 

 

Have you got any thoughts or ideas on this @Grumpy Old Man ?

 

Thanks again,

 

Cheers.

Share this post


Link to post
Share on other sites

I'd say make the distance at least one km, also check for a negative Z velocity to make sure the projectile is heading towards the ground to prevent mishaps.

Depending on how many guns you want to keep in check like this you could also use an eachFrame eventhandler to increase control.

Add one eventhandler to check for multiple projectiles, you could add those projectiles to a global array through a fired eventhandler and have the eachFrame EH iterate through all projectiles.

 

Considering one frame at 60fps takes roughly 16.67ms to run, that would be 18m/48m distance travelled for a projectile flying at 300m/s / 810m/s respectively.

 

Checking for distancesqr and negative Z velocity isn't too expensive and could be negated for projectile counts in the lower 2 digit range.

 

I also recommend to rename your _pos variable into _distance, since it contains the distance, not a position.

 

A check could look like this:

_distance = _projectile distancesqr _base;
if ((velocity _projectile select 2) < 0 AND _distance < 1000000) then {
//bleh
};

Also keep in mind that certain ammo spawns submunition like the sandstorm, could be tricky to handle a case like that.

 

Cheers

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, Grumpy Old Man said:

I'd say make the distance at least one km, also check for a negative Z velocity to make sure the projectile is heading towards the ground to prevent mishaps.

Depending on how many guns you want to keep in check like this you could also use an eachFrame eventhandler to increase control.

Add one eventhandler to check for multiple projectiles, you could add those projectiles to a global array through a fired eventhandler and have the eachFrame EH iterate through all projectiles.

 

Considering one frame at 60fps takes roughly 16.67ms to run, that would be 18m/48m distance travelled for a projectile flying at 300m/s / 810m/s respectively.

 

Checking for distancesqr and negative Z velocity isn't too expensive and could be negated for projectile counts in the lower 2 digit range.

 

I also recommend to rename your _pos variable into _distance, since it contains the distance, not a position.

 

A check could look like this:


_distance = _projectile distancesqr _base;
if ((velocity _projectile select 2) < 0 AND _distance < 1000000) then {
//bleh
};

Also keep in mind that certain ammo spawns submunition like the sandstorm, could be tricky to handle a case like that.

 

Cheers

 

@Grumpy Old Man thanks for that input mate I'll see what I can come up with.

 

Any chance I could PM you if I'm having any difficulties ?

 

Cheers.

Share this post


Link to post
Share on other sites

 

Quote

Considering one frame at 60fps takes roughly 16.67ms to run, that would be 18m/48m distance travelled for a projectile flying at 300m/s / 810m/s respectively.

How did you get those numbers? 0.016(seconds)*300(meters/second) gives only 4.8 meters/frame for 300m/s shell and 13 meters/frame for the high velocity MRLS rocket.

Anyway, by coincidence I've made a similar script a few days ago(To spawn an AI base if the player wants to mortar it). It uses the method proposed above, but it turns out that per-frame timing is excessive.

 

First we can check with rather long time intervals(~1 second) until the mortar shell ascends to its apogee.

Then we check with 0.1 time intervals the time until the mortar shell falls. I estimate it by dividing shell's altitude above the ground by it's vertical velocity. When the time is below some threshold(say, 8 seconds, but you can use a lower one for your case) we can roughly estimate where it's going to land by taking its current horizontal velocity and multiplying it by the estimated time-to-explosion(a linear approximation). Note that this gives higher errors if the shell is travelling above mountains.

 

The method works not bad, but it depends on how big is the zone you want to 'protect'. You can tweak the timing constants to get more precision. If you want super high precision, i think I've seen a function that can tell you where a given line will intersect with terrain.

 

Also the code comes with a bonus: it filters out the HMG/GMG turret fire by arma's default artilleries.

Spoiler

 


//Attach it to the vehicle like this:
//_eh = _unit addEventHandler ["Fired", {_this spawn sense_fnc_infFired_eh}];
sense_fnc_mortarFired_eh =
{
	/*
	Fired event handler for mortars.
	If a mortar shell/rocket is fired, its trajectory is being monitored. If it falls near
	a location, the location is spawned.
	*/
	params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"];
	
	if((_ammo isKindOf "GrenadeBase") || (_ammo isKindOf "BulletBase")) then //If it's some kind of machinegun attached to the artillery
	{
		//In case you want to do something when the layer fires those HMG/GMG turrets
	}
	else //Otherwise it's either a rocket(MLRS) or a shell
	{
		private _posLaunch = getPosWorld _unit;
		//diag_log format ["==== Mortar fire detected!"];
		private _c = _unit getVariable "s_firedArtillery";
		_c = _c + 1;
		_unit setVariable ["s_firedArtillery", _c];
		
		_pos = getPos _projectile;
		//Wait until projectile ascends
		waitUntil {
			_vz = (velocity _projectile) select 2;
			if (isNull _projectile || _vz < 0) then { true }
			else {sleep 0.7; false};
		};
		//diag_log format ["Ascention done!"];
		
		//Wait until projectile is about 8s before impact
		_t = 0;
		waitUntil {
			if(!isNull _projectile) then
			{
				_vz = (velocity _projectile) select 2;
				_h = (getPosATL _projectile) select 2;
				_t = -(_h/_vz);
				if(_t < 8) then {true}
				else {sleep 0.2; false};
			};
		};
		
		//Estimate the impact location
		_v = velocity _projectile;
		_vx = _v select 0;
		_vy = _v select 1;
		_pos = (getPos _projectile) vectorAdd [_vx*_t, _vy*_t, 0];
		//diag_log format ["final eta: %1", _t];
		//diag_log format ["estimated impact pos: %1", _pos];
		
		//_pos is the estimated location where it will land. Check whatever you need here.
		
		//Wait until the explosion (because in my case i dont delete mortar shells, but i monitor them)
		_pos = getPos _projectile;
		waitUntil {
			if (isNull _projectile) then { true } //Wait until the shell is gone
			else {
				_pos = getPos _projectile; sleep 0.2; false
			};
		};

		//_pos is the approximate location where the mortar shell has landed.
	};
};

 

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, sparker said:

 

How did you get those numbers? 0.016(seconds)*300(meters/second) gives only 4.8 meters/frame for 300m/s shell and 13 meters/frame for the high velocity MRLS rocket.

Anyway, by coincidence I've made a similar script a few days ago(To spawn an AI base if the player wants to mortar it). It uses the method proposed above, but it turns out that per-frame timing is excessive.

 

First we can check with rather long time intervals(~1 second) until the mortar shell ascends to its apogee.

Then we check with 0.1 time intervals the time until the mortar shell falls. I estimate it by dividing shell's altitude above the ground by it's vertical velocity. When the time is below some threshold(say, 8 seconds, but you can use a lower one for your case) we can roughly estimate where it's going to land by taking its current horizontal velocity and multiplying it by the estimated time-to-explosion(a linear approximation). Note that this gives higher errors if the shell is travelling above mountains.

 

The method works not bad, but it depends on how big is the zone you want to 'protect'. You can tweak the timing constants to get more precision. If you want super high precision, i think I've seen a function that can tell you where a given line will intersect with terrain.

 

Also the code comes with a bonus: it filters out the HMG/GMG turret fire by arma's default artilleries.

  Reveal hidden contents

 



//Attach it to the vehicle like this:
//_eh = _unit addEventHandler ["Fired", {_this spawn sense_fnc_infFired_eh}];
sense_fnc_mortarFired_eh =
{
	/*
	Fired event handler for mortars.
	If a mortar shell/rocket is fired, its trajectory is being monitored. If it falls near
	a location, the location is spawned.
	*/
	params ["_unit", "_weapon", "_muzzle", "_mode", "_ammo", "_magazine", "_projectile", "_gunner"];
	
	if((_ammo isKindOf "GrenadeBase") || (_ammo isKindOf "BulletBase")) then //If it's some kind of machinegun attached to the artillery
	{
		//In case you want to do something when the layer fires those HMG/GMG turrets
	}
	else //Otherwise it's either a rocket(MLRS) or a shell
	{
		private _posLaunch = getPosWorld _unit;
		//diag_log format ["==== Mortar fire detected!"];
		private _c = _unit getVariable "s_firedArtillery";
		_c = _c + 1;
		_unit setVariable ["s_firedArtillery", _c];
		
		_pos = getPos _projectile;
		//Wait until projectile ascends
		waitUntil {
			_vz = (velocity _projectile) select 2;
			if (isNull _projectile || _vz < 0) then { true }
			else {sleep 0.7; false};
		};
		//diag_log format ["Ascention done!"];
		
		//Wait until projectile is about 8s before impact
		_t = 0;
		waitUntil {
			if(!isNull _projectile) then
			{
				_vz = (velocity _projectile) select 2;
				_h = (getPosATL _projectile) select 2;
				_t = -(_h/_vz);
				if(_t < 8) then {true}
				else {sleep 0.2; false};
			};
		};
		
		//Estimate the impact location
		_v = velocity _projectile;
		_vx = _v select 0;
		_vy = _v select 1;
		_pos = (getPos _projectile) vectorAdd [_vx*_t, _vy*_t, 0];
		//diag_log format ["final eta: %1", _t];
		//diag_log format ["estimated impact pos: %1", _pos];
		
		//_pos is the estimated location where it will land. Check whatever you need here.
		
		//Wait until the explosion (because in my case i dont delete mortar shells, but i monitor them)
		_pos = getPos _projectile;
		waitUntil {
			if (isNull _projectile) then { true } //Wait until the shell is gone
			else {
				_pos = getPos _projectile; sleep 0.2; false
			};
		};

		//_pos is the approximate location where the mortar shell has landed.
	};
};

 

 

Hey thanks very much for sharing your script with us sparker, looks like its just what I need, I'll have a play with it tomorrow.

 

Wow the help and support these forums provide is priceless, I could never have learnt how to code without them.

 

Cheers. 

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

×