The .animated object format
动画物体格式


此处由 Steve_xmh 翻译 仍在施工!

■ Contents 目录

1. 简介
2. 段落结构
3. 运算符
4. 函数
5. 变量
6. 性能
7. 提示
8. 函数范例
9. 格式化语法



■ 1. 简介

动画(.animated)物体格式使你可以引用组合其他的多个模型(B3D/CSV/...)并给它们添加动画。

除了制作动画之外,你也能只用它来组合多个模型(包括其他的动画(.animated)物体)。

动画物体可以用在 CSV/RW 格式的线路中(除了某些特别的指令不允许使用),或者是在列车的 extensions.cfg 文件中作为一个列车外部模型对象(比如开关车门等),或者是在 panel.animated 文件中作为3D驾驶室中的动画物体(比如控制杆,速度指针等)。


● 基本格式

动画是通过以下类型的语句实现的:

  状态变化 —— 简单的在不同的时间点切换成不同的对象
  坐标变换 —— 在三个独立的方向轴(XYZ)上移动物体
  角度变换 —— 在三个独立的轴(XYZ)上旋转物体
  纹理变换 —— 允许在两个独立的方向(UV)上移动对象的纹理坐标


● 一点点编码格式

这个动画文件可以是任何 编码格式的纯文本文件, 但是,使用 UTF-8 编码是最佳的选择。 数字的 解析格式是严格的。 文件名可以是任意的,但是后缀名必须为 .animated。 这个文件将会从上到下通过分析各行的数据进行解释。



■ 2. 段落结构


[Include] 段落


你可以使用 [Include] 段落来引入组合其他的模型,这可以让你将动画物体作为一个容器来组织你的物体。当然 [Include] 段落的数量是随意的,你可以给任意数量的对象进行分组操作。

[Include]

这将开始这个段落。

文件名或路径 0
文件名或路径 1
文件名或路径 2
...

定义一系列的 B3D/CSV/X/ANIMATED 模型对象来组合在一起。

Position = X, Y, Z
将你引入的模型按照三维坐标来偏移。对于其下的文件都有效。



[Object] 段落


你可以使用 [Object] 段落来创建一个普通的动画。这需要你通过 States 参数设置至少一个状态,并使用相应的函数来控制动画。 [Object] 段落数量也是随意的。

[Object]

这个是段落的开头。

Position = X坐标, Y坐标, Z坐标

定义对象的整体位置。这将会相对于 CSV/B3d 文件中的最终位置坐标而偏移,但这个指令将会在解析最后才被执行。例如你如果需要旋转对象, 此时旋转的的中心点仍然是原点 (0,0,0),Position 命令只会在旋转之后来才会进行偏移坐标操作。

States = 文件 0 , 文件 1 , ..., 文件 n-1

加载n个 CSV/B3D/X 模型对象,每加载一个文件就会自带一个状态索引值,从第一个文件开始为 0 不断递增,一般当你需要使用状态变化的时候才需要使用多个文件。这样你可以在多个物体之间选择一个显示或不显示。

StateFunction = 式子

这个指令指定状态变化所遵循的式子,其值将会被四舍五入到整数,如果这个整数在 0 ~ n-1 之间(n为你使用 States 指令时所设定的状态数量),那么这样将会显示出相应的状态,如果索引值指向的对象不存在,则不会显示任何物体。如果你需要做出一个物体的开关效果,可以选择后者。

TranslateXDirection = X坐标, Y坐标, Z坐标
TranslateYDirection = X坐标, Y坐标, Z坐标
TranslateZDirection = X坐标, Y坐标, Z坐标

这将会定义 TranslateXFunctionTranslateYFunctionTranslateZFunction的偏移方向,默认方向是:

TranslateXDirection = 1, 0, 0
TranslateYDirection = 0, 1, 0
TranslateZDirection = 0, 0, 1

这样意味着 TranslateXFunction将会默认向右移动, TranslateYFunction默认向上移动, TranslateZFunction默认向前移动,这也是为什么这样命名的原因。如果你要定义其他方向的话,那么只需要考虑三个函数和相关方向的独立公式即可。在大多数情况下,您不需要使用这三个指令。

TranslateXFunction = 式子
TranslateYFunction = 式子
TranslateZFunction = 式子

这个指令指定的式子将对象偏移到相应方向。式子需要返回从原位置移动的米数。三个Translate*Direction将会和式子相乘得出最终结果,所以如果你想让车门甩飞(误)让物体运动速度加快的话,那么可以尝试把式子乘以二或者是方向轴乘以二。

RotateXDirection = X坐标, Y坐标, Z坐标
RotateYDirection = X坐标, Y坐标, Z坐标
RotateZDirection = X坐标, Y坐标, Z坐标

这将会分别定义 RotateXFunction, RotateYFunctionRotateZFunction, 的旋转方向。默认方向是:

RotateXDirection = 1, 0, 0
RotateYDirection = 0, 1, 0
RotateZDirection = 0, 0, 1

这样意味着 RotateXFunction将会默认绕X轴旋转, RotateYFunction默认绕Y轴, RotateZFunction默认绕Z轴,这也是为什么这样命名的原因。如果你要定义其他方向的话,那么只需要考虑三个函数和相关方向的独立公式即可。在大多数情况下,您不需要使用这三个指令。

RotateXFunction = 式子
RotateYFunction = 式子
RotateZFunction = 式子

这些式子指定了将物体在相应的方向上逆时针旋转的度数。 式子的结果应该是所需要旋转度数的弧度制形式。旋转的默认顺序是X->Y->Z。如果你需要进行多个轴上的旋转,设计时请记好这个顺序。 如果必须使用不同的顺序,请使用Rotate*Direction指令重新定义轴向。

RotateXDamping = NaturalFrequency, DampingRatio
RotateYDamping = NaturalFrequency, DampingRatio
RotateZDamping = NaturalFrequency, DampingRatio

这个指令定义相关的旋转的阻尼系数。如果没有指定,旋转就没有阻尼效果, 自然速率是一个代表对应旋转运动理想无阻力时的角速度的非负值。单位是弧度每秒。 阻尼比 是一个代表阻尼成都的非负值。0与1之间代表阻尼不足,1代表临界阻尼,1以上代表过阻尼。详情请查阅对应的物理文献。

TextureShiftXDirection = X, Y
TextureShiftYDirection = X, Y

这定义了对应的 TextureShiftXFunctionTextureShiftYFunction的方向。默认方向是:

TextureShiftXDirection = 1, 0
TextureShiftYDirection = 0, 1

这样意味着 TranslateXFunction将会默认正方向向右偏移, TranslateYFunction默认正方向向下偏移, 这也是为什么这样命名的原因。如果你要定义其他方向的话,那么只需要考虑函数和相关方向的独立公式即可。在大多数情况下,您不需要使用这两个指令。

TextureShiftXFunction = 式子
TextureShiftYFunction = 式子

这个式子在对应的方向偏移材质的UV坐标。材质坐标按照 式子的结果偏移。结果的整数部分被忽略,0.5的小数代表把材质偏移一半。最终结果是式子结果和材质中UV坐标之和。


TrackFollowerFunction = 式子

这个式子将物体沿着 Rail 0(主轨道)移动一定的距离。 式子需要返回物体以米为单位的移动距离,并受 of Rail 0(主轨道)的弯曲转折影响。

TextureOverride = Value

Value = Timetable: 该物体的所有面都会显示CSV/RW线路中所指定的时刻表图片。
Value = None: 不改变物体材质 (默认)。

RefreshRate = Seconds

这个指令定义了物体动画状态刷新的间隔。当值等于0时,物体将被每帧刷新一次。请注意不论取值如何,可视范围外的物体的刷新频率都会更低。你可以在不需要一个十分平滑的动画(这可以优化性能),或你希望物体以一个固定的时间频率变动时,你可以使用这个指令。


    openBVE 2 兼容性注意事项:
在openBVE(v0.9)和动画模型格式的开发进程中,设计了几个名字以 RPN结尾的指令,例如 TranslateXFunctionRPN。这些指令早已过时,在正式版本(v1.0)中已被弃用,不应在开发环境外使用。虽然openBVE仍然保留了对这些指令的运行支持,它们仍然被计划在openBVE 2中彻底删除。如果你还在用这几个指令,趁早扔了吧!
 



● 关于式子

首先,你输入 式子的符号都会被转换为函数。因此对于每个运算符都有对应的函数,而一些函数则没有与运算符对应,于是只能以函数形式输入。计算顺序在运算符中意义很大。你可以像在数学式里面一样使用括号改变计算顺序。函数的名字不分大小写。

    请注意:如果某个数学计算的结果是正负无穷或虚数,它会被视作0。openBVE不负责处理数值溢出问题,请自行考虑。  



■ 3. 运算符


● 基本数学运算符

运算符形式 函数形式 描述
a + b Plus[ a, b, ...] 加法
a - b Subtract[ a, b] 减法
- a Minus[ a] 取相反数
a * b Times[ a, b,...] 乘法
a / b Divide[ a, b] 除法


● 比较

比较条件成立时结果为1,不成立时为0。

运算符形式 函数形式 说明
a == b Equal[ a, b] 如果 a 等于 b 则成立
a != b Unequal[ a, b] 如果 a 不等于 b 则成立
a < b Less[ a, b] 如果 a 小于 b 则成立
a > b Greater[ a, b] 如果 a 大于 b 则成立
a <= b LessEqual[ a, b] 如果 a 小于等于 b 则成立
a >= b GreaterEqual[ a, b] 如果 a 大于等于 b 则成立


● Logical operations

All operations treat 0 as false and any other value as true, and return 1 for true and 0 for false.

Infix Functional Description
! a Not[ a] True (1) if a is false
a & b And[ a, b] True (1) if both a and b are true
a | b Or[ a, b] True (1) if any of a or b are true
a ^ b Xor[ a, b] True (1) if either a or b is true


● Operator precedence

From highest precedence to lowest. Operators of same precedence are evaluated left to right in the order in they occur in the formula.

a[...]
- (Minus)
/
*
+, - (Subtract)
==, !=, <, >, <=, >=
!
&
^
|

    Please note that some combinations of prefix and infix operators are not recognized. For example a*-b is not accepted. Use a*(-b) or -a*b instead.  



■ 4. List of functions


● Basic arithmetics

Function Description
Reciprocal[ x] Returns the reciprocal, equal to 1/ x
Power[ a, b,...] Returns a raised to the b th power. b must be a non-negative number. For consistency, Power[0, b] always returns 1, even in the degenerate case Power[0,0], and a being negative always returns 0. Adding more arguments will create a chain. Power[a,b,c] will return a b c .


● Numeric functions

Function Description
Quotient[ a, b] Divides a by b and rounds the result down, equal to Floor[a/b].
Mod[ a, b] Returns the remainder of dividing a by b, equal to a-b*Floor[a/b].
Min[ a, b,...] Returns the smallest of the terms.
Max[ a, b,...] Returns the largest of the terms.
Abs[ x] Returns the absolute value.
Sign[ x] Returns the sign of x, which is either -1, 0 or 1.
Floor[ x] Rounds down to the nearest integer.
Ceiling[ x] Rounds up to the nearest integer.
Round[ x] Rounds to the nearest integer. Numbers ending in .5 are rounded to the nearest even integer.
random[ Minimum, Maximum] Returns a new random floating-point number between Minimum and Maximum.
randomInt[ Minimum, Maximum] Returns a new random integer between Minimum and Maximum.


● Elementary functions

Function Description
Exp[ x] The exponential function, or e to the x th power.
Log[ x] The natural logarithm, to base e.
Sqrt[x] The square root.
Sin[ x] The sine (input in radians).
Cos[ x] The cosine (input in radians).
Tan[ x] The tangent (input in radians).
ArcTan[ x] The inverse tangent (output in radians).


● Conditionals

Function Description
If[ cond, truevalue, falsevalue] If cond is != 0, returns truevalue, otherwise falsevalue



■ 5. 变量


● 基础

变量 描述
value 这个式子上一次计算的结果。第一次计算时为0。
delta 从上次计算这一式子到现在相隔的时间,以秒为单位。请注意openBVE不能保证式子两次计算之间的时间间隔永远相等。
currentState 物体目前所处的状态编号。


● 时间和视角

变量 描述
time 从游戏中第一天的午夜开始算起的秒数。
cameraDistance 物体与游戏视角摄像机之间的几何距离,以米为单位。
cameraMode 0代表游戏正处于司机室视角,1反之。


● 列车

一般来说,指派到列车模型的动画物体中的变量返回对应列车和车厢的对应参数,除非指定了其他的车厢编号。 而外景物体中的变量则反映距离其最近的列车的司机室所在车厢的情况(不一定是玩家列车)。

在下方一些变量中, 车厢编号代表这一意味:0是前方第1节车厢,1是前方第2节,以此类推;而-1代表尾部第1节,-2代表尾部第2节,同样以此类推。总的来说,由 - 车厢总数 to 车厢总数-1 的数字代表存在的车厢,而其他的代表不存在的车厢。由于列车至少有一节车厢,0和-1这两个车厢编号总是存在的。


● 列车(总体)

变量 描述
cars 列车的车厢总数。
speed 当前车厢的有符号实际速度,单位为m/s。向前为正,向后为负。
speed[ 车厢编号] 对应车厢的有符号实际速度,单位为m/s。向前为正,向后为负。
speedometer The signed perceived speed of the current car in m/s as it would appear to a speedometer on wheel slip and wheel lock.
speedometer[ 车厢编号] The signed perceived speed of the car 车厢编号 in m/s as it would appear to a speedometer on wheel slip and wheel lock.
acceleration The actual acceleration of the current car in m/s².
acceleration[ 车厢编号] The actual acceleration of the car 车厢编号 in m/s².
accelerationMotor The acceleration which the motor of the first motor car currently generates in m/s².
accelerationMotor[ 车厢编号] The acceleration which the motor of the car 车厢编号 currently generates in m/s².
distance The non-negative cartesian distance measured from the object to the closest car in meters. Only meaningful for scenery objects.
distance[ 车厢编号] The non-negative cartesian distance measured from the object to the car 车厢编号 in meters, or 0 if the car does not exist. Only meaningful for scenery objects.
trackDistance The signed track distance measured from the object to the closest end of the nearest train in meters. Is positive when the train is in front of the object, negative when behind, and zero when the object lies between the ends of the train.
trackDistance[ 车厢编号] The signed track distance measured from the object to the car 车厢编号 of the nearest train in meters. Is positive when the center of the car is in front of the object, and negative if behind. Returns 0 if the car does not exist. Only meaningful for scenery objects.


● Trains (brake)

Variable Description
mainReservoir The current pressure in the main reservoir in this car, measured in Pa.
mainReservoir[ 车厢编号] The current pressure in the main reservoir in car 车厢编号, measured in Pa.
emergencyReservoir The current pressure in the emergency reservoir in this car, measured in Pa.
emergencyReservoir[ 车厢编号] The current pressure in the emergency reservoir in car 车厢编号, measured in Pa.
brakePipe The current pressure in the brake pipe in this car, measured in Pa.
brakePipe[ 车厢编号] The current pressure in the brake pipe in car 车厢编号, measured in Pa.
brakeCylinder The current pressure in the brake cylinder in this car, measured in Pa.
brakeCylinder[ 车厢编号] The current pressure in the brake cylinder in car 车厢编号, measured in Pa.
straightAirPipe The current pressure in the straight air pipe in this car, measured in Pa.
straightAirPipe[ 车厢编号] The current pressure in the straight air pipe in car 车厢编号, measured in Pa.


● Trains (doors)

Variable Description
doors The state of the doors. Returns 0 if fully closed, 1 if fully opened, or any intermediate value, biasing doors that are in a more open state.
doors[ 车厢编号] The state of the doors of car 车厢编号. Returns 0 if fully closed, 1 if fully opened, or any intermediate value, biasing doors that are in a more open state.
leftDoors The state of the left doors. Returns 0 if fully closed, 1 if fully opened, or any intermediate value, biasing doors that are in a more open state.
leftDoors[ 车厢编号] The state of the left doors of car 车厢编号. Returns a value between 0 and 1, biasing doors that are in a more open state, or -1 if the car does not exist.
rightDoors The state of the right doors. Returns 0 if fully closed, 1 if fully opened, or any intermediate value, biasing doors that are in a more open state.
rightDoors[ 车厢编号] The state of the right doors of car 车厢编号. Returns a value between 0 and 1, biasing doors that are in a more open state, or -1 if the car does not exist.
leftDoorsTarget The anticipated target state of the left doors. Returns either 0 (closed) or 1 (opened).
leftDoorsTarget[ 车厢编号] The anticipated target state of the left doors of car 车厢编号. Returns either 0 (closed) or 1 (opened).
rightDoorsTarget The anticipated target state of the right doors. Returns either 0 (closed) or 1 (opened).
rightDoorsTarget[ 车厢编号] The anticipated target state of the right doors of car 车厢编号. Returns either 0 (closed) or 1 (opened).
leftDoorsButton The state of the left doors button. Returns either 0 (released) or 1 (pressed).
rightDoorsButton The state of the right doors button. Returns either 0 (released) or 1 (pressed).


● Trains (miscellaneous)

Variable Description
reverserNotch The state of the reverser, which is either -1 (backward), 0 (neutral), or forward (1).
powerNotch The current power notch, i.e. 0 for N, 1 for P1, 2 for P2, 3 for P3, etc.
powerNotches The amount of power notches the train has.
brakeNotch The current brake notch.
  For trains without the automatic air brake: 0 for N, 1 for B1, 2 for B2, 3 for B3, etc.
  For trains with the automatic air brake: 0 for REL, 1 for LAP and 2 for SRV.
brakeNotches The amount of brake notches the train has. For trains with the automatic air brake, this returns 2.
brakeNotchLinear A combination of brake notch, hold brake and emergency brake.
  For trains without the automatic air brake and without hold brake: 0 for N, 1 for B1, 2 for B2, 3 for B3, etc., up to BrakeNotches+1 for EMG.
  For trains without the automatic air brake but with hold brake: 0 for N, 1 for HLD, 2 for B1, 3 for B2, 4 for B3, etc., up to BrakeNotches+2 for EMG.
  For trains with the automatic air brake: 0 for REL, 1 for LAP, 2 for SRV or 3 for EMG.
brakeNotchesLinear The highest value returned by brakeNotchesLinear.
  For trains without the automatic air brake and without hold brake, this is BrakeNotches+1.
  For trains without the automatic air brake but with hold brake, this is BrakeNotches+2.
  For trains with the automatic air brake, this returns 3.
emergencyBrake Whether the emergency brake is currently active (1) or not (0).
hasAirBrake Whether the train has the automatic air brake (1) or not (0).
holdBrake Whether the hold brake is currently active (1) or not (0).
hasHoldBrake Whether the train has a hold brake (1) or not (0).
constSpeed Whether the const speed system is currently active (1) or not (0).
hasConstSpeed Whether the train has a const speed system (1) or not (0).
hasPlugin Whether the train uses a plugin (1) or not (0).
pluginState[ i] The state of the i th plugin variable, returning an integer depending on the plugin. Is the same as ats i in the panel2.cfg.
FrontAxleCurveRadius[ 车厢编号] Returns the curve radius at the front axle position of car 车厢编号.
RearAxleCurveRadius[ 车厢编号] Returns the curve radius at the rear axle position of car 车厢编号.
CurveCant[ 车厢编号] Returns the cant value for car 车厢编号.
Odometer Returns a signed number representing the distance in meters travelled by the current car.
Odometer[ 车厢编号] Returns a signed number representing the distance in meters travelled by car 车厢编号.
Klaxon Returns the currently playing horn (if any) as follows: (0) No horns are playing (1) The primary horn is playing (2) The secondary horn is playing (3) The music horn is playing. Note If multiple horns are playing, the lowest value will be returned.
PrimaryKlaxon Returns 1 if the primary horn is currently playing, 0 otherwise.
SecondaryKlaxon Returns 1 if the secondary horn is currently playing, 0 otherwise.
MusicKlaxon Returns 1 if the music horn is currently playing, 0 otherwise.

If pluginState[i] is used with the built-in safety systems ATS and ATC, the following mappings for i apply:

i English 日本語 Return values pluginState[271] Meaning
256 ATS ATS 0 (unlit) or 1 (lit) 0 ATC not available
257 ATS RUN ATS 作動 0 (unlit), 1 (lit) or 2 (flashing) 1 0 km/h
258 ATS RUN ATS 作動 0 (unlit / non-flashing), 1 (lit / flashing) 2 15 km/h
259 P POWER P 電源 0 (unlit) or 1 (lit) 3 25 km/h
260 PTN APPROACH パターン接近 0 (unlit) or 1 (lit) 4 45 km/h
261 BRAKE RELEASE ブレーキ開放 0 (unlit) or 1 (lit) 5 55 km/h
262 BRAKE APPLY ブレーキ動作 0 (unlit) or 1 (lit) 6 65 km/h
263 ATS P ATS-P 0 (unlit) or 1 (lit) 7 75 km/h
264 FAILURE 故障 0 (unlit) or 1 (lit) 8 90 km/h
265 ATC ATC 0 (unlit) or 1 (lit) 9 100 km/h
266 ATC POWER ATC 電源 0 (unlit) or 1 (lit) 10 110 km/h
267 ATC SRV ATC 常用 0 (unlit) or 1 (lit) 11 120 km/h
268 ATC EMG ATC 非常 0 (unlit) or 1 (lit) 12 ATS is active
269 CONST SPEED 定速 0 (unlit) or 1 (lit)
270 EB EB 0 (unlit) or 1 (lit)
271 ATC speed indicator 0 - 12, see table on the right


● Sections (signalling)

The section context is defined when the object is placed using Track.SigF.

Variable Description
section The value of the section aspect currently shown.
If this variable is used outside of a Track.SigF context, the behavior is currently undefined and subject to change.



■ 6. Performance

There are certain kinds of animation which are less expensive, and others which are more. Also, the underlying object plays a significant role. If you want to design your animated objects with as best performance as possible for future releases of openBVE, take a look at the following performance table:

Animation Object Performance
State changes Has only opaque faces Good
State changes Has partially transparent faces Moderate
Translation Has only opaque faces Good
Translation Has partially transparent faces Moderate
Rotation Has only opaque faces Good
Rotation Has partially transparent faces Bad
Texture shifts Has only opaque faces Bad
Texture shifts Has partially transparent faces Bad

Performance is generally better if the result of a function only infrequently changes. So, even if you set the RefreshRate parameter to zero, performance is generally better if the outcome of your formula is constant over longer periods of time. On the other hand, if it changes every frame, performance is generally worse.

Generally, you should avoid using animation with partially transparent faces and stick to opaque faces when possible. Also, try to avoid texture shifts, and consider using state changes or translation where possible.



■ 7. Tips


  Generally speaking, try to keep the complexity of functions as low as possible. This is not the most critical aspect, though, as most of the performance impact will result from applying the results of a function, e.g. rotating the object, and not evaluating the function.

  Use the RefreshRate parameter when possible to optimize performance. Usually, you can use this parameter when you don't need a smooth animation, or when you deliberately want the functions to only update in intervals.

  Don't use functions which always evaluate to the same constant. For example, don't use RotateXFunction = 3.14159, but rotate the underlying CSV/B3D/X object directly.

  State changes are very cheap as long as the state doesn't actually change in between two executions of the StateFunction. If a change occurs, this is a relatively expensive operation, though.

  Try to optimize out if conditions. Especially try to avoid nested if functions. Often, there is an elegant mathematical solution.

  Certain functions, e.g. Exp, Sin, Cos, etc., are relatively expensive. Use them only if absolutely necessary for an effect. Don't include unnecessary operations. For example, the result of StateFunction is automatically rounded toward the nearest integer, so don't apply an additional explicit Round.

  When working with car objects, bear in mind that some variables have an optional car index. You should use this index if you want to query the state of a particular car (that is, not necessarily the one the object is attached to). If, however, you just want to query the value of the particular car the object is attached to, use the variable without the index. For scenery objects, you should not generally use car indices as you can't be sure how many cars the queried train has.



■ 8. Example functions



● Blinking light

States = OBJECT0, OBJECT1
StateFunction = value == 0
RefreshRate = SECONDS



● Rotating wheel

States = OBJECT
RotateXFunction = value + delta * speedometer / RADIUS_OF_THE_WHEEL



● Cycling through a list of objects

States = OBJECT0, OBJECT1, OBJECT2, ...
StateFunction = mod[value + 1, AMOUNT_OF_OBJECTS]
RefreshRate = TIME_PER_OBJECT



● Signal (3-aspect) for Track.Section(0; 2; 4)

States = RED_OBJECT, YELLOW_OBJECT, GREEN_OBJECT
StateFunction = section / 2



● Employing an approach-controlled delay in signals

If you want to create a signal that keeps being red until the train approaches it to some distance, then counts down a timer before it changes aspect to green, please refer to this post on the forum for a detailed explanation. Once you understand the concepts, you can use this code template:
States = RED_OBJECT, GREEN_OBJECT
StateFunction = if[trackDistance>DISTANCE | section==0, 0, min[value + 0.5*delta/DELAY, 1]]

States = RED_OBJECT, ..., GREEN_OBJECT
StateFunction = if[trackDistance>DISTANCE | section==0, 0, if[value<0.5, value + 0.5*value/DELAY, section]]



■ 9. Formal Grammar
The formal grammar for the language may not match up perfectly with the implimentation included in OpenBVE. An example is a*-b which is valid under the grammar but the parser rejects it.
<expression>        ::= <xor_expression> "" <expression>     | <xor_expression>
<xor_expression>    ::= <or_expression>  "^" <xor_expression> | <or_expression>
<or_expression>     ::= <not_expression> "|" <or_expression>  | <not_expression>

<not_expression>    ::= "!" <equal_expression> | <equal_expression>

<equal_expression>  ::= <plus_expression> "==" <equal_expression> | <plus_expression> "!=" <equal_expression> |
                        <plus_expression> ">"  <equal_expression> | <plus_expression> "<"  <equal_expression> |
                        <plus_expression> "<=" <equal_expression> | <plus_expression> "<=" <equal_expression> | <plus_expression>

<plus_expression>   ::= <times_expression> "+" <plus_expression>  | <times_expression> "-" <plus_expression> | <times_expression>

<times_expression>  ::= <divide_expression> "*" <times_expression>  | <divide_expression>
<divide_expression> ::= <minus_expression>  "/" <divide_expression> | <minus_expression>

<minus_expression>  ::= "-" <function_call> | <function_call>
<function_call>     ::= <name> "[" <expression> ("," <expression>)* "]" | <term>

<term>   ::= "(" <expression> ")" | <name> | <number>
<number> ::= <digit>*
<name>   ::= <letter> (<letter> | <digit>)*

<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" |
             "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" |
             "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" |
             "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
<digit>  ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"