Difference between revisions of "If"

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search
imported>HawkFest
imported>Thalassicus
Line 80: Line 80:
=== Oblivion evaluates entire If statement ===
=== Oblivion evaluates entire If statement ===


Note also, that Oblivion evaluates all parts of an IF-statement. When you combine expressions with "&&" for example and the first expression is false, then the second one will still be evaluated.
Oblivion evaluates all the conditions for an IF statement. For example, when you combine expressions with "&&", if the first expression is false, later expressions will still be evaluated, even though they are irrelevant (false && anything = always false, true || anything = always true).


If ReferenceVariable != 0 && ReferenceVariable.Getav Health < 30
This can also result in unexpected errors, such as below:


Will crash Oblivion when the reference variable is undefined ("0"), because the second part is evaluated although the first part already returned "false". In such cases you need to use nested IF-blocks instead:
If (ReferenceVariable != 0) && (ReferenceVariable.Getav Health < 30)
 
This crashes Oblivion if the reference variable is undefined ("0"), because the second part is still evaluated. In such cases you need to use nested IF-blocks instead:


  If ReferenceVariable != 0
  If ReferenceVariable != 0
     If ReferenceVariable.Getav Health < 30
     If ReferenceVariable.Getav Health < 30
Since boolean conditions (&& ||) are inefficient and implemented poorly in Oblivion, use nested IF-blocks whenever possible.


== Comparisons and Expressions ==
== Comparisons and Expressions ==

Revision as of 10:08, 13 December 2009

The if statement allows you to execute (or not execute) a block of script commands based on one or more comparisons that you specify. Oblivion's if command is very powerful and comparable to "real" programming languages.


Overview

An if statement uses the following syntax:

if expressionA [comparison] expressionB
; test "expressionA [comparison] expressionB" passed
elseif expressionB [comparison] expressionC
; test "expressionB [comparison] expressionC" passed
else
; none of the above tests passed
endif

The else and elseif statements are optional.


Comparison Operators

An if statement may contain one or more comparison operators. Below is a table of valid comparison operators:

Operator Description
== Exactly equal to
!= Not equal to
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to

It is important to note that there are no bitwise comparisons available in Oblivion's scripting language.

NOTE: <> and >< are used often in other programming languages, but not in Oblivion's scripting language. While they do not register as errors when saved in a script in the CS, they will not work in-game.

Combining Comparisons

Comparisons can be linked together using the following logical operators:

Operator Description Example
&& Logical AND if x == 1 && y == 1 ; considered true only if both x and y equal 1.
|| Logical OR if x == 1 || y == 1 ; considered true unless both x and y equal 0.


Note that "||" is evaluated before "&&": "||" has precedence over "&&", just like "*" is evaluated before "+" in normal algebra. Which also shows an opposite behaviour from the standard operator notations for scripting conditional expressions (IF statements), and needs to be clarified, as it impacts the design of boolean expressions: in arithmetic and algebra, from the earliest use of mathematical notation, multiplication took precedence over addition, and the standard order of operators is: 1-exponents and roots; 2-multiplication and division; 3-addition and subtraction;

  • In terms of computing, we're talking about a precedence number order, and operator precedence is usually ordered with the corresponding number order. For expressions where two operators of different precedences compete for the same operand, the operator with the higher precedence wins.
  • functions have precedence over comparision and arithmetic operators, which themselves always have precedence over logical operators ("||" and "&&").
  • In Common operator notation involving "normal" algebra or boolean algebra, "*" ("&&") is always evaluated before "+" ("||"), it has a higher precedence number than the "+" operator. For example, 3×4+5 = ((3×4)+5), not (3×(4+5)). However, this is not the case with Oblivion's scripting language, since OR ("||") has a higher precedence than AND ("&&"):
    if myVar1 == 1 && myVar2 == 1 || myVar2 == 5
    is equivalent to
    if myVar1 == 1 && (myVar2 == 1 || myVar2 == 5)
    This is true when MyVar1 = 1 AND myVar2 is either 1 or 5.

    If you need the "&&" comparision operator to be evaluated before the "||" (OR) operator, you must include its part in-between parentheses. In this case:
    if (myVar1 == 1 && myVar2 == 1) || myVar2 == 5
    is true when either myVar2 is 5 OR both, myVar1 and myVar2 are 1.

The later also explains why one has to be very careful in positioning conditions in a condition list of an editor item: for the CS/OB's engine, OR has order preference, has precedence over AND. For example, the condition items (A AND B OR C AND D) are evaluated as (A AND (B OR C) AND D), and not (( A AND B) OR (C AND D)), as opposed to common operator notation for most languages. In general, we call this an inversed or negative notation. Always keep the later in mind when applying boolean algebra for evaluating some given expression when scripting, as standard operator notations will lead you to errors.

Oblivion evaluates entire If statement

Oblivion evaluates all the conditions for an IF statement. For example, when you combine expressions with "&&", if the first expression is false, later expressions will still be evaluated, even though they are irrelevant (false && anything = always false, true || anything = always true).

This can also result in unexpected errors, such as below:

If (ReferenceVariable != 0) && (ReferenceVariable.Getav Health < 30)

This crashes Oblivion if the reference variable is undefined ("0"), because the second part is still evaluated. In such cases you need to use nested IF-blocks instead:

If ReferenceVariable != 0
   If ReferenceVariable.Getav Health < 30

Since boolean conditions (&& ||) are inefficient and implemented poorly in Oblivion, use nested IF-blocks whenever possible.

Comparisons and Expressions

The comparison operators can be used with any expression that can be evaluated into a number. Assuming "a = 17", "b = 20" and "c = a - b", all of the following expressions work as expected. Parentheses are only needed when they're necessary for mathematical reasons.

IF c == -3 && b == 20
IF c == -3 && b == 20 && a == 17
IF c - 1 == -4 && b == 20 && a == 17
IF a - 20 == 17 - b
IF a - 20 == 17 - b && c + 3 == 0
IF a + 3 == b
IF a - b == c
IF a *4 - b * 4 == c * 4
IF a * ( 5 + c ) - 14 == b
IF 2*(a*(5+c)-14)==b - -b

If a variable or the result of a function returns 1 or 0, or you're just interested in whether the result is 0 or not you don't need to test on "== 1" or "!=0"

IF Done
IF Getisid MyNPC
IF Getitemcount Lockpick
IF IsActor && Flag

Do the same as

IF Done != 0
IF Getisid MyNPC != 0
IF Getitemcount Lockpick != 0
IF IsActor != 0 && Flag != 0


Assignment

The result of logical expressions can be saved to variables just like the results of mathematical expressions. E.g. you can do this:

set bResult to c == -3 && b == 20
set bTest to c == -3 && b == 20 && a == 17

You can use this to invert a logical value:

set bValue to ( bValue == 0 )

If bValue is intially 1 (True), then it will be reset to 0 (False). Or if initially 0 (False), it will be reset to 1 (True).

Notes

Keep in mind that the script parser doesn't accept one-lined statments. While

if condition==1 set varname to 1
else set varname to 2

works in other programming languages, you need to split this up for Oblivion.

if condition==1
  set varname to 1
else
  set varname to 2
endif

(it's more readable too...)


After the condition or the "else" statement the rest of the line is ignored. There aren't any error messages to warn you, so (since the line appears to be correct) you might spend a lot of time locating the source of the problem.

Spaces and Tabs

When using Tabs or Spaces to separate operators/expressions you need to use the same separator on each side. If you use Space on one side and Tab on the other, the script might be permanently stopped when the line is executed.

  if SomeVar>=1           ;GOOD
  if (SomeVar>=1)         ;GOOD
  if ( SomeVar >= 1 )     ;GOOD
  if (SomeVar___>=___1)   ;GOOD ( "___" = Tab) 
  if___(SomeVar >= 1)     ;GOOD ( Tab before "(" and nothing after it is okay) 
  if ( SomeVar ___>=___1) ;GOOD ( Spaces around "SomeVar"), tabs around ">=") 
  if ( SomeVar___>=___1);BAD  ( Space and Tab around "SomeVar" causes problems)
  if___SomeVar >= 1     ;BAD  ( Tab and Space around "SomeVar")
  if (___SomeVar >= 1)  ;BAD  ( Space and Tab around "(")  
  if___( SomeVar >= 1)  ;BAD  ( Tab and Space around "(") 
  if SomeVar >=___1     ;BAD  ( Space and Tab around ">=")  
  if (SomeVar___>= 1)   ;BAD  ( Tab and Space around ">=")  

Note that you will not receive any compiler error or warnings. You only notice the script not working correctly. You can determine if the problem is caused by this by examining the script in an external text-editor or by looking directly at the compiled script data.