Jump to content

Recommended Posts

I am stumped.

I can do: 

_veh addAction ["Center Turret", "turretdir.sqf"];

but get Invalid number in expression at the end of the line with: 

_veh addAction ["Center Turret", "turretdir.sqf", [] ];

which makes it impossible to do the full: 

_veh addAction ["Center Turret", "turretdir.sqf", [], 3, false, false, [], "(_allow_center_turret) && ((driver _veh) == player) && (call checkForGunnerSeat)"];

for some reason those inner square brackets break the whole thing! I can't even replace it with anything - I've tried 0nil"", other brackets..

Edit: this happens in both CBA's Extended Event Handler as well as putting it directly into the init.sqf.

Share this post


Link to post
Share on other sites

Another update - it now, inexplicably, (mostly) works, the day after. I changed allowCenterTurret to a global var after I found it working. 

// mission.malden\description.ext
class Extended_InitPost_EventHandlers
{
	class Helicopter
    {
      clientInit = "_this execVM 'centerTurret.sqf';";
    };
};
// mission.malden\centerTurret.sqf
_veh = _this select 0;
_veh addAction ["Center Turret", "turretdir.sqf", nil, 3, false, false, "", "(allowCenterTurret) && (call checkForGunnerSeat)"];

The above works perfectly, but I still need to check if the player executing the addAction is the driver. Yet with me in the pilot's seat and:

_veh addAction ["Center Turret", "turretdir.sqf", nil, 3, false, false, "", "(allowCenterTurret) && (call checkForGunnerSeat) && (driver _veh == player)"];

the action doesn't appear. Replacing _veh with vehicle player also doesn't work. Am I not seeing something?

Share this post


Link to post
Share on other sites

Okay it's done guys! Thanks so much for the help!

I had to change driver _veh == player out for another call

// mission.malden\centerTurret.sqf
_veh = _this select 0;
_veh addAction ["Center Turret", "turretdir.sqf", nil, 3, false, false, "", "(allowCenterTurret) && (call checkForGunnerSeat) && (call checkInDriverSeat)"];
// mission.malden\init.sqf
checkForGunnerSeat = compile preprocessFileLineNumbers "checkgunner.sqf";
checkInDriverSeat = compile preprocessFileLineNumbers "checkdriver.sqf";
allowCenterTurret = true;
// mission.malden\checkdriver.sqf
_is_player_driver = false;
if (driver vehicle player == player) then {
	_is_player_driver = true;
};

_is_player_driver;

I think I might publicly release this script after some more testing because I couldn't find anything like it earlier. 

Updating OP to the working script. 

Share this post


Link to post
Share on other sites

you could merge checkgunner.sqf and checkdriver.sqf and also implement the check for allowCenterTurret in the merged script. This way u only need one function call in ur addAction condition parameter.

 

also there is a syntax error in ur checkdriver.sqf. ther has to be no semicolon behind the return value _is_player_driver in the last line.

 

the complete merged script could look alike:

// mission.malden\check_allow_center_turret.sqf

_vec = vehicle player;

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

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

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

// return value if not exited before
allow_center_turret

I introduced exitWith there to prevent unnecessary checks.

 

EDIT:

according to this the return value can have or not have a semicolon. Maybe it was changed in the past 2 years :-)

"... Traditionally the returning statement is written without ";" after it. Have it or don't have it, it is up to you, doesn't make a blind bit of difference ..."

Share this post


Link to post
Share on other sites

I think u can calculate ur offset position just this way without the need of ur function:

 

_marker_position = _this modelToWorld [0, 5, 0]; // set position 5 metres ahead of vehicle position

 

Share this post


Link to post
Share on other sites

It works as intended with these optimisations, thank you for them. Only improvement I can think of is to move the marker with the heli, because right now you have to keep its position still.

Would it be better (performance and reliability) to attachTo a temporary invisible object in front of the heli, or to use a loop to update the marker position?

Share this post


Link to post
Share on other sites

loop solution could be this:

 

_sleeptime = time + 3;
waitUntil 
{
 sleep 0.1;
 _marker_name setMarkerPos ((vehicle _this) modelToWorld [0, 5, 0]);
 _this doWatch markerPos _marker_name;
 time >= _sleeptime
};

use it instead of ur doWatch and instead of ur sleep line

Share this post


Link to post
Share on other sites

Working well! There isn't a way to detect when the AI is looking at the marker is there, rather than using sleep? CursorTarget/Object is player-only.

Either way, thanks a lot for the help.

Share this post


Link to post
Share on other sites

maybe u r right and attachTo is a better solution. You could use the following commands to get a solution. Notice that this is not a script for use it just shows what u can use to get a script.

_pencil = "Land_PencilRed_F" createVehicle [0,0,0];
_pencil attachTo [_this, [0,5,0]];
_unit doTarget _pencil;
sleep 3;

 

there is a way to get the aiming direction of the gunner turret with weaponDirection but then u ve to deal with the direction vector and u ve to crawl the vehicles config for the name of the gunners weapon. I think a simple sleep 3; is much more simple.

 

EDIT: the weapon name can be got without config file using currentWeapon:

 

_weaponClass = currentWeapon (vehicle player);//Example: "M16A2GL"

 

EDIT2: above can be used to get the weapons direction vector:

 

_vec = vehicle _unit;
_dir_vector_gun = _vec weaponDirection (currentWeapon _vec);

 

EDIT3:

to get the direction vector of your entire vehicle u can use this:

 

_dir_vector_vec = vectorDir _vec;

now u r able to compare those 2 vectors and end the script if a minimum difference is reached.

 

LAST EDIT:

vector comparing could be done with vectorDistance. The whole thing could look like this:

 

_epsilon = 0.01; // minimum difference between vectors, may need adjustment
_vec = vehicle _unit;

_pencil = "Land_PencilRed_F" createVehicle [0,0,0];
_pencil attachTo [_vec, [0,5,0]];
_unit doTarget _pencil;

_sleeptime = time + 10; //just for safty to get no endless loop if something goes wrong
waitUntil 
{
 sleep 0.1;
 (time >= _sleeptime) || (((_vec weaponDirection (currentWeapon _vec)) vectorDistance (vectorDir _vec) ) < _epsilon)
};

detach _pencil;

// object deletion has to be done and object hiding as well

 

 

 

Share this post


Link to post
Share on other sites

Something like this I guess?

// mission.malden\inq\turretDir.sqf
0 = _turretUnit spawn {
	_this doWatch (vectorDir (vehicle _this));
	waitUntil {
		([(vehicle _this) weaponDirection (currentWeapon (vehicle _this))] call INQ_fnc_computeSourceDir) == ([vectorDir (vehicle _this)] call INQ_fnc_computeEndDir);
	};
};
// mission.malden\functions\fn_computeSourceDir
_SourceX = [_this select 0, 4] call BIS_fnc_cutDecimals;
_SourceY = [_this select 1, 4] call BIS_fnc_cutDecimals;
_SourceZ = [_this select 2, 4] call BIS_fnc_cutDecimals;
[_SourceX, _SourceY, _SourceZ]
// mission.malden\functions\fn_computeEndDir
_EndX = [_this select 0, 4] call BIS_fnc_cutDecimals;
_EndY = [_this select 1, 4] call BIS_fnc_cutDecimals;
_EndZ = [_this select 2, 4] call BIS_fnc_cutDecimals;
[_EndX, _EndY, _EndZ]

I haven't tested it yet. Is there a better way to round out the decimals to 4 places? 

Share this post


Link to post
Share on other sites

look at my last edit above :-)

 

EDIT: wait, there some mistakes ...

 

EDIT2: should be ok now

Share this post


Link to post
Share on other sites

Seeing what I can do with this, but something is wrong: 

// [] execVM "turretDir.sqf";
allowCenterTurret = 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 doWatch _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;
	allowCenterTurret = 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)
	allowCenterTurret = true; 													//	allow further instances of script
};

I'm getting an Invalid Number error after "_pencil = "Land_PencilRed_F" createVehicle [0,0,0];"

Share this post


Link to post
Share on other sites

post the full error message plz

 

EDIT: u already did: _veh = vehicle player; therefore u can delete _vec = vehicle _unit; and use _veh instead of _vec in the lines after that. but this is not the error

 

EDIT2: why do u do this?

if (_veh emptyPositions "gunner" > 0) then {

I would do the empty position check in ur condition check function. I do not see the sense in your else section

Share this post


Link to post
Share on other sites

Error:

Spoiler

Error in expression <Land_PencilRed_F" createVehicle [0,0,0];
_pencil allowDamage false;
_pencil h>
Error position: <

_pencil allowDamage false;
_pencil h>
Error Invalid number in expression
File <hidden>\mission.malden\inq\turretDir.sqf, line 20

 

Share this post


Link to post
Share on other sites

don't use doWatch cauz it needs a position. use doTarget cauz it tracks an object. then try again and tell if the error persists.

Share this post


Link to post
Share on other sites

I actually did change it to doTarget on the one I sent the error of (my only change) - it happens on both doTarget and doWatch

 

If I comment out only the waitUntil, I get the same error. 

If I comment out everything related to _pencil (leaving the waitUntil alone) I get:

Spoiler

Error in expression <time = time + 10;
waitUntil {
sleep 0.1;
(time >= _sleeptime) || (((_vec weap>
Error position: <

(time >= _sleeptime) || (((_vec weap>
Error Invalid number in expression
File <hidden>\mission.malden\inq\turretDir.sqf, line 28

And if I comment out everything related to _pencil as well as the waitUntil, there's no error. So it's somewhere in the lines of _pencil or waitUntil.

Dunno if that helps.

Share this post


Link to post
Share on other sites

I can't find a mistake. I ll leave for today and get back tomorrow.

the only thing I found for the error message is this.

 

pay attention on the difference of these lines:

Example: 
 this setobjecttexture [0,”\uns_army\data\1acav_co.paa”]; // simply won't work
 this setobjecttexture [0,"\uns_army\data\1acav_co.paa"];

maybe there is somewhere a similar tiny mistake in ur script ...

Share this post


Link to post
Share on other sites

I checked this line:

	_pencil = "Land_PencilRed_F" createVehicle [0,0,0];@

and I think u have a weird invisible special character after the semicolon.

Delete it and try again :-)

 

EDIT: its behind this line as well but there u have it 3 times:

	@_pencil allowDamage false;@@@

EDIT2:

you can check it with Word or some other app which is able to show invisible special characters.

I found it in those 2 lines too:

_unit doWatch _pencil;@
sleep 0.1;@

 

I marked it now with @ at all for lines. Now you should know where it is.

Share this post


Link to post
Share on other sites

Why do you need an addAction instead of a simple automatic code? (even if addAction is fine for that)

Share this post


Link to post
Share on other sites

Yep, for some reason those invisible characters were the cause of those errors. Works perfectly now. Unless you can think of any further optimisations I think that's all I can do. I will update OP with working script.

Share this post


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

Why do you need an addAction instead of a simple automatic code? (even if addAction is fine for that)

Automatic code? Like centring the turret when nobody's in the gunner seat?

Well TBH our server host doesn't have the best CPU so I would like to avoid as many loops as I can. 

Plus someone might have some obscure reason to keep it uncentered. 

Share this post


Link to post
Share on other sites

1. What is that extended eventhandler for (I've no CBA eperience) and what is centerTurret.sqf?
2. As I asked before, why don't u do the check for an empty gunner seat inside of fn_allowCenterTurret.sqf?
The only reason I can think of is the else section in turretDir.sqf but I don't know why u need it.
3. You could implement turretDir.sqf in your function library and use spawn INQ_fnc_turretDir to execute it.
4. I did not know that Multiplayer is a thing here so I like to know if it is a dedicated server or a server machine where your friend is playing on.
5. What pierremgi means with his post is to do everything with armas vanilla event handlers. This would not be more cpu consuming if implemented well.

Share this post


Link to post
Share on other sites

- I'm using CBA's Extended Event Handlers to load centerTurret.sqf onto anything with class Helicopter. 

- I don't want to look for an empty gunners seat because I want to still be able to use the action if an AI is in the seat (which is what the else in turretDir.sqf is for). FullCrew works well enough for this.

- Would there be any significant advantage to launching it as a function? I'm aware it will precompile it but I'm not sure if it would really do much for the script - it would only get use a few times a session at most. 
- Also yes, he runs a regular listen server (not the best decision, I know) for his discord group. He hasn't the hardware for dedicated and I haven't managed to convince him to let a few of us pay for server hosting. 

EDIT: I set the target of the AI to objNull (in the 'else') rather than follow the same script because if I did, after lining it up they'd just go back to an 'untargeted' state anyway.

Edited by PortalGunner

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

×