Difference between revisions of "If-then-else"

From FreeSpace Wiki
Jump to: navigation, search
m (if-then-else with multiple possibilities: some oversights)
m (some fixes)
 
(3 intermediate revisions by the same user not shown)
Line 7: Line 7:
 
  Rest: Actions to take if that expression becomes false.
 
  Rest: Actions to take if that expression becomes false.
  
==Example SEXP tree==
+
'''If-then-else''' is an action operator that can be used to evaluate two outcomes if a mission event is fired, and append an action to either outcome. Since it is an action operator, it must be put in the "do-nothing" part of the event. The operator itself consists of three parts:
 +
 
 +
#The condition to check.
 +
#What to do if the condition is true.
 +
#What to do if the condition is false.
 +
 
 +
==Example mission==
 +
In the example mission, we have Alpha 1 who has to destroy four containers. Ten seconds into the mission, Command will assess the player's performance. If at least two containers are destroyed, they will send the "Good job so far." message. If one or none are destroyed, Command will send the "Hurry it up, pilot." message. The event that deals with these two outcomes is this:
 +
 
 
[[image:if-then-else.jpg]]
 
[[image:if-then-else.jpg]]
  
In this experimental mission, Omicron departs 20 seconds into the mission.
+
Where ( has-time-elapsed 10 ) represents the prerequisite to assess the player's performance.
 +
 
 +
The if-then-else parts deals with the performance assessment. Per above, there are two possible outcomes. The >= part is the condition to check. '''If''' the condition is true (so the number of containers is 3 or greater), '''then''' the "Hurry it up, pilot" message will be sent, '''else''' the "Good work so far" message will be sent.
 +
 
 +
Without if-then-else you would need two separate events, one for either message. Unfortunately, FREDders tend to forget that has-time-elapsed means "At least 10 seconds have elapsed", not "Exactly 10 seconds have elapsed," and they create events like these:
 +
 
 +
$Formula: ( when
 +
  ( and
 +
      ( has-time-elapsed 10 )
 +
      ( <
 +
        ( num-ships-in-battle
 +
            "TC 2 1"
 +
            "TC 2 2"
 +
            "TC 2 3"
 +
            "TC 2 4"
 +
        )
 +
        3
 +
      )
 +
  )
 +
  ( send-message
 +
      "#Command"
 +
      "High"
 +
      "COM - Good"
 +
  )
 +
)
 +
+Name: Asses situation - good
 +
+Repeat Count: 1
 +
+Interval: 1
 +
 
 +
$Formula: ( when
 +
  ( and
 +
      ( has-time-elapsed 10 )
 +
      ( >=
 +
        ( num-ships-in-battle
 +
            "TC 2 1"
 +
            "TC 2 2"
 +
            "TC 2 3"
 +
            "TC 2 4"
 +
        )
 +
        3
 +
      )
 +
  )
 +
  ( send-message
 +
      "#Command"
 +
      "High"
 +
      "COM - Bad"
 +
  )
 +
)
 +
+Name: Assess situation - bad
 +
+Repeat Count: 1
 +
+Interval: 1
 +
 
 +
If FREDded like this, the "Good work so far message " will be sent if the player destroys the second container in the 12th second, 2 seconds after receiving the "Hurry up, pilot" message. Further precautions are needed to make FRED ignore the good outcome message in this case. One possibility is to edit the event like this:
 +
 
 +
$Formula: ( when
 +
  ( and
 +
      ( has-time-elapsed 10 )
 +
      ( <
 +
        ( num-ships-in-battle
 +
            "TC 2 1"
 +
            "TC 2 2"
 +
            "TC 2 3"
 +
            "TC 2 4"
 +
        )
 +
        3
 +
      )
 +
      ( not
 +
        ( is-event-true-delay
 +
            "Assess situation - bad"
 +
            0
 +
        )
 +
      )
 +
  )
 +
  ( send-message
 +
      "#Command"
 +
      "High"
 +
      "COM - Good"
 +
  )
 +
)
 +
+Name: Asses situation - good
 +
+Repeat Count: 1
 +
+Interval: 1
  
''If-then-else'' is equivalent to a ''when X'' paired with a ''when not-X'', for the same X.  Thus if ''if-then-else'' appears in an event by itself, one of its branches will immediately fire.  Therefore, this sexp will probably be more useful when chained after, or used as a subordinate to, a controlling sexp.  In the example above, the ''destroyed-or-departed-delay'' sexp controls when ''if-then-else'' should check if its condition is true or not.
+
With if-then-else, no such precautions are needed, because the event fires in the 10th second, and since there is no repeat or trigger count added to it, the engine will mark the event as true, and "forget" it.
  
If you substitute  ''destroyed-or-departed-delay'' with ''true'', then the player's shield icon will flash at mission start. If you substitute it with (has-time-elapsed 15), then the player has 15 seconds to destroy Omicron. If he manages to kill Omicron in 15 seconds, then his ETS will flash. If not, his shield icon will.  If the player kills Omicron in the 16th second, his ETS gauge will not flash.
+
Neither the old nor the new method is unambiguously better than the other. The if-then-else tree can be used to avoid sending the two conflicting messages, but you can mess up both methods if you don!t pay attention, like confusing > with <.
  
 
===if-then-else with multiple possibilities===
 
===if-then-else with multiple possibilities===
A single ''if-then-else'' is sufficient to check an either/or duality. Omicron is either destroyed or not, there's nothing in between. By using SEXP embedding, if-then-else can be used to take multiple, not only two, possibilities into account for scenarios that have more than two logical outcomes.
+
A single ''if-then-else'' is sufficient to check an either/or scenario. The player either destroys at least 2 containers or not, there's nothing in between. By using SEXP embedding, if-then-else can be used to take multiple, not only two, possibilities into account for scenarios that have more than two conceivable outcomes.
  
In this example mission, we'll use ''percent-ships-destroyed'' on Beta, four fighters. If any of Beta jumps out or all are destroyed, Command will inform you how many of them were killed. Here are the logically possible outcomes:
+
In this example mission, we'll use ''percent-ships-destroyed'' on Beta, a wing of four fighters. If any of Beta jumps out or all are destroyed, Command will inform you how many of them were killed. Here are the possible outcomes:
  
 
*All survived
 
*All survived
Line 70: Line 159:
 
  )
 
  )
  
The event will trigger if there is 0 of Beta in the mission ( = ( num-ships-in-wing "Beta" ) 0 ). This event would fire immediately if Beta weren't present on startup, so watch out if you want to apply this to a wing that arrives later. At the moment, we aren't interested in how many of Beta survives. We just want to tell FRED when to "look for survivors." Now comes the first "main" ''if-then-else'', below which the rest are subordinated. If 100 percent of Beta is destroyed, Command will say "All destroyed." Now, if this scenario becomes false, so at least one survives, FRED will look below to see what to do if sending "All destroyed" is out of the question. The trick here is to use another ''if-then-else'', not a ''send-message''. ''If-then-else'' has two possible outcomes, while ''send-message'' has one: it sends a message and that's it.
+
The event will trigger if there is 0 of Beta in the mission ( = ( num-ships-in-wing "Beta" ) 0 ). This event would fire immediately if Beta weren't present on startup, so watch out if you want to apply this to a wing that arrives later. At the moment, we aren't interested in how many of Beta survives. We just want to tell FRED when to count the survivors. Now comes the first "main" ''if-then-else'', below which the rest are subordinated. If 100 percent of Beta is destroyed, Command will say "All destroyed." Now, if this scenario becomes false, so at least one survives, FRED will look below to see what to do if sending "All destroyed" is out of the question. The trick here is to use another ''if-then-else'', not a ''send-message''. ''If-then-else'' has two possible outcomes, while ''send-message'' has one: it sends a message and that's it.
 
 
These chains must be set up according to logic. In this case, I don't jump from (percent-ships-destroyed 100) to (percent-ships-destroyed 50) then (percent-ships-destroyed 75) because that's not how math works. In this case, I need (percent-ships-destroyed 75) subordinated below (percent-ships-destroyed 100). If 75% of Beta is destroyed, Command will say "Three destroyed." If (percent-ships-destroyed 75) becomes false, then FRED will look for another possibility, another subordinated ''if-then-else''. The chain continues until all logically possible scenarios are depleted; in this case, (percent-ships-destroyed 25) becoming false, which equates to all of Beta surviving.
 
  
Get the example mission [http://www.mediafire.com/?cdzc1by29c6dqlv here]. Destroying the container is Beta's departure cue. The No Traitor flag is set, so you can kill as many Beta as you want to test each possibility.
+
These chains must be set up according to logic. If I have four fighters, I don't jump from (percent-ships-destroyed 100) to (percent-ships-destroyed 50) then (percent-ships-destroyed 75) because that's not how math works. In this case, I need (percent-ships-destroyed 75) subordinated below (percent-ships-destroyed 100). If 75% of Beta is destroyed, Command will say "Three destroyed." If (percent-ships-destroyed 75) becomes false, then FRED will look for another possibility, another subordinated ''if-then-else''. The chain continues until all logically possible scenarios are depleted; in this case, (percent-ships-destroyed 25) becoming false, which equates to all of Beta surviving.
  
 
[[Category:SCP SEXPs]]
 
[[Category:SCP SEXPs]]

Latest revision as of 07:27, 13 September 2012

If-then-else (Conditional operator)
	Performs one action if a condition is true (like "when"), or another action (or set of actions) if the condition is false.  Note that this sexp only completes one of its branches once the condition has been determined; it does not come back later and evaluate the other branch if the condition happens to switch truth values.

Takes 3 or more arguments...
	1:	Boolean expression to evaluate.
	2:	Actions to take if that expression becomes true.
	Rest:	Actions to take if that expression becomes false.

If-then-else is an action operator that can be used to evaluate two outcomes if a mission event is fired, and append an action to either outcome. Since it is an action operator, it must be put in the "do-nothing" part of the event. The operator itself consists of three parts:

  1. The condition to check.
  2. What to do if the condition is true.
  3. What to do if the condition is false.

Example mission

In the example mission, we have Alpha 1 who has to destroy four containers. Ten seconds into the mission, Command will assess the player's performance. If at least two containers are destroyed, they will send the "Good job so far." message. If one or none are destroyed, Command will send the "Hurry it up, pilot." message. The event that deals with these two outcomes is this:

If-then-else.jpg

Where ( has-time-elapsed 10 ) represents the prerequisite to assess the player's performance.

The if-then-else parts deals with the performance assessment. Per above, there are two possible outcomes. The >= part is the condition to check. If the condition is true (so the number of containers is 3 or greater), then the "Hurry it up, pilot" message will be sent, else the "Good work so far" message will be sent.

Without if-then-else you would need two separate events, one for either message. Unfortunately, FREDders tend to forget that has-time-elapsed means "At least 10 seconds have elapsed", not "Exactly 10 seconds have elapsed," and they create events like these:

$Formula: ( when 
  ( and 
     ( has-time-elapsed 10 ) 
     ( < 
        ( num-ships-in-battle 
           "TC 2 1" 
           "TC 2 2" 
           "TC 2 3" 
           "TC 2 4" 
        )
        3 
     )
  )
  ( send-message 
     "#Command" 
     "High" 
     "COM - Good" 
  )
)
+Name: Asses situation - good
+Repeat Count: 1
+Interval: 1
$Formula: ( when 
  ( and 
     ( has-time-elapsed 10 ) 
     ( >= 
        ( num-ships-in-battle 
           "TC 2 1" 
           "TC 2 2" 
           "TC 2 3" 
           "TC 2 4" 
        )
        3 
     )
  )
  ( send-message 
     "#Command" 
     "High" 
     "COM - Bad" 
  )
)
+Name: Assess situation - bad
+Repeat Count: 1
+Interval: 1

If FREDded like this, the "Good work so far message " will be sent if the player destroys the second container in the 12th second, 2 seconds after receiving the "Hurry up, pilot" message. Further precautions are needed to make FRED ignore the good outcome message in this case. One possibility is to edit the event like this:

$Formula: ( when 
  ( and 
     ( has-time-elapsed 10 ) 
     ( < 
        ( num-ships-in-battle 
           "TC 2 1" 
           "TC 2 2" 
           "TC 2 3" 
           "TC 2 4" 
        )
        3 
     )
     ( not 
        ( is-event-true-delay 
           "Assess situation - bad" 
           0 
        )
     )
  )
  ( send-message 
     "#Command" 
     "High" 
     "COM - Good" 
  )
)
+Name: Asses situation - good
+Repeat Count: 1
+Interval: 1

With if-then-else, no such precautions are needed, because the event fires in the 10th second, and since there is no repeat or trigger count added to it, the engine will mark the event as true, and "forget" it.

Neither the old nor the new method is unambiguously better than the other. The if-then-else tree can be used to avoid sending the two conflicting messages, but you can mess up both methods if you don!t pay attention, like confusing > with <.

if-then-else with multiple possibilities

A single if-then-else is sufficient to check an either/or scenario. The player either destroys at least 2 containers or not, there's nothing in between. By using SEXP embedding, if-then-else can be used to take multiple, not only two, possibilities into account for scenarios that have more than two conceivable outcomes.

In this example mission, we'll use percent-ships-destroyed on Beta, a wing of four fighters. If any of Beta jumps out or all are destroyed, Command will inform you how many of them were killed. Here are the possible outcomes:

  • All survived
  • 1 killed
  • 2 killed
  • 3 killed
  • All killed

In retail, you need one event for each message, accumulating to five events altogether. With embedded if-then-else, you need only one. The event looks like this:

$Formula: ( when 
   ( = ( num-ships-in-wing "Beta" ) 0 ) 
   ( if-then-else 
      ( percent-ships-destroyed 100 "Beta" ) 
      ( send-message 
         "#Command" 
         "High" 
         "All destroyed" 
      )
      ( if-then-else 
         ( percent-ships-destroyed 75 "Beta" ) 
         ( send-message 
            "#Command" 
            "High" 
            "Three destroyed" 
         )
         ( if-then-else 
            ( percent-ships-destroyed 50 "Beta" ) 
            ( send-message 
               "#Command" 
               "High" 
               "Two destroyed" 
            )
            ( if-then-else 
               ( percent-ships-destroyed 25 "Beta" ) 
               ( send-message 
                  "#Command" 
                  "High" 
                  "One destroyed" 
               )
               ( send-message 
                  "#Command" 
                  "High" 
                  "All survived" 
               )
            )
         )
      )
   )
)

The event will trigger if there is 0 of Beta in the mission ( = ( num-ships-in-wing "Beta" ) 0 ). This event would fire immediately if Beta weren't present on startup, so watch out if you want to apply this to a wing that arrives later. At the moment, we aren't interested in how many of Beta survives. We just want to tell FRED when to count the survivors. Now comes the first "main" if-then-else, below which the rest are subordinated. If 100 percent of Beta is destroyed, Command will say "All destroyed." Now, if this scenario becomes false, so at least one survives, FRED will look below to see what to do if sending "All destroyed" is out of the question. The trick here is to use another if-then-else, not a send-message. If-then-else has two possible outcomes, while send-message has one: it sends a message and that's it.

These chains must be set up according to logic. If I have four fighters, I don't jump from (percent-ships-destroyed 100) to (percent-ships-destroyed 50) then (percent-ships-destroyed 75) because that's not how math works. In this case, I need (percent-ships-destroyed 75) subordinated below (percent-ships-destroyed 100). If 75% of Beta is destroyed, Command will say "Three destroyed." If (percent-ships-destroyed 75) becomes false, then FRED will look for another possibility, another subordinated if-then-else. The chain continues until all logically possible scenarios are depleted; in this case, (percent-ships-destroyed 25) becoming false, which equates to all of Beta surviving.