Tutorial - Conditional Arguments
So you're here to have an argument? That's just down the hall. Room 12A.
And you're here to learn about conditional arguments? Well just sit right down!
- 1 ARGUMENTS!
- 1.1 any-of (and the basics of arguments)
- 1.2 invalidate-argument
- 1.3 every-of
- 1.4 random-of/random-multiple-of
- 1.5 number-of
- 1.6 in-sequence
- 1.7 for-counter
- 1.8 Advanced Conditional Sexps
- 1.9 UNDER THE HOOD
God's gift to FREDders everywhere.
So just what is an conditional argument? Basically it is a type of sexp that allows the game to choose from a list of pre-defined arguments and use one, a few, or all of them like a normal sexp. Still confused? Well let's fix that.
We're going to make a quick scenario that will let us showcase every type of conditional argument.
- FYI: I'm just going to call them arguments from this point. It's just easier for me.
We have 5 ships! Alpha Wing, comprised of 4 Perseus-class fighters and an Elysium transport, named Omega 1. No hostiles or anything. This is just our sandbox right now.
So we're going to set up a sexp system that will make each of these fighters warp out if they get below 30% health. Normally this would require 4 very similar sexps. But we're going to do it in ONE. First though, let's set up some events to make all of our ships go to 25% health.
- Key-pressed is in the training category.
Ok, let's make this work.
any-of (and the basics of arguments)
Any-of is the simplest argument conditional and probably the most common one you will use. Like the name suggests, the sexp will be evaluated once ANY of the arguments can pass the conditions we set.
So first, let's change this when to a when-argument. Right click on the "when", go to "Replace Operator", then "Conditionals", and finally "when-argument". You can see there's some other operators such as "everytime-argument" and a bunch of grayed out operators. We will get to those later. So now you should have something like the below.
Let's change the event name to "Retreat when hurt". Now click on "<any data>" and edit it to be Alpha 2. Then right click on "any-of" and go to "add data" and then "string". Make this new entry, Alpha 3. Repeat this process to enter Alpha 4 and Omega 1. It looks like the below, right? Right?
Good! Now lets make our trigger condition. We want it to trigger when hull is less than 30%. So that's just < hits-left 30! Wait, what do I put as the ship? Is it this <argument> thingy that appeared out of nowhere? Why yes! You're smart, buddy.
Let's extend this train of thought to our action. For warping out.
To give this a bit of flair. Let's make a message that plays when someone needs to warp out. No need for a head ani or anything right now. We're keeping it simple, smart guy. (On a side note, I was denied the trademark for KISSG, and I can't figure out why).
Lastly, let us ensure this sexp will repeat a suitable amount of times. 4 possible arguments, so lets set trigger count to 4.
Time to RUN THE MISSION.
Lets press the 1 key to hurt Alpha 2 enough to run like the baby he is.
Hey it works!
Wait, that message replayed a few times... I'm sure its a simple bug we can fix later. Let's make Alpha 3 cry more.
Hey! What's going on here! He didn't run, but his health is below the threshold we set.
Does this have to do with those multiple messages? Did we forget one last step? By asking these oddly specific questions, am I implying that this is indeed the case?
When an argument can pass the condition we set, it doesn't vanish. It stays there unless we remove it. Now, the sexp looks for a ship in our argument list with less than 30% hull. If it finds one, it gives the ship (let's say Alpha 2) an order to warp out and to send a message. But the next time the sexp checks everything, Alpha 2 still has less than 30% hull. So it runs through the actions again. And again. And again.
Luckily we have a sexp that can remove an argument from the list. And that sexp is... invalidate-argument! Wait, how did you know that already?
So let's just tack this on at the end of our sexp. 99.999% of the time, the sexp will be invalidate-argument <argument>. So that's nice.
Let's run this mission again.
Hooray! The message was sent once. Pressing 2!
Yayifications! Pressing 3 and 4!
Look at that. Cool, isn't it? Let's go on to the other types and... oh- yes you in the back. You have a question?
A very common misconception
Axem, I have a rather complex mission and I want to use this sexp. Could I take a shortcut and just replace Alpha 2, Alpha 3, Alpha 4 with just Alpha? Or maybe just go any-of GTF Perseus?
Short answer, no. Long answer, noooooooooooooooooo.
When you are using arguments, be aware of type mismatching. The type of arguments in your list should be able to be used in the sexps you want to use them in.
Oh, this will check any of the ships that are a GTF Perseus, right? No. Because if we substitute <argument> with GTF Perseus we get a sexp that checks to see if a ship NAMED GTF Perseus is under 30% hull. There's no one like that, so the sexp will never trigger.
Arguments are very powerful because they will accept ANY type of data. FRED is blind to what you put in the argument list, so its up to YOU to ensure that they are correct and valid.
Anyway, on to every-of.
Similar to any-of, except that using this will only trigger when EVERY item on the list can pass the condition. For our sexp, that means our wingmen will only run away when everyone is below 30% hull. Give it a quick try. Just replace the any-of with every-of, save and run.
Neat, huh? You'll notice that everyone sent their message at the same time, so everyone's actions happen at the same time. This is the case with most conditional arguments. If there's multiple arguments that can be passed through, the game will use them all.
- FYI: The difference between random-of and random-multiple-of is the same as the random number system. Where random will generate the same random number throughout repeats, while random-multiple will generate different results for every repeat.
Random-of isn't a good choice for this situation, but we'll use it anyway for the purposes of showing you the sexp. The conditionals will choose a random item on the list and check that argument against the condition. The issue with this is that the random argument chosen is only chosen on the merit that it is on the list, not that it can pass the condition, but the sexp will try to trigger once if any of the arguments can complete the condition. Sounds complicated? Let's break it down.
Change the argument conditional to random-of. Save, and run the mission. Run through it a few times.
If you were proactive enough to, you would discover that the results are pretty inconsistent. Sometimes the key you press will cause the ship you want to retreat, sometimes it does nothing. But why?
Let's go through the game's thought process.
"Alpha 2 has 25% hull. Hey, there's a sexp that related to him being under 30% hull. Oh but, this sexp is asking for a random item on the list. Let's roll the dice! I choose... Alpha 4. Does Alpha 4 have under 30% hull? No. Okay, I'll skip this then."
Kind of weird, isn't it? Well the real action you are undertaking here is "Randomly pick someone to see if they should leave."
If you use just random-of, you will guarantee yourself a single random ship retreating.
Number-of will only begin once a specified number of list items can pass the condition. A number-of with a 1 will act as an any-of. A number-of with the number of items you have in the list (in our case 4) will act as an every-of. So the real stuff it can do is in between. Change the argument conditional to number-of. But be warned, you will have to reenter the argument list. That's because the first argument now is a number, not a string. Set our number argument to 2.
Let's run the mission!
As you probably saw, it took hurting Alpha 2 and Alpha 3 to make them warp out. And then it took hurting both Alpha 4 and Omega 1 to warp them out. What happens if we bump it the number argument to 3?
Well, I hurt Alpha 2, Alpha 3 and Alpha 4 and they all warped out.
But now I hurt Omega 1 and he just stays there.
Sort of predictable, I guess. We're looking for 3 items on the list to be true, but there's only 1 item left!
Hmm... But what if we have everyone hurt at the SAME time? Who gets chosen then?
...Let's find out...
Let's make everyone's health start off at 25%.
Now let's run the mission...
Wait, so before we had 3 ships leave, but now we had everyone leave! Why? The sexp actually looks for at least a number of arguments that can pass the condition. But that doesn't explain why Omega 1 didn't leave when we were hurting them one a a time. Actually, it does. When we invalidate an argument, we remove it from the list. So hurting them one by one will make the list get cut short, excluding the last ship. But hurting them all at once (in the same frame!) will make the game include the whole list.
Still confused? Here, let me explain with a bit of game thought process.
Hurting one-by-one: "I need to wait until I have at least 3 of these ships go below 30% hull before I tell them to warp out. Oh hey, Alpha 2, Alpha 3 and Alpha 4 all have hulls below 30%. I better tell them to leave. Also I will remove them from the list so they won't be evaluated again. Now I'm waiting to get at least another 3 ships to go below 30% hull... but there's only 1 ship left on the list. Oh well, the FREDder knows best!"
Hurting all at once: "I need to wait until I have at least 3 of these ships go below 30% hull before I tell them to warp out. Oh hey, Alpha 2, Alpha 3, Alpha 4 and Omega 1 all have hulls below 30%. I better tell them to leave. Also I will remove them from the list so they won't be evaluated again. Now I'm waiting to get at least another 3 ships to go below 30% hull... oh hey, the list is empty now. Whatever."
Well, that was fun. Lets give everyone 100% health again.
In-sequence is very interesting. All of these conditionals before either began as soon as someone could fufill the conditions, or randomly chose one. But in-sequence is very rigid, it will only evaluate the top item. So let us set up the argument list for in-sequence... (yes we need to redo it again)
Now let's go in game.
I'm gonna make Alpha 3 get hurt first... Oh. Nothing happens. Maybe Alpha 4? No?! Okay. Let's hurt Alpha 2 now.
He leaves, and then Alpha 3 leaves shortly after. Then Alpha 4.
So when Alpha 3 got hurt, the game didn't care, because Alpha 2 was in the top position. But once Alpha 2 got hurt, the game gave him the order, then invalidated Alpha 2 from the list. This now made Alpha 3 the top item on the list. And since Alpha 3 was hurt, the game saw it needed to make him leave too and take him off the list. Now Alpha 4 is at the top! For one second anyway. Because I'm sure you can guess what happens next.
This is kind of advanced and isn't applicable to this situation. If you are familiar with programming, for-counter is like a for-loop. Read the help description, that's the best you're going to get from this tutorial!
Advanced Conditional Sexps
These are for advanced FREDders only. Don't worry about these if you don't understand them.
If you want to remove the argument list, perhaps because you want it to stop midway through, you can use this sexp. It's probably wise to use this in an branching when conditional. If, for whatever reason, you don't want anyone to run away after Omega 1 was hurt, you could do this...
These sexps are the only way to add arguments to an argument list. Since arguments are local to their sexp tree level, this might be a little tricky to use. This probably best used with another when conditional. VALIDATE-ALL-ARGUMENTS will restore all arguments that were originally in the list. An example on this will follow shortly.
A valid item is an item that is on the list and ready to be evaluated by a possible trigger condition check. So num-valid-arguments basically returns the size of the argument list. With this you can tell how large the list is. If you can tell the size of the list, you can see if it's empty or not. So you can do something like this...
This will detect if there's no more arguments left on the list. If there's none left, it will restore all the default arguments, making this sexp, good as new! Using this with in-sequence, like I just did, will let you start from the beginning again once you finish.
- WARNING This Valid is not the Valid from the previous sexps. This should probably be named...
But that's too long for FRED.
Anyway, this is a special conditional. Basically for each valid argument that can //pass// the trigger condition, the sexp action will repeat what you put inside.
Let's say we want to track the number of hurt ships in the area. I've taken out the warp out order, so everyone will stick around. Then I crated a new variable, numHurtShips. Obviously we just set this to increment by one, right?
Well, technically yes... But no. What happens if the game has two arguments it can pass through on the same frame? We can easily see this with number-of 2.
Lets try this in-game.
Obviously that's not right. There's 2 hurt ships! So let's add this do-for-valid-arguments on top of the modify-variable sexp.
2 hurt ships!
4 hurt ships!
UNDER THE HOOD
(For FREDders with extremely high IQs)
Here's an extremely simplified explanation on how the conditional argument system works.
We have 2 main lists. The VALID list, the list that you enter into FRED. And the ACTIVE list, the list that the game is using to replace <argument> with real data types. (These names invented by Axem, coders won't know what you're talking about).
If the game sees that items on the VALID list can pass the condition trigger, it will copy them to the ACTIVE list. The game will then replace every instance of <argument> with the items in the ACTIVE list. If the ACTIVE list has more than one item, the sexps with <argument> in them will be repeated for each item in the ACTIVE list. If you want ALL sexps (and not just the ones with <argument> to be repeated for each item on the ACTIVE list, make them a child of a do-for-valid-argument sexp.
*By design, the random conditionals and in-sequence can only pass one argument at a time. The rest can pass as many arguments as you like
If the game encounters an invalidate-argument, it will remove the entry from the VALID list, but the ACTIVE list will remain intact (Ditto for the other types of (in)validation sexps). So in theory, you can invalidate the current argument and go and use <argument> after and still get the same result. In general though, it makes it easier to read when invalidate-argument is at the end.