Difference between revisions of "NMLTutorial/Callback and switch"
(about callbacks and switches) |
m (use <return> in switch blocks, as an identifier isn't a ''return value'' (but a reference to a different block)) |
||
(7 intermediate revisions by 2 users not shown) | |||
Line 11: | Line 11: | ||
Callbacks are defined in the [[NMLTutorial/Item#Graphics block|graphics block]] of the item block and from there they can either directly return a value or point to a switch or spritegroup. Let's look at the graphics block once more: |
Callbacks are defined in the [[NMLTutorial/Item#Graphics block|graphics block]] of the item block and from there they can either directly return a value or point to a switch or spritegroup. Let's look at the graphics block once more: |
||
− | <pre |
+ | <pre class="pseudo"> |
item { |
item { |
||
graphics { |
graphics { |
||
− | callback: <identifier>|<return_value>; |
+ | <callback>: <identifier>|<return_value>; |
[<callback2>: <identifier2>|<return_value2>;] |
[<callback2>: <identifier2>|<return_value2>;] |
||
[...;] |
[...;] |
||
Line 25: | Line 25: | ||
So for example (using fictional callback names): |
So for example (using fictional callback names): |
||
+ | <pre class="example"> |
||
− | <pre style="color:darkblue; white-space: pre-wrap"> |
||
graphics { |
graphics { |
||
callback_to_spritegroup: spritegroup_identifier; |
callback_to_spritegroup: spritegroup_identifier; |
||
Line 39: | Line 39: | ||
== Switch blocks == |
== Switch blocks == |
||
− | As written in the introduction, switch blocks can be used to make decisions on certain variables. A switch block can be used to decide a callback return value depending on a variable, or to decide what spritegroup to use for the graphics depending on a variable. You need to [http://newgrf-specs.tt-wiki.net/wiki/NML:Properties_and_variables_and_callbacks look up] what variables are available for the feature you're using. Don't forget the [http://newgrf-specs.tt-wiki.net/wiki/NML:General#General_variables general variables] that are available for all features. |
+ | As written in the introduction, switch blocks can be used to make decisions on certain variables. A switch block can be used to decide a callback return value depending on a variable, or to decide what spritegroup to use for the graphics depending on a variable. You need to [http://newgrf-specs.tt-wiki.net/wiki/NML:Properties_and_variables_and_callbacks look up] what variables are available for the feature you're using. Don't forget the [http://newgrf-specs.tt-wiki.net/wiki/NML:General#General_variables general variables] that are available for all features. And instead of a variable you may also use a GRF parameter. |
If you think you can make these decisions using if/else statements, you're wrong. Most variables are only available in a switch block of the feature you're working on. So when working with callbacks and graphics, use switches to make decisions based on variables. |
If you think you can make these decisions using if/else statements, you're wrong. Most variables are only available in a switch block of the feature you're working on. So when working with callbacks and graphics, use switches to make decisions based on variables. |
||
Line 45: | Line 45: | ||
The switch block syntax looks like this: |
The switch block syntax looks like this: |
||
− | <pre |
+ | <pre class="pseudo"> |
− | switch (<feature>, <relation>, <identifier>, < |
+ | switch (<feature>, <relation>, <identifier>, <expression>) { |
− | <range>: < |
+ | <range>: <return>; |
− | <range2>: < |
+ | <range2>: <return2>; |
+ | <default_return>; |
||
− | <default_return_value>; |
||
} |
} |
||
</pre> |
</pre> |
||
* <code><feature></code>: the [[NMLTutorial/NML Syntax#Features|feature]] you're working on. |
* <code><feature></code>: the [[NMLTutorial/NML Syntax#Features|feature]] you're working on. |
||
− | * <code><relation></code>: either <code>SELF</code> or <code>PARENT</code>. This indicates if you want to use the variable of the item itself or that of it's related item. See the NML Documentation on [http://newgrf-specs.tt-wiki.net/wiki/NML:Switch switch blocks] for a table of what these relations are for each feature. |
+ | * <code><relation></code>: either <code>SELF</code> or <code>PARENT</code>. This indicates if you want to use the variable of the item itself or that of it's related item. See the NML Documentation on [http://newgrf-specs.tt-wiki.net/wiki/NML:Switch switch blocks] for a table of what these relations are for each feature. Sometimes it will not be entirely clear which one you need, in that case just try <code>SELF</code> and change it to <code>PARENT</code> if it doesn't work like you think it should. <code>PARENT</code> is mostly needed for things that have to do with randomizations; in other cases <code>SELF</code> mostly does the trick. |
− | * <code><identifier></code>: a self-chosen identifier (name) for this switch. It's useful to start with ''switch_''. |
+ | * <code><identifier></code>: a self-chosen identifier (name) for this switch. It's useful to start with ''switch_'' followed by the name of the item this is a switch for. Like with any other identifier, also these identifiers need to be unique throughout the NML file. |
− | * <code>< |
+ | * <code><expression></code>: A [http://newgrf-specs.tt-wiki.net/wiki/NML:Properties_and_variables_and_callbacks variable] or GRF parameter you want to base this decision on. You may do mathematical calculations on a variable or parameter before having to make a decision on it's value and you may even list multiple expressions in the form of an array (we'll see examples of this later), but just a single variable or parameter if of course also fine. |
− | * <code><range></code>: Either a single value or a subrange from the value range |
+ | * <code><range></code>: Either a single value or a subrange from the value range this expression can result in. If you want to specify a subrange, use <code><range_start>..<range_end></code> |
− | * <code>< |
+ | * <code><return></code>: An identifier to a different switch or spritegroup block, or (when switching a callback) the <code>return</code> keyword followed by a number or string reference. |
− | * <code>< |
+ | * <code><default_return></code>: Like a <code><return_value></code>, but this one is only used if none of the ranges specified above matches the value of the variable. |
Now this may sound rather complicated and I agree that it may be a bit overwhelming when presented like this. Switches are one of the most complicated blocks in NML and they represent the VarAction2 in NFO. In case you're familiar with that: VarAction2 is one of the most complicated things in NFO as well. |
Now this may sound rather complicated and I agree that it may be a bit overwhelming when presented like this. Switches are one of the most complicated blocks in NML and they represent the VarAction2 in NFO. In case you're familiar with that: VarAction2 is one of the most complicated things in NFO as well. |
||
Line 66: | Line 66: | ||
Let's look at a little example showing some of the possibilities of a switch. Note that doesn't have an actual meaning other than showing some of the options. In reality it will be very uncommon that a single switch blocks needs to have a string returned for one range, a number for another range, point to an other switch for yet another range. |
Let's look at a little example showing some of the possibilities of a switch. Note that doesn't have an actual meaning other than showing some of the options. In reality it will be very uncommon that a single switch blocks needs to have a string returned for one range, a number for another range, point to an other switch for yet another range. |
||
+ | <pre class="example"> |
||
− | <pre style="color:darkblue; white-space: pre-wrap"> |
||
switch (FEAT_TRAINS, PARENT, some_vehicle_switch, (position_in_consist) { |
switch (FEAT_TRAINS, PARENT, some_vehicle_switch, (position_in_consist) { |
||
0..2: return string(STRING_FOO_BAR); //return a text message |
0..2: return string(STRING_FOO_BAR); //return a text message |
||
Line 73: | Line 73: | ||
400: switch_other_identifier; //chain to some other switch block |
400: switch_other_identifier; //chain to some other switch block |
||
401: return num_vehs_in_consist + 1; //return a value with a variable access |
401: return num_vehs_in_consist + 1; //return a value with a variable access |
||
− | CB_FAILED; //return a failure result as default |
+ | CB_FAILED; //return a failure result as default |
} |
} |
||
</pre> |
</pre> |
||
Line 79: | Line 79: | ||
Because this particular example returns numbers and strings, it can only be a switch for a callback. Switches used for graphics will (only) return identifiers to spritegroups, for example (this is an actual realistic example for a change): |
Because this particular example returns numbers and strings, it can only be a switch for a callback. Switches used for graphics will (only) return identifiers to spritegroups, for example (this is an actual realistic example for a change): |
||
+ | <pre class="example"> |
||
− | <pre style="color:darkblue; white-space: pre-wrap"> |
||
switch (FEAT_TRAINS, PARENT, some_other_vehicle_switch, (position_in_consist) { |
switch (FEAT_TRAINS, PARENT, some_other_vehicle_switch, (position_in_consist) { |
||
1..2: spritegroup_vehicle_1; //use this for second and third part of articulated vehicle |
1..2: spritegroup_vehicle_1; //use this for second and third part of articulated vehicle |
||
Line 89: | Line 89: | ||
− | There's |
+ | There's much more to say about callbacks and switch blocks, but this is probably intimidating enough already. Next we'll make an articulated tram vehicle to show you where these callbacks and switches go in your NML code. |
{{NMLTutorialNavbar|Road vehicle cargo graphics|Tram}} |
{{NMLTutorialNavbar|Road vehicle cargo graphics|Tram}} |
Latest revision as of 09:44, 30 August 2011
Callbacks allow to do some fancy things on the fly. Where properties are defined static, callbacks allow to change (some) properties depending on the game state (for instance the game year or what cargo a vehicle is refitted to). Apart from that, some callbacks allow things that are not possible from the usual item definition (such as graphic animations or articulated vehicles).
Callbacks are often used in combination with switches. Switches are things that allow to make a decision based on variables. These variables depend on the game state (so if you for instance want to change vehicle properties depending on the game year, you need a switch attached to the callback). Furthermore, switches can be used to "switch graphics" based on the same variables (e.g. pointing to different spritegroups/sets for each part of an articulated vehicle).
Callbacks
What callbacks are available depend on the feature you're working on. Then you can look up the available callbacks in the NML Documentation. These tables list the names of the callbacks, what they do and what value they want to see returned. Some callbacks need to be pointed to spritegroups, while others want a string or number returned.
Callbacks are defined in the graphics block of the item block and from there they can either directly return a value or point to a switch or spritegroup. Let's look at the graphics block once more:
item { graphics { <callback>: <identifier>|<return_value>; [<callback2>: <identifier2>|<return_value2>;] [...;] } }
If you want to point the callback to a different block (a switch block or a spritegroup block), you just put the identifier of that block behind the name of the callback. If you want the callback to return a value (string or number) directly, you need to first write the keyword return
and then the numeric value or string()
.
So for example (using fictional callback names):
graphics { callback_to_spritegroup: spritegroup_identifier; callback_to_switch: switch_identifier; callback_return_string: return string(STR_STRINGNAME); callback_return_number: return 20; default: spritegroup_default_graphics; }
Please note that all callbacks need to be defined in a single graphics block.
Switch blocks
As written in the introduction, switch blocks can be used to make decisions on certain variables. A switch block can be used to decide a callback return value depending on a variable, or to decide what spritegroup to use for the graphics depending on a variable. You need to look up what variables are available for the feature you're using. Don't forget the general variables that are available for all features. And instead of a variable you may also use a GRF parameter.
If you think you can make these decisions using if/else statements, you're wrong. Most variables are only available in a switch block of the feature you're working on. So when working with callbacks and graphics, use switches to make decisions based on variables.
The switch block syntax looks like this:
switch (<feature>, <relation>, <identifier>, <expression>) { <range>: <return>; <range2>: <return2>; <default_return>; }
<feature>
: the feature you're working on.<relation>
: eitherSELF
orPARENT
. This indicates if you want to use the variable of the item itself or that of it's related item. See the NML Documentation on switch blocks for a table of what these relations are for each feature. Sometimes it will not be entirely clear which one you need, in that case just trySELF
and change it toPARENT
if it doesn't work like you think it should.PARENT
is mostly needed for things that have to do with randomizations; in other casesSELF
mostly does the trick.<identifier>
: a self-chosen identifier (name) for this switch. It's useful to start with switch_ followed by the name of the item this is a switch for. Like with any other identifier, also these identifiers need to be unique throughout the NML file.<expression>
: A variable or GRF parameter you want to base this decision on. You may do mathematical calculations on a variable or parameter before having to make a decision on it's value and you may even list multiple expressions in the form of an array (we'll see examples of this later), but just a single variable or parameter if of course also fine.<range>
: Either a single value or a subrange from the value range this expression can result in. If you want to specify a subrange, use<range_start>..<range_end>
<return>
: An identifier to a different switch or spritegroup block, or (when switching a callback) thereturn
keyword followed by a number or string reference.<default_return>
: Like a<return_value>
, but this one is only used if none of the ranges specified above matches the value of the variable.
Now this may sound rather complicated and I agree that it may be a bit overwhelming when presented like this. Switches are one of the most complicated blocks in NML and they represent the VarAction2 in NFO. In case you're familiar with that: VarAction2 is one of the most complicated things in NFO as well.
Let's look at a little example showing some of the possibilities of a switch. Note that doesn't have an actual meaning other than showing some of the options. In reality it will be very uncommon that a single switch blocks needs to have a string returned for one range, a number for another range, point to an other switch for yet another range.
switch (FEAT_TRAINS, PARENT, some_vehicle_switch, (position_in_consist) { 0..2: return string(STRING_FOO_BAR); //return a text message 3..4: return; //returns 3 in case position_in_consist == 3 or 4 in case position_in_consist == 4 5..300: return 42; //42 is always a good answer 400: switch_other_identifier; //chain to some other switch block 401: return num_vehs_in_consist + 1; //return a value with a variable access CB_FAILED; //return a failure result as default }
Because this particular example returns numbers and strings, it can only be a switch for a callback. Switches used for graphics will (only) return identifiers to spritegroups, for example (this is an actual realistic example for a change):
switch (FEAT_TRAINS, PARENT, some_other_vehicle_switch, (position_in_consist) { 1..2: spritegroup_vehicle_1; //use this for second and third part of articulated vehicle 3..4: spritegroup_vehicle_2; //use this for fourth and fifth part of articulated vehicle 5: spritegroup_vehicle_3; //use this for sixth part of articulated vehicle spritegroup_vehicle_0; //use this for first and other parts of articulated vehicle (i.e. default) }
There's much more to say about callbacks and switch blocks, but this is probably intimidating enough already. Next we'll make an articulated tram vehicle to show you where these callbacks and switches go in your NML code.
NML Tutorial: Callback and switch