Jump to content

Recommended Posts

Posted (edited)

Hi there,

It's quite annoying when someone else has used the gunner seat of a Heli, offsetting its position, and you later decide to Manual Fire from the pilot's seat and have a misaligned gun.

I've been putting a lot of effort into setting up a script that can deal with this via a User Action, however I'm getting a few errors. A few of them are about missing " ) ", " ] ", " ; " (though I have done my best to never leave these out, including using a bracket checker plugin), or invalid variables (which is probably because it's checking a variable before it's set).

 

To summarise, when a player pilot is in an armed Heli, they shall get a user action to centre the turret. This will have either the current AI or a temporary, invisible AI in the gunner seat target a spawned marker in front of the vehicle (if a player is in the seat it won't affect them). I currently have five six files in relation to this. 

 

EDIT: Below has been updated to the latest working script - If you get errors make sure there's no invisible characters using Word

It requires CBA

 

mission.Malden\init.sqf

Spoiler

if ((!isServer) && (player != player)) then {waitUntil {player == player};};

allowCentreTurret = true;

 

 

mission.Malden\description.ext

Spoiler

class Extended_InitPost_EventHandlers
{
	class Helicopter
    {
		clientInit = "_this call INQ_fnc_centreTurret;";
    };
};
class CfgFunctions
{
	#include "functions\functions.hpp"
};

 

 

mission.Malden\functions\functions.hpp

Spoiler

class INQ
{
	tag = "INQ";
	class functions
	{
		file = "functions";
		class allowCentreTurret {};
		class centreTurret {};
		class turretDir {};
	};
};

 

 

mission.Malden\functions\fn_centreTurret.hpp

Spoiler

_veh = _this select 0;
_veh addAction ["Centre Turret", INQ_fnc_turretDir, nil, 1, false, false, "", "call INQ_fnc_allowCentreTurret"];

 

 

mission.Malden\functions\fn_allowCentreTurret.sqf

Spoiler

_vec = vehicle player;

//exit and return false if player is not driver
if !(driver _vec == player) exitWith {false};

_turrets = fullCrew [_vec, "gunner", true];

//exit and return false if vehicle has no gunner seat
if (count _turrets == 0) exitWith {false};

//exit and return false if a player is gunner
if (isPlayer (gunner _vec)) exitWith {false};

// return value if not exited before
allowCentreTurret

 

 

mission.Malden\functions\fn_turretDir.sqf

Spoiler

allowCentreTurret = false;														//	disallow further instances of script
_veh = vehicle player;															//	set current player's vehicle as script object

if (_veh emptyPositions "gunner" > 0) then {									//	check if the gunner seat is empty
	_group = createGroup civilian;												//	if so create a temporary unit to fill slot
	_group deleteGroupWhenEmpty true;
	_unit = _group createUnit ["B_Soldier_F", position _veh, [], 50, "NONE"];
	_unit setCaptive true;
	_unit allowDamage false;
	_unit hideObjectGlobal true;
	_unit setSpeaker "NoVoice";
	_unit setName "Turret Control";
	_unit assignAsGunner _veh; 													//	move the temporary unit to gunner seat
	_unit moveInGunner _veh; 

	_epsilon = 0.001; 															// minimum difference between vectors
	_vec = vehicle _unit;
	
	_pencil = "Land_PencilRed_F" createVehicle [0,0,0];
	_pencil allowDamage false;
	_pencil hideObjectGlobal true;
	_pencil attachTo [_vec, [0,5,0]];
	_unit doTarget _pencil;
	
	_sleeptime = time + 10;
	waitUntil {
		sleep 0.1;
		(time >= _sleeptime) || (((_vec weaponDirection (currentWeapon _vec)) vectorDistance (vectorDir _vec)) < _epsilon);
	};
	deleteVehicle _unit;														//	remove temporary unit
	deleteVehicle _pencil;
	allowCentreTurret = true;													//	allow further instances of script
} else {																		//	if the gunner seat is NOT empty
	_unit = gunner _veh;														//	set current gunner (AI/player) as script object
	_unit doWatch objNull;														//	order unit to watch nothing (defaults to forward)
	allowCentreTurret = true; 													//	allow further instances of script
};

 

 

Currently, unit spawning, marker generation and AI watching are working as intended, however the user action does not appear and if i set off turretdir.sqf manually ( [] execVM "turretdir.sqf"; ) it errors. 

EDIT: All working as intended.

I'm not as proficient at SQF scripting as I'd like to be, so I've probably made some very obvious mistakes. Any help setting this up correctly and optimising would be appreciated. I will keep trying in the meantime. 

Edited by PortalGunner
updated scripts

Share this post


Link to post
Share on other sites

I was off of scripting a long long time but I think the following line is wrong:

 

_centerTurret = player addAction ["Center Turret","turretdir.sqf",[], 7, true, true, "", "(_allow_center_turret) && (driver vehicle player == player) && (vehicle player isKindOf Helicopter) && ((!isNull gunner vehicle player) || (vehicle player emptyPositions "gunner">0))"];

 

look at isKindOf - there the typeName is embraced in quotation marks. therefore that part should be:

(vehicle player isKindOf "Helicopter")

 

Share this post


Link to post
Share on other sites

Thank you, that has gotten rid of one error.
~I've edited the post with proper quotations (and one random ; near the end of the line)
I'm still getting an Invalid number in expression at the end of that line unfortunately.

Share this post


Link to post
Share on other sites

If im not mistaken, it has to do with the condition of the AddAction.

 

(_allow_center_turret) && (driver vehicle player == player) && (vehicle player isKindOf Helicopter) && ((!isNull gunner vehicle player) || (vehicle player emptyPositions "gunner">0))

A && B && C && D || E

 

that simply won´t work. If you want it to work then you need 1 more pair of ():

 

(A && B && C && D )|| E

 

this way you get a real OR condition.

 

im not in arma currently to test this but this got my attention.

Share this post


Link to post
Share on other sites
Just now, ofp_f3d3 said:

If im not mistaken, it has to do with the condition of the AddAction.

 


(_allow_center_turret) && (driver vehicle player == player) && (vehicle player isKindOf Helicopter) && ((!isNull gunner vehicle player) || (vehicle player emptyPositions "gunner">0))

A && B && C && D || E

 

that simply won´t work. If you want it to work then you need 1 more pair of ():

 

(A && B && C && D )|| E

 

this way you get a real OR condition.

 

im not in arma currently to test this but this got my attention.


As I count the brackets it is
A && B && C && (D || E)
unless that's somehow not supported?
>n<

Share this post


Link to post
Share on other sites
Posted (edited)

I'm also getting a missing ) bracket error after _turretVehicle)

if ((getPosATL _turretVehicle) select 2 < 2) then {

in turretdir.sqf

Edited by PortalGunner
formatting that should've been there

Share this post


Link to post
Share on other sites
if ((getPosATL _turretVehicle)# select 2 < 2) then {
in turretdir.sqf

the # isn´t needed. Also you´ll get an error with "in turretdir.sqf" because the IN expects a value first.

 

https://community.bistudio.com/wiki/in

 

IN is used to check if a value is inside an array.

Share this post


Link to post
Share on other sites
7 minutes ago, ofp_f3d3 said:

if ((getPosATL _turretVehicle)# select 2 < 2) then {
in turretdir.sqf

the # isn´t needed. Also you´ll get an error with "in turretdir.sqf" because the IN expects a value first.

 

https://community.bistudio.com/wiki/in

 

IN is used to check if a value is inside an array.

I'm sorry if I should have been clearer - the # was just to demonstrate where editor debug thinks there's a problem, and I was stating the file name of the .sqf file the error occurred in. 
I did format that message but it seems it didn't take 😕

Share this post


Link to post
Share on other sites

i just tried writing this to check whats wrong in the syntax:

 

if ((getPosATL vehicle player) select 2 < 2) then { hint "hello";};

 

somehow this works, but i can´t see why yours wont work, sorry if this isn´t very helpful

Share this post


Link to post
Share on other sites

why do u do this?

		if ((getPosATL _turretVehicle) select 2 < 2) then {					//	check if vehicle is not in flight
			(vehicle _this) engineOn false;
		};

it just turns the engine off automatically below 2 meters but this has nothing to do with the intention of ur script.

 

also I don't understand this condition in ur addAction:

(!isNull gunner vehicle player) || (vehicle player emptyPositions 'gunner'>0)

this is true if gunner seat is manned OR if the gunner seat has an empty position

 

Also the following is ur whole condition just simplified for readability:

"(A) && (B) && (C) && ((!isNull gunner vehicle player) || (vehicle player emptyPositions 'gunner'>0));"
											

the semicolon at the end of that condition is wrong because a condition has not to be closed with a semicolon.

 

Share this post


Link to post
Share on other sites
Just now, ofp_f3d3 said:

somehow this works, but i can´t see why yours wont work, sorry if this isn´t very helpful

I appreciate that you've taken the time to respond anyway.

I've messed around a bit with it and I think it might be looking for a ) bracket from something earlier in the script? I can't tell what though. 
Even if, in turretdir.sqf, I change 

if (vehicle player emptyPositions "gunner" > 0) then {

to

if ((vehicle player) emptyPositions "gunner" > 0) then {

like I did with the other uses of it in init.sqf,
it still doesn't fix it - and there's no other () bracket codes above the error in turretdir.sqf.

Share this post


Link to post
Share on other sites

afaik in some cases bracket errors r able to continue across borders. this means the error could be in a prior script.

Share this post


Link to post
Share on other sites
10 minutes ago, sarogahtyp said:

it just turns the engine off automatically below 2 meters but this has nothing to do with the intention of ur script.

The AI gunner spawned to aim the turret may turn the engine on (because they're stupid) if it's done on the ground - so I want to turn it off again - but if you're flying and you run the script, it will still turn your engine off. So that if argument is to make sure that the engine isn't switched off when you're still flying the heli - because that would end.. poorly.

(!isNull gunner vehicle player) || (vehicle player emptyPositions 'gunner'>0)

As for that ^ I'm trying to detect if the vehicle has a gunner seat at all, it's been hard to find a coherent explanation of how. 

 

10 minutes ago, sarogahtyp said:

the semicolon at the end of that condition is wrong because a condition has not to be closed with a semicolon.

I added the semicolon at the end of the condition only because it seemed to satisfy the editor debug. 

 

4 minutes ago, sarogahtyp said:

afaik in some cases bracket errors r able to continue across borders. this means the error could be in a prior script.

So the error could be in init.sqf still 😕
Thanks for the feedback so far. 

Share this post


Link to post
Share on other sites
Posted (edited)

I'm posting what I've found in the .rpt log here:
Errors:

Spoiler

 Error in expression <layer) emptyPositions 'gunner' > 0));"];


0 = [] spawn {
while {true}
>
   Error position: <


0 = [] spawn {
while {true}
>
   Error Invalid number in expression
 File <hidden>\mission.malden\init.sqf, line 17

Spoiler

 Error in expression <sleep 3; 
if ((getPosATL _turretVehicle) select 2 < 2) then {                    
(vehicle _
>
   Error position: < select 2 < 2) then {                    
(vehicle _
>
   Error Missing )
 File <hidden>\mission.malden\turretdir.sqf, line 27

Edited by PortalGunner
put the ones from most recent run!

Share this post


Link to post
Share on other sites

first error:

"gunner" has to be 'gunner' because this is not allowed:

 

" ... "gunner" ..."

but this is allowed

" ... 'gunner' ..."

 

but the error message is not representing ur posted code for init.sqf in OP. There u did it correct...?

 

EDIT: I think u posted different error messages from different builds?

first u ve this:

 Error in expression <r) || ((vehicle player) emptyPositions "gunner">0))"];

 

then this:

Error in expression <layer) emptyPositions 'gunner' > 0));"];

 

both is the same line but different syntax.

Share this post


Link to post
Share on other sites

here is a script where I detected if a turret is a gunner seat but it is not very easy because its doing a lot more stuff.

the key to check for a gunner seat is to use the fullCrew command.

If I ve the time then I ll do a simple version to detect the gunner seat only.

Share this post


Link to post
Share on other sites

Yes I didn't realise the log was recording multiple mission starts as I was skimming through. I've now edited the errors and the OP script correctly. Real sorry for that mess-up 😓

I'll check out FullCrew in a sec - if you can find that time that'd be awesome. 

Share this post


Link to post
Share on other sites

gunner_seat_check.sqf

// example script, not tested, just to show how it could work to detect an empty gunner seat.

_empty_gunner_pos_available = false;

_vec = vehicle player;

_turrets = fullCrew [_vec, "gunner", true];

if (count _turrets > 0) then
{
 if(_vec emptyPositions "gunner" > 0) then
 {
  _empty_gunner_pos_available = true
 };
};

_empty_gunner_pos_available

the script creates an array of all vehicle turrets which are marked as gunner turret. each vehicle can have only one turret which is marked as gunner!

then it uses emptyPositions as u already did to detect if that gunner position is empty.

  • Thanks 1

Share this post


Link to post
Share on other sites
Posted (edited)
24 minutes ago, sarogahtyp said:
Spoiler


// example script, not tested, just to show how it could work to detect an empty gunner seat.

_empty_gunner_pos_available = false;

_vec = vehicle player;

_turrets = fullCrew [_vec, "gunner", true];

if (count _turrets > 0) then
{
 if(_vec emptyPositions "gunner" > 0) then
 {
  _empty_gunner_pos_available = true
 };
};

_empty_gunner_pos_available

 

the script creates an array of all vehicle turrets which are marked as gunner turret. each vehicle can have only one turret which is marked as gunner!

then it uses emptyPositions as u already did to detect if that gunner position is empty.

 

So I assume this will work something like this (below) for my intentions?

_vec = vehicle player;
_turrets = fullCrew [_vec, "gunner", true];

// below is simplified
_centerTurret = player addAction ["Center Turret", "turretdir.sqf", [], 7, true, true, "", "(A) && (B) && (C) && (count _turrets > 0);";

Edit: Hang on I just realised that's only gonna run once because it's in init.sqf
I guess I could add the first 2 lines inside the While in init.sqf? Or am I overthinking and it isn't necessary? -~-

Edited by PortalGunner

Share this post


Link to post
Share on other sites

I would do a script of it and call that inside of ur addAction condition. R u familiar with how to compile scripts for usage with call ?

Share this post


Link to post
Share on other sites

in init.sqf u just compile a function out of the script:

checkForEmptyGunnerSeat = compile preprocessFileLineNumbers "gunner_seat_check.sqf";

after that u can call the function in ur condition:

 

_centerTurret = player addAction ["Center Turret", "turretdir.sqf", [], 7, true, true, "", "(_allow_center_turret) && (driver vehicle player == player) && (vehicle player isKindOf 'Helicopter') && (call checkForEmptyGunnerSeat)"];

 

EDIT:

for clarification u should read about these commands:

compile

preprocessFileLineNumbers

call

spawn

 

also u should know about the Scheduler to get an idea what should be called, spawned or execVMed when and where:

 

Share this post


Link to post
Share on other sites

init.sqf: 

checkForGunnerSeat = compile preprocessFileLineNumbers "checkgunner.sqf";
_allow_center_turret = true;

// Below is simplified 
_centerTurret = player addAction ["Center Turret", "turretdir.sqf", [], 7, true, true, "", "(A) && (B) && (C) && (call checkForGunnerSeat);"];

checkgunner.sqf:

_gunner_pos_available = false;
_vec = vehicle player;
_turrets = fullCrew [_vec, "gunner", true];
if (count _turrets > 0) then {
	_gunner_pos_available = true;
};

_gunner_pos_available;

Like such? Also yes, I'm just trying to find any gunner seat, not just empty. 

Share this post


Link to post
Share on other sites

yes but don't do that semicolon at the end of ur condition in addAction! A condition never has a semicolon at its end.

 

B) && (C) && (call checkForGunnerSeat);"];    <<< red is wrong

Share this post


Link to post
Share on other sites
Posted (edited)

It looks good, and the editor debug isn't throwing a fit about that semicolon anymore. Unfortunately the two errors I posted earlier are still occurring. As such the user action isn't showing up in pilot's seat and turretdir.sqf doesn't run properly. 

 

PS. Is there any need for my entire While loop in my init.sqf or does addAction already take care of that?

Edited by PortalGunner

Share this post


Link to post
Share on other sites

Okay I have turretdir.sqf working (though its strange because it lost the variables halfway through), and I've tried moving the addAction to an Extended Event Handler (the mission already required CBA which adds these). The only problem now seems to lie in the conditions of the addAction, because if I remove all the conditions it works, and fires turretdir.sqf

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

×