Jump to content
Sign in to follow this  
gnarly_rider

Nesting IF THEN ELSE statements?

Recommended Posts

OK folks, please be nice, this is literally my first ever script!

Basically I have an escaping general (assassination objective) who, upon BLUFOR detection, will attempt to escape in the nearest viable vehicle. This script therefore evaluates whether primary vehicle is functional, general runs to it and drives off. If vehicle disabled, goes to secondary and escapes.

Have tested, works fine.

BUT how do I implement the same method to a third or even fourth vehicle??? Tried nesting another if then else statement within second ELSE {..} section, and it returns an error. Obviously _vehicle3 is current unused for this reason......

PS any comments on making this better or doing it a better way much appreciated, this may be the bulldozer method for all I know!

// escape_vehicle.sqf
// November 2009 - Gnarly (zspecialunit.org)
/*
Places the escaping unit into the first viable  (i.e. functional) vehicle of 3 specified.
Put this in the init line of a waypoint in the editor: 
nul = [who, vehicle1, vehicle2, vehicle3] execVM "scripts\escape_vehicle.sqf";
*/


_who 		= _this select 0;
_vehicle1       = _this select 1;
_vehicle2     	= _this select 2;
_vehicle3	= _this select 3;


if (canmove _vehicle1 )then
{
_who domove getpos _vehicle1;
_who assignAsDriver _vehicle1;
[_who] orderGetIn true;
hint "veh1 good";

} else {
_who domove getpos _vehicle2;
_who assignAsDriver _vehicle2;
[_who] orderGetIn true;
hint "veh2 good";

};

Note: accidentally posted in Scripting (addons) forum as well...

Share this post


Link to post
Share on other sites

Make sure you define any variable used inside a "private" statement at the top of the script otherwise they loose definition inside nests.

Like;

private ["_who", "_vehicle1", "_vehicle2", "_vehicle3"];

Share this post


Link to post
Share on other sites

Related thread which is WAY over my head.... :)

http://forums.bistudio.com/showthread.php?t=88283&highlight=vehicle+escape

---------- Post added at 11:08 AM ---------- Previous post was at 11:01 AM ----------

Gnat;1491403']Make sure you define any variable used inside a "private" statement at the top of the script otherwise they loose definition inside nests.

Like;

private ["_who"' date= "_vehicle1", "_vehicle2", "_vehicle3"];

WOW it works!!! So simple, thanks Gnat!

Share this post


Link to post
Share on other sites

You could make an array of the all the vehicles, then use forEach. Note that the below example will hint the editorname of the vehicle.

_who		= _this select 0;
_vehicle1	= _this select 1;
_vehicle2	= _this select 2;
_vehicle3	= _this select 3;

_vehicles = [_vehicle1,_vehicle2,_vehicle3];

{
if (canMove _x) exitWith
{
	_who doMove getPos _x;
	_who assignAsDriver _x;
	[_who] orderGetIn true;
	hint format["%1 is good",_x];
};
} forEach _vehicles;

Share this post


Link to post
Share on other sites
You could make an array of the all the vehicles, then use forEach. Note that the below example will hint the editorname of the vehicle.

Thanks muchly Fincuan, much simpler!

However I will have to use the original script modified , as my primary vehicle will actually be a chopper with pilots standing by, so I need to be able to set the General as cargo for that particular case (as well as check whether at least one pilot is alive: chopper may be functional, but pilots have been killed hence voiding chopper as exfil option).

Just to be painful, during testing I note that if waypoint at which script is initiated is not close to valid vehicle, and this vehicle is incapacitated whilst general moving towards it, he basically ignores all other vehicles and runs off for final distant waypoint (the one he is supposed to drive to), rather than reassessing the remaining vehicle options. How would I continuously assess current designated vehicle, and redesignate if current is !(canmove)?

---------- Post added at 12:30 PM ---------- Previous post was at 11:29 AM ----------

OK penultimate version below, incorporating health checks on the two pilots. Check line is highlighted, seems to take upwards of 30 seconds for this line to be evaluated, before I'm sure there was barely a pause. I assume I've got the AI's knickers in a twist with some very inefficient looping?

// escape_vehicle.sqf
// November 2009 - Gnarly (zspecialunit.org)
/*
Places the escaping unit into the first viable  (i.e. functional) vehicle of 3 specified.
Put this in the init line of the item or waypoint in the editor: 
nul = [who, vehicle1, vehicle2, vehicle3] execVM "scripts\escape_vehicle.sqf";
*/

private ["_who", "_vehicle1", "_vehicle2", "_vehicle3"];

_who 		= _this select 0;
_vehicle1       = _this select 1;
_vehicle2     	= _this select 2;
_vehicle3	= _this select 3;


[color="Red"]if ((canmove _vehicle1 && alive pilot1) or (canmove _vehicle1 && alive pilot2))then[/color]
{
_who domove getpos _vehicle1;
_who assignAscargo _vehicle1;
[_who] orderGetIn true;
hint "veh1 good";

} else {
	if (canmove _vehicle2 )then
	{
	_who domove getpos _vehicle2;
	_who assignAsDriver _vehicle2;
	[_who] orderGetIn true;
	hint "veh2 good";

		} else {
		_who domove getpos _vehicle3;
		_who assignAsDriver _vehicle3;
		[_who] orderGetIn true;
		hint "veh3 good";

		}

	};

Share this post


Link to post
Share on other sites

you could change your nested if with a switch command..

something like this

switch (true) do {

   case ((canmove _vehicle1) && (alive pilot1 || alive pilot2)) :
   {
       _who domove getpos _vehicle1;
_who assignAscargo _vehicle1;
[_who] orderGetIn true;
hint "veh1 good";
   };
   case ((canmove _vehicle2) && (alive pilot1 || alive pilot2)) :
  {
       _who domove getpos _vehicle2;
_who assignAsDriver _vehicle2;
[_who] orderGetIn true;
  };
   default
   {
_who domove getpos _vehicle3;
_who assignAsDriver _vehicle3;
[_who] orderGetIn true;
hint "veh3 good";
   };
};

altho i have not tested this.

but switch works by breaking out when 1st true condition found in one of the cases.

so it can be used instead of nested if's

Share this post


Link to post
Share on other sites
Gnat;1491403']Make sure you define any variable used inside a "private" statement at the top of the script otherwise they loose definition inside nests.

Like;

private ["_who"' date= "_vehicle1", "_vehicle2", "_vehicle3"];

Now I'm confused. I thought private statements simply made a variable local to the current scope. I didn't think it made variables persist.

Share this post


Link to post
Share on other sites
Now I'm confused. I thought private statements simply made a variable local to the current scope. I didn't think it made variables persist.

Me too... I've never had to declare variables private just to use them in nested statements, that'd drive me insane. You should only need to declare them private if they might exist at a higher scope and you don't want to clobber them.

e.g.

_foo = "bar";
if (damage player > 0.5) then
{
 _foo = "baz";
};
hintSilent format["foo = %1", _foo];

will say "foo = bar" if the player is unhurt, or "foo = baz" if the player is seriously hurt. But if you didn't initialise/declare _foo before the if statement, the result would always be "foo = <ANY>" (or something like that) because _foo was defined at a lower scope (inside the if clause) and becomes undefined after that scope is closed.

Alternatively, you can use "private" to declare the variable without assigning it a value, so you can later use isNil to check if it was assigned a value at some point.

Share this post


Link to post
Share on other sites

To continue that a bit:

_foo = "bar";
if (damage player > 0.5) then
{
private["_foo"];
_foo = "baz";
};
hintSilent format["foo = %1", _foo]

This would always hint "foo = bar", because the _foo inside the inner scope is private to that scope, and is thus different from the _foo of the outer scope.

Share this post


Link to post
Share on other sites

hehehe ..... test on a couple of nest levels deep and you will see I speak the truth.

I know from a very recent bad experience ..... wasted #@#@%$# hours looking for the bug .... that wasn't really a bug.

Share this post


Link to post
Share on other sites

Please do provide an example script, because I for one have never seen such behaviour and would be interested to see it.

edit: 20 nested ifs and still working...

_testvar = "Yay! We reached the bottom!";
if (true) then
{
if (true) then
{
	if (true) then
	{
		if (true) then
		{
			if (true) then
			{	
				if (true) then
				{
					if (true) then
					{
						if (true) then
						{
							if (true) then
							{
								if (true) then
								{
									if (true) then
									{
										if (true) then
										{
											if (true) then
											{
												if (true) then
												{
													if (true) then
													{	
														if (true) then
														{
															if (true) then
															{
																if (true) then
																{
																	if (true) then
																	{
																		if (true) then
																		{
																			hint _testvar;
																		};
																	};
																};
															};
														};
													};
												};
											};
										};
									};
								};
							};
						};
					};
				};
			};
		};
	};
};
};

Edited by Fincuan

Share this post


Link to post
Share on other sites

i think the problem gnat might have had is that he defined a variable inside a scope and tried to access it outside the scope. which cant be done without using private..

if (true) then
{
_a =+ 1;
hint format["In 1st Scope A == %1",_a];
sleep 2;
if (true) then
{	
	_a = _a + 1;
	hint format["In 2nd Scope A == %1",_a];
};
sleep 2;
hint format["In 1st Scope A == %1",_a];
};
sleep 2;
hint format["In NO Scope A == %1",_a];

this example code will hint out the value _a fine inside the scopes.. but as soon as it exits the 1st scope it was used in, it has no meaning. value _a becomes any value

so if you put on top

private ["_a"];

it will also hint out the value of _a outside the scopes

Edited by nuxil

Share this post


Link to post
Share on other sites

so if you put on top

private ["_a"];

it will also hint out the value of _a outside the scopes

This, or define _a outside the scope, which the OP did. Both work equally well in this case and even without "private[...]" at the start you won't lose the variables when going inside the "nests".

Share this post


Link to post
Share on other sites

i already know that,, my example was a response to your 20 nested if. showing it can cause problems if not used..

i also dont like to use Private.. 99.9% of my scripting i do it without private.

anyway this private discussion has become a bit offtopic.. so i think my switch solution is best in respons to the OP :p

Share this post


Link to post
Share on other sites
Now I'm confused. I thought private statements simply made a variable local to the current scope. I didn't think it made variables persist.

Confused too.

Just had a test with this and it works (hints "Hello Chernarus!", "1st Hello Chernarus!", "2nd Hello Chernarus!")

_text = "Hello Chernarus!";
_i = 1;
hint format ["%1", _text];
while {_i < 3} do {
sleep 1;
hint "while";
if (_i == 1) then {
	hint format ["%1st %2", _i, _text];
} else {
	hint format ["%1nd %2", _i, _text];
};
_i = _i + 1;
};
sleep 1;
hint "done";

I called it from the init line of my player.

However, I'm pretty sure (not 100%) that I wrote it like that the first time I tried, and I would only get the first hint, and nothing else.

I then tried around a bit and finally came back to this version.

Another thing I noticed that if you don't put the closing paranthesis to the else part, like this

_text = "Hello Chernarus!";
_i = 1;
hint format ["%1", _text];
while {_i < 3} do {
sleep 1;
hint "while";
if (_i == 1) then {
	hint format ["%1st %2", _i, _text];
} else {
	hint format ["%1nd %2", _i, _text];

_i = _i + 1;
};
sleep 1;
hint "done";

there will only the be the first hint again, and nothing else.

Now the strange thing for me is, that I have added -showScriptErrors, no errors showing on the screen and no errors in arma2.rpt!!!

Some further testing shows that

_text = "Hello Chernarus!";
_i = 1;
f*cken;
hint format ["%1", _text];
while {_i < 3} do {
sleep 1;
hint "while";
if (_i == 1) then {
	hint format ["%1st %2", _i, _text];
} else {
	hint format ["%1nd %2", _i, _text];
};
_i = _i + 1;
};
sleep 1;
hint "done";

will throw also no errors and runs as it "should", this

_text = "Hello Chernarus!";
_i = 1;
f*cken;
while it is fun keep on going;
hint format ["%1", _text];
while {_i < 3} do {
sleep 1;
hint "while";
if (_i == 1) then {
	hint format ["%1st %2", _i, _text];
} else {
	hint format ["%1nd %2", _i, _text];
};
_i = _i + 1;
};
sleep 1;
hint "done";

shows an error like "while it |#|is fun keep on going; : error missing ; blabla"

Share this post


Link to post
Share on other sites
Another thing I noticed that if you don't put the closing parenthesis to the else part [...] there will only the be the first hint again, and nothing else.

Now the strange thing for me is, that I have added -showScriptErrors, no errors showing on the screen and no errors in arma2.rpt!!!

The parser is an interesting beast. I had the same thing happen when I forgot to terminate a string - the first part of the code ran, then nothing after that did, but no errors reported. Took me a while to spot the missing ". The strange thing is there were other strings in the code, which should have terminated the missing one and then confused the heck out of the interpreter.

Maybe when it reaches the end of the file it just throws away any statements it currently has in its buffer, without warning about it?

Some further testing shows that

_text = "Hello Chernarus!";
_i = 1;
f*cken;
hint format ["%1", _text];

will throw also no errors and runs as it "should", this

_text = "Hello Chernarus!";
_i = 1;
f*cken;
while it is fun keep on going;
hint format ["%1", _text];

shows an error like "while it |#|is fun keep on going; : error missing ; blabla"

I think also that syntactically correct things won't trigger errors; the scripting engine tries its best to just keep running even if you do strange things like multiply two non-existent variables together and throw away the result (which is what f * cken is doing).

The line that starts with 'while' triggers extra grammar rules, and since the sentence doesn't fit the correct structure of a 'while' loop it complains.

This has gone way off-topic... did gnarly rider get the info they were looking for? :)

Share this post


Link to post
Share on other sites

LMAO!

I did never fear, though I am perplexed why with any of the initial chopper +/- checks, why it takes about 43 seconds (measured multiple times) for the general to evaluate when the chopper or pilots are invalid, and take the second vehicle instead. If the chopper and 1 pilot is viable, the decision is made within about 7 seconds

Using either of these options has the same evaluation time.

if ((canmove _vehicle1 && alive pilot1) or (canmove _vehicle1 && alive pilot2))then

OR

((canmove _vehicle1) && (alive pilot1 || alive pilot2)

Also

Just to be painful, during testing I note that if waypoint at which script is initiated is not close to valid vehicle, and this vehicle is incapacitated whilst general moving towards it, he basically ignores all other vehicles and runs off for final distant waypoint (the one he is supposed to drive to), rather than reassessing the remaining vehicle options. How would I continuously assess current designated vehicle, and redesignate if current is !(canmove)

Neither of these two issues are terminal, just trying to make it better! But the ongoing dialogue has been interesting, though way over my head...

Share this post


Link to post
Share on other sites

im not sure what youre doing in your mission. it shouldnt take that long to evaluate the condition.

this example.. this is done in about 1 second.

// unit that should get in as cargo.
//[unit,car1,car2,car3] execvm "test.sqf":

_who = _this select 0;
_vehicle1 = _this select 1;
_vehicle2 = _this select 2;
_vehicle3 = _this select 3;

sleep 1;
switch (true) do 
{
   case ((CanMove _vehicle1) && alive Driver) :
   {
	Driver  domove getpos _vehicle1;
	Driver assignAsDriver _vehicle1;
	[Driver] orderGetIn true;

	_who domove getpos _vehicle1;
	_who assignAscargo _vehicle1;
	[_who] orderGetIn true;
	hint "veh1 good";
   };
   case ((canmove _vehicle2) && alive Driver) :
  {
  		Driver  domove getpos _vehicle2;
	Driver assignAsDriver _vehicle2;
	[Driver] orderGetIn true;

               _who domove getpos _vehicle2;
	_who assignAscargo _vehicle2;
	[_who] orderGetIn true;
  };
  case ((canmove _vehicle3) && alive Driver) :
  {
  		Driver  domove getpos _vehicle3;
	Driver assignAsDriver _vehicle3;
	[Driver] orderGetIn true;

               _who domove getpos _vehicle3;
	_who assignAscargo _vehicle3;
	[_who] orderGetIn true;
  };
   default
   {
	hint "omfg no vehciles to take a ride in. Did someone kill my Driver ??";
   };
};

i placed me. 1 unit called test and one i called Driver. + 3 cars i called b1,b2 and b3..

i trigger the script by radio..

Edited by nuxil

Share this post


Link to post
Share on other sites

How are you determining the evaluation times? Are you killing off the pilots and then seeing how long it takes your general to decide to use another transport method?

If so, I think I know why you're such a delay; I noticed this myself a few days ago and added it to the talk page for alive on the wiki, but it didn't click for me when I was reading your description.

Essentially, 'alive' returns true if the group in question thinks the unit is alive. If you kill a group rapidly, or kill the last group member, it takes a long time for anyone to notice they're dead. You might have seen this effect when playing: one of your team mates can go down, but it takes a while to be reported. The 'alive' function will only return false after that report has occurred.

You might want to try replacing your "alive unit" checks with "damage unit < 1.0" and see what result you get. The 'damage' command returns the actual amount of damage the unit has at that moment.

Share this post


Link to post
Share on other sites

@nuxil

Basically, the general has 3 waypoints, the second waypoint has the script in its on activation line. I tried your script last night, and the processing time on this for certain cases is still 30 odd seconds at times. Chopper has two pilots (modified your script to accommodate both pilots ie chopper is till viable if one pilot alive) with their own separate waypoints, the load command of which is syned to the general geing onboard. General is driver for backup vehicles.

@some kind of guy

Basically I sit their as a captive SMAW man, and check each permutation.

1/. Does gerneral get in chopper when all AOK -fast

2/. Blow chopper (and nearby pilots) up with SMAW- long evaluation time

3/. Kill just one pilot;

4/. Kill both pilots

5/. Damage chopper but pilots OK

6/. Then in tandem with above, disbale or destroy hevicles 2 and /or 3 to see if following cases enacted correctly

I'll recheck in a few days(be away for a the weekend) but case 2 above is almost always 20-40 seconds while the generla pauses at WP 2 and takes forever to relise that the chopper and both pilots are dead, therefore goto vehcile 2.. I'll also give you rsuggestion a go. C

Cheers muchly guys

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  

×