Jump to content

Photo
- - - - -

Nesting IF THEN ELSE statements?


  • Please log in to reply
23 replies to this topic
Thread Starter
gnarly_rider
gnarly_rider

    Staff Sergeant

  • Members
  • 319 posts

Posted 17 November 2009 - 10:54 #1

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...

-APS-Gnat
-APS-Gnat

    Captain

  • Members
  • 6401 posts

Posted 17 November 2009 - 10:59 #2

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"];
Posted Image

Thread Starter
gnarly_rider
gnarly_rider

    Staff Sergeant

  • Members
  • 319 posts

Posted 17 November 2009 - 11:08 #3

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


http://forums.bistud...=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", "_vehicle1", "_vehicle2", "_vehicle3"];


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

Fincuan
Fincuan

    Staff Sergeant

  • Members
  • 335 posts

Posted 17 November 2009 - 11:11 #4

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;


Thread Starter
gnarly_rider
gnarly_rider

    Staff Sergeant

  • Members
  • 319 posts

Posted 17 November 2009 - 12:30 #5

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";
		
			}
		
		};


nuxil
nuxil

    Sergeant Major

  • Members
  • 1606 posts

Posted 17 November 2009 - 12:57 #6

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

deadfast
deadfast

    Moderator

  • 3175 posts

Posted 17 November 2009 - 13:18 #7

I don't think the above will work.

Fincuan
Fincuan

    Staff Sergeant

  • Members
  • 335 posts

Posted 17 November 2009 - 13:24 #8

Looks completely fine to me

Thread Starter
gnarly_rider
gnarly_rider

    Staff Sergeant

  • Members
  • 319 posts

Posted 17 November 2009 - 20:48 #9

Cheers, will give it a try!

tcp
tcp

    Gunnery Sergeant

  • Members
  • 435 posts

Posted 18 November 2009 - 02:01 #10

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", "_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.

nomdeplume
nomdeplume

    Gunnery Sergeant

  • Members
  • 502 posts

Posted 18 November 2009 - 05:15 #11

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.

Fincuan
Fincuan

    Staff Sergeant

  • Members
  • 335 posts

Posted 18 November 2009 - 12:17 #12

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.

-APS-Gnat
-APS-Gnat

    Captain

  • Members
  • 6401 posts

Posted 18 November 2009 - 12:33 #13

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.
Posted Image

Fincuan
Fincuan

    Staff Sergeant

  • Members
  • 335 posts

Posted 18 November 2009 - 13:01 #14

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, 18 November 2009 - 13:16.


nuxil
nuxil

    Sergeant Major

  • Members
  • 1606 posts

Posted 18 November 2009 - 14:55 #15

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, 19 November 2009 - 13:25.


-APS-Gnat
-APS-Gnat

    Captain

  • Members
  • 6401 posts

Posted 18 November 2009 - 15:15 #16

Thanks nuxil ;)
Posted Image

Fincuan
Fincuan

    Staff Sergeant

  • Members
  • 335 posts

Posted 18 November 2009 - 15:57 #17

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".

nuxil
nuxil

    Sergeant Major

  • Members
  • 1606 posts

Posted 18 November 2009 - 16:13 #18

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

schaefsky
schaefsky

    Sergeant

  • Members
  • 121 posts

Posted 18 November 2009 - 20:23 #19

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"

nomdeplume
nomdeplume

    Gunnery Sergeant

  • Members
  • 502 posts

Posted 19 November 2009 - 05:41 #20

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? :)