Page 1 of 2

Questions regarding moving AI and syntax of IF statement....

Posted: Wed Jun 25, 2003 1:00 am
by grb
Hi all,
I have a part question.
Q1: How should I interprete the "bat sign" when used in IF statements?
Q2: How can I make a AI move from it's spawn point to a pathway that I assign a target name?

OK. Now concerning the first question. When I test to see if a AI is alive I thought I do something like this. Of course the AI has a targetname etc..
The following is what you would see in a thread that I call from the main
program once friendlies and player are given weapons, etc..

move_tom:
if (isAlive level.tom)
{
iprintln "got this far"
level.tom runto $pn1
}

OK. Now when I run the game I do not get any error messages in the logfile. BUT, I neither see tom move to the targeted pathnode pn1 NOR
do I see any message pop up on the screen.

OK. Now if I change the if test parameter to read:

if !(isAlive level.tom)

Then I see the "got this far" message pop up on the screen.

NOW, if I understand the if statement syntax correctly, AND ALSO WHAT I SEE IN VARIOUS SCRIPT FILES FROM THE GAME......

Putting the "!" sign in front of the IF statement expression as you see above should TEST TRUE IF tom was dead, and therefore execute the statements within the IF statement. BUT this is not what I see here.
The only way I get the "got this far" text to show on the screen is if the
IF test returns senses that tom is dead.....which is not true...he is alive
and standing close to me in the game.

SO...... can some one set me straight on what the "!" sign does here?
Also in direct line with this I want to eventually test to see if a AI is dead,
AND then move another player to a given spot. Therefore I assumed that
the "!" placed in front of the test expression brackets, again like this....

if !(isAlive level.tom) would mean that if tom where dead then the statements would be carried out in the test statement, otherwise nothing would happen.

OK, if you have followed me this far, let me also say this..... If I test to see if tom is alive by writting:
if (isAlive level.tom) I GET NO ERRORS IN THE LOGFILE. BUT
NOTHING HAPPENS.
If I write the code as:
if !(isAlive level.tom) I get the iprintln test message BUT he does not
move.
AND WHEN WRITTEN WITH THE BAT SIGN, I GET THE FOLLOWING ERRORS IN THE LOGFILE:


level.tom runto $friendhide (maps/test_grb1.scr, 81)
level.tom ^

^~^~^ Script Error: command 'runto' applied to NIL


This is confusing as hell. He is alive but the test statement when testing to see if he is alive does not work, but seems to work if I test for if he is dead.



OK. For the second question. Is the command line correct in this thread
for moving the AI from his spawn point or for that matter whereever he would be at a given time, to a targeted PathNode?

I have tried for a few hours to make sure I have set mindist, maxdist, leash, etc.., to all type combos to see if they where preventing him from moving, with no success. Of course it would appear that the first question
regarding the IF statement syntax must be understood in order to expect
the guts of the if test statements to run correctly.

thanks for any help on these questions. I am being verbose to make sure
anyone that might help understands that I have set the targetname of the pathnode correctly, and as you see above, appear to be using the IF
statement correctly. Incidentally, when I use the IF statement for setting up a friendly player, it works the way I would expect it to. That is, the
guts of the IF statement get executed if the AI is alive, put another way,
the IF statement returns a TRUE to the command: if (isAlive level.friendly.1).

thanks in advance for any help....

Posted: Wed Jun 25, 2003 1:16 am
by nuggets
lol, you didn't miss much out in that post :P

! = not so you were right in that bit

i think and i'm not thinking too much now cos it's 2am, but
have you defined level.tom as a defined player???
i.e.

level.tom = $tom

if not then that'd be the reason for both errors :D

if not i'll have another think tomorrow if some1 else hasn't solved this

Posted: Wed Jun 25, 2003 1:30 am
by Alcoholic
command "runto" applied to NIL means this... the line could not find the "listener" (in this case level.tom).

what is the name of your friendly. what i want you to type is the exact copied name from his properties in mohradiant.

after you setup a friendly, his name in the script is "level.friendlyX" where X is the #fnum you assigned him.

FROM THERE, to give him a different name in the script, you type level.newname = level.friendlyX make sure the newname is on the left and the oldname is on the right...

the ! conditional simply means "the opposite". so if you had

Code: Select all

if ($sniper cansee $snipee)
   println "diediedie"
    end
if you put a ! before the (, it would ask "can the sniper NOT see the snipee?"

thanks nuggets and alcoholic for your response....

Posted: Wed Jun 25, 2003 3:54 am
by grb
OK guys. I got everthing to work. Not to confuse things. I originally had
an AI following me about, friendly =1 mode. What I had did was add
another AI which I was discussing in this thread. I wanted him to first
run to a rock and duck then after he and the original AI helped me shoot
up all visible baddies, then follow the first AI guy around as the first AI
followed me around. ALL IS WORKING CORRECTLY NOW.

Alcoholic, the changes are two much to bother you with, since again,
I had to make a lot of minor name changes. Bottom line is the first AI
has a targetname of friendly and is set to 1 ( #fnum 1), and the second
AI guy has a targetname of friendly and is set to 2 ( #fnum 2).

I get absolutely no errors for any of the friendly initialization threads...
where we setup the AI as a friendly to follow player or other AI around,
and I see all the print text statements in the screen for each thread as it
is being ran. The second AI player runs to the cover pathnode waits
5 seconds per the wait 5 I have in the if statement for him to move, then
returns to the first AI and me to start firing at various targets.

NOW MY ONLY QUESTION IS: How should we interprete the if statement's
use of a "!" ? And also I was not using the correctly syntax. I read
in a supposedly authoritative statement in this forum that THIS:
if ( !isAlive blah) was incorrect and that THIS: if !(isAlive blah) was correct.

BUT. When I changed the if statements in question to read......
if ( !isAlive blah)............the commands in the if statement work. So perhaps you can see why I wrote some of the stuff I did.

So where does this all lead to?
Well I still have the question.........

Why must I use if ( !isAlive blah) to recognize a alive AI? You would
think it is the other way around. After all you guys are using .....

if (isAlive blah) in threads that set up friendlies etc.. Which should mean
....if blah is alive then do the following statements within the if construct.

And if ( !isAlive blah) should if anything return a FALSE boolean if blah is alive and therefore should not perform the if statements commands.
At least that is the way it is in C programming/UNIX shell programming and other languages I have used over the years.

NOW..... how this all started was................I want to check for when
a given enemy is killed so that a number of idle enemies on another street in a town will run to a given set of pathnodes (targetnames applied of course).
So how can I check to see if a enemy is dead so that those other baddies
will run to a given area? As far as I can tell (I'm a newbie at this stuff),
there is no inverse check for if a AI is dead, for example .....

if (isdead blah). THEREFORE YOU WOULD THINK THAT YOU SHOULD BE ABLE TO USE THE if ( !isAlive blah) to return a TRUE and therefore carry out the contents of the if statement.......IF the AI is dead.


Any feedback on this issue would be highly appreciated. And thank you all, who are reading this thread, for your patience. Lastly I am getting no errors the way the code is now set up.

Finally, Alcoholic, I understand your statement. But would you do this
if !($sniper cansee $snippe) OR if ( !$sniper cansse $snippee).
It makes a world of difference.
I am using it to move the second AI correctly. Like this:

move_tom:
if ( !isAlive level.friendly2)
{
iprintlnbold "Try to move tom"
level.friendly2.leash = 1000
level.friendly2.mindist = 128
level.friendly2.maxdist = 4000
level.friendly2 runto $friendhide
wait 5
thread init_tom
}
end

NOTICE AT THE END OF THE THREAD I CALL ANOTHER THREAD. This where I set up the friendly characteristics for this AI.

I just wish I understood what the inverse is for if (isAlive blah). If you
kind folks tell me that if !(isAlive blah) would be correct for detecting if the AI is really dead, then why did does it not work in my code? The AI is alive! And if (isAlive blah) will not allow the commands in the if construct to run. Tiss getting late, my brain is shot at this point, been working on this stuff for 12 to 16 hours for days on end. :(

Posted: Wed Jun 25, 2003 4:08 am
by Alcoholic
im not sure about this, but if you put the ! before the (, then the conditional will ask if everything inside the () is the opposite.

if it was...

Code: Select all

if (!isalive $jim && !isalive $tim)
i think it means the same as...

Code: Select all

if !(isalive $jim && isalive $tim)

Posted: Wed Jun 25, 2003 7:32 am
by jv_map
Alcoholic wrote:im not sure about this, but if you put the ! before the (, then the conditional will ask if everything inside the () is the opposite.

if it was...

Code: Select all

if (!isalive $jim && !isalive $tim)
i think it means the same as...

Code: Select all

if !(isalive $jim && isalive $tim)
No it is a little different :P

In the first example, if jim is dead and tim is alive, it would return if(1 && 0) so that would be false. However in the second example it would be if !(0 && 1) equals if !(0) so that is true. :wink:

I think I know what is wrong.

Posted: Wed Jun 25, 2003 6:49 pm
by grb
I think I understand why the If statement as being used in a thread that is called up from the main section to test for if a enemy is dead or alive and then if he is dead to move some enemies to given locations is not working.

I run the thread at the start of the mission. So naturally the enemy in question is alive. The thread ends.... So it will not test later in the mission when I shoot the enemy I am testing for (is he alive or dead, and if dead, then move some baddies to a given location).

So the question should be:

Should I put a while statement in the main program which keeps tabs on the condition of the enemy in question, so that when I shoot him, other baddies will run to a given area? OR, can I spawn a thread from the main, but not put an end statement at the end of that thread, and assume
the thread would stay active during the whole mission?
Why I ask this, is that I am not up on how to write good code in this language. Is it OK for instance to put a lot of inline coding within the main script area?

For instance if I have in the main script area the following:

thread init_ambush

Then in the thread code have:

init_ambush:
if !(isAlive $h1_germ1) //check if dead ...if so move germans to new spot.
{
$h1_germ3 runto $pn1
$h1_germ4 runto $pn2
}
end

BUT DO NOT PUT THE "end" statement at the end of this thread, will it stay active during the mission? That is continually test to see when h1_germ1 dies? Just asking, I think if it did do this that the scripting language is poorly written in the sense it has a bad set of rules.

Now one note on your two responses concerning the negate operator "!".
I guess the only way to figure out what is correct to use is to make some
examples up and see what happens.

If the scripting tool in use is using the standard boolean logic sets, then

if !(isAlive $tim) should return TRUE when tim is dead. And,
if (!isAlive $tim) should return TRUE when tim is dead. And,
if !(!isAlive $tim) should return TRUE when tim is alive, because the outer
negate operator will reverse the logic condition set within the brackets. So
if we wrote:

if (!isAlive $tim || !isAlive $jim) would return a TRUE when tim OR jim are dead.

if !(!isAlive $tim && !isAlive $jim) would return a TRUE when tim OR jim are dead. BECAUSE the outer negate symbol also reverses the logic operator within the test experssion. That is changes the AND operator into a OR operator. At least this is the way it is in standard Boolean Algebra. We must remember to always not the nots and unnot the nots
based on where the negate symbol is located within test experssions.

So if we wrote this: if !!(!isAlive $tim && isAlive $jim) in order to get
a return of TRUE ( 1) for this statement the following condition would have to be true. tim would be dead and jim would be alive.
This is true because, the first ! cancels out the second ! in front of the left bracket. Therefore the test operator IF simply interprets the guts of the experession found in between the brackets. Which in this case would be
tim=dead AND jim=alive.

In the following boolean logic experssion think of the ! sign as a horizontal bar over which is placed over a element within an expression or over any group of elements or over the whole experession. So if in the following example we replace the ! with a / sign (which would represent a horizontal bar instead of the divide symbol) and wrote the following:

/(A + B) if A AND B where false. Then the test is TRUE. Where the + sign represents an OR operator.
/(A * B) if A OR B where false. Then the test is TRUE. Where the * sign
represents an AND operator (when we write boolean expresssions on paper we would use a DOT instead of the * sign, I only use the * here so that it shows at mid-hight as would be the case when you put a dot on the paper between the A and B elements).

So if we wrote ( A * /B), the test is TRUE when A is 1 AND B is 0.
Conversely, / ( A * /B) would be interpreted to return a TRUE if
A is 0 OR B is 1.

Lastly, if we wrote: //(/A + /B) the test is TRUE when A OR B is 0,
because the outer negate symbol negates the inner negate symbol thereby forcing the test statement to interprete only what is inside the
brackets.
Hope it makes sense to you folks, I think it does, and thanks if you can
suggest where I should best place an while loop or some other type
conditional statement that will monitor the condition of $h1_germ1 during
game play and once he is shoot dead, allow for the other enemies to run to a given area.

best regards

Posted: Wed Jun 25, 2003 7:10 pm
by nuggets
use while()

not using end will just read the next lines of script until break or end

i haven't read the latter part of ur post, you type to much :P

nuggets, thanks for feedback...

Posted: Thu Jun 26, 2003 12:49 am
by grb
Could you possibly further qualify your statement:
"use while()
not using end will just read the next lines of script until break or end".

I do not understand what you are trying to say, help me understand.

Are you saying that not putting an end statement at the end of a thread which contains a while loop will in effect allow that thread to run as a
seperate subroutine AND NOT keep other threads that get called in the main section of script file from starting? Or are you refering to not putting
an end statement within the body of the while loop?

I do understand exactly how the various while statement constructs work in this scripting language, in short, the various while constructs seen here
are the same as basic C code or Bourne shell while constructs. That is not the issue. But thank you for responding to help me out!

Moving on.........

OK, after examining the M3L2 and M3L3 scripts for the Normandy stuff,
I have come to the conclusion that:

Whoever made the statement in this forum (that I mentioned days ago about possible use of................... if ( !isAlive $blah) was a bit confused.
I have not found one example in the above mentioned scripts nor in others I have looked at that use this type of IF construction/syntax.

Always, it is either:
if !(isAlive $blah) or if (isAlive). So I am very sorry I had written so much making an issue about using if ( isAlive). I find NO occurance of this syntax anywhere. Dead Issue.


What I have tried to do is put various forms of while loops with inclusive
if statement test in a few cases, in the main area of the script file.

Depending on what form of syntax for performing a sequence of logic test I use.............the following happens.
1. either the program bombs and tells me that I have a overflow problem due to an infinite loop...............which I undertand why it happens, so no
use wasting your time trying to explain the hang here.
2. After the initial mission loads, none of the threads that are in the main
part of the script file run .............so I do not get weapons assigned to players, AI do not become friendly, or AI do not make any initial moves that I ask them to perform in those threads.

So at this point, I do not think that one can have a while loop run within
the main program that will test the condition of some AI during game play.
Now when I called a thread from main that does the while loop tests, to see if a AI is dead so that specific AI can move to given location, I cannot get the test to work within a thread either. The game does not lock up but again, none of the other threads called from the main area,
are processed, so the same conditions happen when trying it this way.

So at this point, I do not expect anyone to waste their time in trying to
provide a solution to this particular code control problem.

I realize I can always just put in a multiple trigger close to the point where I or another allied soldier would kill that particular enemy thereby
forcing other enemies hiding behind walls etc, in other parts of the town to converge on a given point and ambush my team. BUT this is a shabby way of doing it! It forces to much artifical control into the mission. Whereas what I wanted to do was allow for the enemy not to be killed and therefore the group that would ambush would not move to the ambush point but be free to fire on me and the team when we arrived at their current area. I was seeking a flexible way for various enemy groups to behave, based on the health or dead/alive condition of some of the enemy within a given area of combat. And the only way I can envision
do that is to have while loops with test statements that test to see if a
given enemy is dead, THROUGHOUT THE GAME. Not just in some given
sequence in time.

But thank you, alcoholic, jv_map, and nuggets for your willingness to help. Best regards

Posted: Thu Jun 26, 2003 3:02 am
by bdbodger
The while loop will run if the while statement is true once the statement is not true and you have no end the thread will run into the next lines below it possibly another thread . While(1) will not end but you probably want the thread to end some time . while threads are also used to pause the script untill something is true or not true then continue the thread with either a break in the loop or by haveing the while statement become not true .You get an overflow from threads that run too fast too many if statements not true is one way , the game handles only so many commands from a thread on a per second basis sometimes a wait 1 or move will cure that . If you get no weapons at the beginning of your script and the syntax is ok it is because there is an error somewhere in your script that stops the script from loading , check the console or type logfile 1 into the console then start your map after check the main directory for a file called qconsole.log and read it looking for an error that will stop the script from running . If you give your friendly nodes an area number and give your enemy an area number the friendly will stay in that area untill all enmies with that area number are dead then the nodes will turn off .

bdbodger thanks for your feedback...

Posted: Thu Jun 26, 2003 3:37 am
by grb
Interesting that you say that sometimes one will get over flow because each thread is limited to just so many possible computations per second.
What I will try to do is as you suggested, put in a wait 1. The same problem shows up when I write:
while () or while (1) or lets say shove in a wildcard placeholder type
test expression such as:
while ( isAlive $player)

Here is the thread in it's present form. All I want to do is check as the game progress to see when I or one of my buddies key a given enemy then have other enemies run from their current position (type_idle) to
an ambush point.

ambush_1:
while (isAlive $player)
{
if (isAlive $h1_germ1) // guy I want to keep tabs on.
{
continue
}
else
{
$h1_germ3 runto $pn1 //send these guys to the ambush point.
$h1_germ4 runto $pn2
break
}
}
end

Does this logic seem OK? Thank you in advance for any further help.

Posted: Thu Jun 26, 2003 8:20 am
by bdbodger
yes that will work but better to use

ambush_1:
$h1_germ1 waittill death //pauses script untill guy dies
$h1_germ3 runto $pn1 //send these guys to the ambush point.
$h1_germ4 runto $pn2
end

other possible waits too

level.friendly1 waittill movedone

level.friendly1 waittill saydone

$mytrigger waittill trigger

$myguy waittill animdone

self waittill death // self is entity that called the thread like $h1_germ1 thread ambush_1

ambush_1:
self waittill death //pauses script untill guy dies
$h1_germ3 runto $pn1 //send these guys to the ambush point.
$h1_germ4 runto $pn2
end

probably more waits I think it is like waitill true these are the common waits used a lot in the game

Posted: Thu Jun 26, 2003 8:43 am
by bdbodger
Ok I know I forgot about the player ok if it is single player the level ends anyway in multiplayer there are is more that one "$player" in the game .

ambush_1:
$h1_germ1 waittill death //pauses script untill guy dies
if (isalive level.friendly1)
{
$h1_germ3 runto $pn1 //send these guys to the ambush point.
$h1_germ4 runto $pn2
}
end

If you have more than one friendly the use a for loop
// syntax is do first thing , while second thing true loop , do third thing at end of loop

main:
....
....
$h1_germ1 thread ambush_1
....
end

ambush_1:
self waittill death
for(local.i=1;local.i<($friendly.size+1);local.i++)
{
if (isalive $friendly[local.i])
{
$h1_germ3 runto $pn1 //send these guys to the ambush point.
$h1_germ4 runto $pn2
end
}
}
end

of course if any of the friendly's are alive it will execute the run statements

thanks bdbodger.....

Posted: Thu Jun 26, 2003 11:20 pm
by grb
I will download this thread for closer inspection as to how you suggest to do sense AI condition and move AI.

The last post I made that I showed the somewhat "reduntant" while loop
did not work.
However when I changed the while loop code to what you see immediately below it works just fine!

check_zipo:
while (isAlive $zipo)
{
wait 1
continue
}
$h3_g1 runto $pn1
$h3_g2 runto $pn2
end

I think despite your advice the other day about including the wait 1, which
DID stop the over flow problem and then allowed the while loop to work without screwing up other main tread initializations etc.., that there is
some fundelmental problems with putting if statements within while loops,
which is the case in other languages I have worked with in the past. Some
times the loops will work fine, where othertimes despite what appears to be a good logic sequence, for some reason the program gets hung up while in the while loops, especially when one buries while loops within while loops that contain compound if statements etc..
Logically that should have worked, but did not. The simply version you
above works great.

Lastly, I can see where your two large code entries will be a big help.
Obviously you are not using the while loops, and the code method you
demontrate seems like a neater way of presenting the code. For instance where you have $h1_germ1 waittil death //pauses script until guy dies

Is clean, and takes less code then creating the while loop.
So at this point I guess this topic can be closed. I definetly am going to
analyse the way your pieces of code work.

Thanks again.

Posted: Fri Jun 27, 2003 2:45 am
by mohaa_rox
too much text, make me giddy. :shock: