Oblivion XML Reference/Operators

Revision as of 13:30, 18 June 2018 by imported>DavidJCobb (→‎Other operators: listed)

Operators act as a stack of sorts. Each operator element has its own value (either as the contents of its XML tag, or pulled from another element via the src and trait attributes) and it returns a value, operating with awareness of its previous sibling’s returned value.

Trait elements can only contain raw number values, raw string values, or operator child elements. Operator elements can generally only contain raw number values or operator child elements. Besides copy, there are no string operators. Here are some examples of operators:

  <copy>3</copy>
  <copy src="other_tile" trait="other_trait" />
  <add>3</add>
  <add src="other_tile" trait="other_trait" />
   
  <copy>&true;</copy> <!-- "&true;" equals "2" under the hood -->

Operators can also be nested up to any depth:

  <copy>3</copy>
  <mult>
     <copy>1</copy>
     <add>2</add>
  </mult>
  <!--
     This code computes: 3 * (1 + 2)
  -->

The following terms are used when explaining operators:

argument
The value inside of an operator's tags.
current working value
The value that has been computed right up to an operator being processed.
to select
To pull a value from somewhere else, using the src and trait attributes.
to return
The act of providing a result. As an example, the mult operator multiplies the argument by the current working value, and "returns" the result. The returned value then becomes the next operator's current working value.

In the above code sample, the add operator has a current working value of 1, and an argument of 2.

Copy operator

The copy operator is used to overwrite the current working value:

  <copy>3</copy>
  <add>2</add>
  <!-- Current working value: 3 + 2 -->
  <copy>1</copy>
  <!-- Current working value: 1 -->

However, the copy operator can also be used to implement XML switch-cases. If the current working value is a number, and the copy operator selects a trait whose name starts and ends with an underscore, then that trait is treated as a list of choices suffixed with numbers:

  <_traitName_1> First Value </_traitName_1>
  <_traitName_2> Second Value </_traitName_2>
  <_traitName_3> Third Value </_traitName_3>
  
  <string>
     <copy>2</copy>
     <add>1</add>
     <copy src="me()" trait="_traitName_" />
  </string>

In that code example, the current working value is (2 + 1), or 3. The last copy operator selects a trait bordered by underscores (_traitName_), so the current working value is tacked onto that trait name (_traitName_3), and the resulting trait's value is returned. The underscore-bordered traits are referred to as cases.

The utility of this is that you can switch-case on any value. For example, the RepairMenu is actually used for selecting an item to repair, selecting an ingredient to add to a potion, or selecting a soul gem to use for an enchantment. The user0 trait on the menu identifies what it's being used for. That means you can do something like this:

  <text name="menu_title">
     <_title_1> Repair your gear </_title_1>
     <_title_2> Pay a merchant to repair gear </_title_2>
     <_title_3> Select an alchemy ingredient </_title_3>
     <_title_4> Select an item to enchant </_title_4>
     <_title_5> Select a soul gem to enchant with </_title_5>
     <_title_6> Select a sigil stone </_title_6>
     
     <string>
        <copy src="RepairMenu" trait="user0" />
        <copy src="me()" trait="_title_" />
     </string>
  </text>

There are a few caveats to keep in mind regarding XML switch-cases:

  • The zeroth (0) case will never be used.
  • If the copy operator ends up looking for a missing trait, then the number zero will be returned — not an empty string.
  • The switch-case feature doesn't handle trait names properly if they contain an underscore in the middle, e.g. _trait_name_3. The XML properly extracts the 3, but it will then look for _trait_3.
  • According to Bethesda’s code comments (in the stats menu), switch-cased strings only work on the first frame if the cases are defined before the copy operator is used.

Other operators

abs
If the current working value is less than zero, then the operator’s argument is added to it, and the operator returns the absolute value of the result. Otherwise, the current working value is returned verbatim.
add
Adds its value to the current working value, and returns the result.
and
Returns &true; if both the current working value and the operator’s argument evaluate to &true;, or &false;
ceil
Returns the current working value rounded up to the nearest integer. Disassembly of the executable suggests that the operator’s argument is added to the current working value before the rounding is performed.
div
Divides the current working value by the argument, and returns the result.
eq
Returns &true; if the current working value is equal to the argument, or &false; otherwise. Note that this operator only works on floating-point values; it always returns false for strings.
floor
trunc
Returns the current working value rounded down to the nearest integer. Disassembly of the executable suggests that the operator’s argument is added to the current working value before the rounding is performed.
The trunc tag isn’t used in any vanilla menus, but its meaning was verified through examining the executable.
gt
Returns &true; if the current working value is greater than its value, or &false; otherwise.
gte
Returns &true; if the current working value is greater than or equal to its value, or &false; otherwise.
log
Computes and returns the base-10 logarithm of the current working value. Disassembly suggests that the operator’s argument is not used.
ln
Computes and returns the natural logarithm of the current working value. Disassembly suggests that the operator’s argument is not used.
lt
Returns &true; if the current working value is less than the argument, or &false; otherwise.
lte
Returns &true; if the current working value is less than or equal to its value, or &false; otherwise.
max
Compares the argument to the current working value, and returns whichever value is larger.
min
Compares the argument to the current working value, and returns whichever value is smaller.
mod
Returns the current working value modulo the operator’s argument.
mul
mult
Multiplies the current working value by the argument, and returns the result.
neq
Returns &true; if the current working value is not equal to the argument, or &false; otherwise.
not
Casts the argument to a Boolean, inverts it, and returns the result.
onlyif
Returns the current working value if the operator’s argument evaluates to &true;, or zero otherwise.
onlyifnot
Returns the current working value if the operator’s argument evaluates to &false;, or zero otherwise.
or
Returns &true; if one or both of the current working value and the operator’s argument evaluate to &true;.
rand
Sets the current working value to a random integer between 1 and the operator’s argument, inclusive.
ref
This operator generally does nothing, and is completely ignored. It is only handled by keyboard navigation.
sub
Subtracts the argument from the current working value, and returns the result.