Difference between revisions of "NML:Random switch"

From GRFSpecs
Jump to navigationJump to search
 
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{NMLNavBlocksyntax}}
 
{{NMLNavBlocksyntax}}
  +
  +
== Syntax ==
   
 
While a [[NML:Switch|switch-block]] allows making a predictable decision, a random_switch allows a randomised choice between several options.
 
While a [[NML:Switch|switch-block]] allows making a predictable decision, a random_switch allows a randomised choice between several options.
Line 8: Line 10:
 
(<probability>: <return_value>;)+
 
(<probability>: <return_value>;)+
 
}
 
}
  +
  +
== Feature and Type ==
   
 
The first parameter <code style="color:darkgreen">&lt;feature&gt;</code> specifies the feature to use. <code style="color:darkgreen">&lt;type&gt;</code>, the second parameter, is used to define what random data is used. The supported combinations are listed in the following table. The amount of random data is given in the third column. The maximum number of possible combinations is equal to 2^x, with x being the number of random bits. Not all combinations support re-randomizing via triggers, this is indicated in the fourth column. The last column specifies the object of which the random data is used.
 
The first parameter <code style="color:darkgreen">&lt;feature&gt;</code> specifies the feature to use. <code style="color:darkgreen">&lt;type&gt;</code>, the second parameter, is used to define what random data is used. The supported combinations are listed in the following table. The amount of random data is given in the third column. The maximum number of possible combinations is equal to 2^x, with x being the number of random bits. Not all combinations support re-randomizing via triggers, this is indicated in the fourth column. The last column specifies the object of which the random data is used.
   
{| class="t"
+
{| class="wikitable sortable"
 
! Feature
 
! Feature
 
! Type
 
! Type
Line 20: Line 24:
 
| Vehicles
 
| Vehicles
 
| SELF
 
| SELF
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| Yes
 
| Yes
 
| Vehicle itself
 
| Vehicle itself
Line 26: Line 30:
 
| Vehicles
 
| Vehicles
 
| PARENT
 
| PARENT
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| No
 
| No
 
| Leading engine
 
| Leading engine
Line 32: Line 36:
 
| Vehicles
 
| Vehicles
 
| BACKWARD_SELF(x)
 
| BACKWARD_SELF(x)
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| No
 
| No
| Count x vehicles backward (away from the engine), starting at the vehicle itself <ref name=expression>x can be any expression. It may access parameters, registers, or variables of the vehicle itself.</ref>
+
| Count x vehicles backward (away from the engine), starting at the vehicle itself <ref name=expression>x can be any expression. It may access parameters, registers, or variables of the vehicle itself. Uses register 0x100 if x is not a constant expression between 1 and 15</ref>
 
|-
 
|-
 
| Vehicles
 
| Vehicles
 
| FORWARD_SELF(x)
 
| FORWARD_SELF(x)
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| No
 
| No
 
| Count x vehicles forward (towards the engine), starting at the vehicle itself <ref name=expression />
 
| Count x vehicles forward (towards the engine), starting at the vehicle itself <ref name=expression />
Line 44: Line 48:
 
| Vehicles
 
| Vehicles
 
| BACKWARD_ENGINE(x)
 
| BACKWARD_ENGINE(x)
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| No
 
| No
 
| Count x vehicles backward, starting at the leading engine <ref name=expression />
 
| Count x vehicles backward, starting at the leading engine <ref name=expression />
Line 50: Line 54:
 
| Vehicles
 
| Vehicles
 
| BACKWARD_SAMEID(x)
 
| BACKWARD_SAMEID(x)
  +
| 8 {{ottdp|14.0|no}} 16
| 8
 
 
| No
 
| No
 
| Count x vehicles backward, starting at the first vehicle in the chain with the same ID <ref name=expression />
 
| Count x vehicles backward, starting at the first vehicle in the chain with the same ID <ref name=expression />
Line 102: Line 106:
 
| Object tile (different per tile)
 
| Object tile (different per tile)
 
|-
 
|-
  +
| Railtypes
| Rail types
 
 
| SELF
 
| SELF
 
| 2
 
| 2
 
| No
 
| No
 
| Rail tile (pseudo-random, based on location)
 
| Rail tile (pseudo-random, based on location)
  +
|-
  +
| Roadtypes
  +
| SELF
 
| 2
 
| No
  +
| Road tile (pseudo-random, based on location)
  +
|-
  +
| Tramtypes
  +
| SELF
 
| 2
 
| No
  +
| Road tile (pseudo-random, based on location)
 
|}
 
|}
   
 
<references />
 
<references />
   
  +
== ID ==
The third parameter <code style="color:darkgreen">&lt;ID&gt;</code> can be used to refer to this block from other (random-)switch-blocks. The last parameter <code style="color:darkgreen">&lt;triggers&gt;</code> is optional and allows re-randomizing when certain conditions occur. The events and accompanying trigger names are given in the following tables. To re-randomize graphics when any of a set of events occurs, use <code style="color:darkgreen">bitmask(TRIGGER_A, TRIGGER_B, .. , TRIGGER_Z)</code> To re-randomize only when ''all'' of the events have occured, add <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code> to the list of used triggers, e.g. use <code style="color:darkgreen">bitmask(TRIGGER_ALL_NEEDED, TRIGGER_A, ...)</code>
 
  +
  +
The third parameter <code style="color:darkgreen">&lt;ID&gt;</code> can be used to refer to this block from other (random-)switch-blocks.
  +
  +
== Triggers ==
  +
 
The last parameter <code style="color:darkgreen">&lt;triggers&gt;</code> is optional and allows re-randomizing when certain conditions occur. The events and accompanying trigger names are given in the following tables. To re-randomize graphics when any of a set of events occurs, use <code style="color:darkgreen">bitmask(TRIGGER_A, TRIGGER_B, .. , TRIGGER_Z)</code> To re-randomize only when ''all'' of the events have occured, add <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code> to the list of used triggers, e.g. use <code style="color:darkgreen">bitmask(TRIGGER_ALL_NEEDED, TRIGGER_A, ...)</code>
  +
  +
=== Vehicles ===
   
{| class="t"
+
{| class="wikitable sortable"
 
|+ Vehicle triggers
 
|+ Vehicle triggers
 
|-
 
|-
Line 137: Line 161:
 
To re-randomize when the consist has been emptied and then receives new cargo, use <code style="color:darkgreen">bitmask(TRIGGER_VEHICLE_UNLOAD_ALL, TRIGGER_VEHICLE_ANY_LOAD, TRIGGER_ALL_NEEDED)</code>
 
To re-randomize when the consist has been emptied and then receives new cargo, use <code style="color:darkgreen">bitmask(TRIGGER_VEHICLE_UNLOAD_ALL, TRIGGER_VEHICLE_ANY_LOAD, TRIGGER_ALL_NEEDED)</code>
   
  +
=== Stations ===
{| class="t"
 
  +
  +
{| class="wikitable sortable"
 
|+ Station triggers
 
|+ Station triggers
 
|-
 
|-
Line 169: Line 195:
 
|}
 
|}
   
The last four triggers in the table only trigger on the platform on which they occur. Note that triggers are only saved per-station, not per-tile, so using <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code> doesn't make a lot of sense for per-platform triggers
+
All triggering events involve a cargo-type (which arrives, is loaded, or unloaded). The triggers only apply to a station section, if the cargo-type is listed in the property <code style="color:darkgreen">cargo_random_triggers</code>.
   
  +
The last four triggers in the table only trigger on the platform on which they occur.
{| class="t"
 
  +
  +
Note that triggers are only saved per-station, not per-tile, so using <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code> doesn't make a lot of sense for per-platform triggers; or in general, if a station is composed of sections from different NewGRF.
  +
  +
=== Houses ===
  +
  +
{| class="wikitable sortable"
 
|+ House triggers
 
|+ House triggers
 
|-
 
|-
Line 186: Line 218:
 
Using <code style="color:darkgreen">TRIGGER_HOUSE_TOP_TILELOOP</code>, it is possible to re-randomize the whole building as one unit. All tiles of a multi-tile house will get the same new random data.
 
Using <code style="color:darkgreen">TRIGGER_HOUSE_TOP_TILELOOP</code>, it is possible to re-randomize the whole building as one unit. All tiles of a multi-tile house will get the same new random data.
   
  +
=== Industry tiles ===
{| class="t"
 
  +
  +
{| class="wikitable sortable"
 
|+ Industry tile triggers
 
|+ Industry tile triggers
 
|-
 
|-
Line 203: Line 237:
   
 
Industry tiles can rerandomise both their own random bits as well as the random bits of the industry (via type <code style="color:darkgreen">PARENT</code>). The triggers for rerandomisation are in both cases shared per tile (when using <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code>), i.e. the triggers are in all cases independent for different tiles. Industries have random bits. However, they can only be rerandomised by their tiles.
 
Industry tiles can rerandomise both their own random bits as well as the random bits of the industry (via type <code style="color:darkgreen">PARENT</code>). The triggers for rerandomisation are in both cases shared per tile (when using <code style="color:darkgreen">TRIGGER_ALL_NEEDED</code>), i.e. the triggers are in all cases independent for different tiles. Industries have random bits. However, they can only be rerandomised by their tiles.
  +
  +
== independent and dependent ==
   
 
<code style="color:darkgreen">&lt;independent&gt;: &lt;other_random&gt;;</code> makes sure that this random_switch block and <code style="color:darkgreen">&lt;other_random&gt;</code> use different (non-intersecting) random data. This allows making multiple randomized decisions that are independent of each other.
 
<code style="color:darkgreen">&lt;independent&gt;: &lt;other_random&gt;;</code> makes sure that this random_switch block and <code style="color:darkgreen">&lt;other_random&gt;</code> use different (non-intersecting) random data. This allows making multiple randomized decisions that are independent of each other.
Line 209: Line 245:
   
 
Both of these options require enough random data to be available. Also, the combination must make sense. For example, if A is dependent on B and B is dependent on C, then A cannot be independent of C.
 
Both of these options require enough random data to be available. Also, the combination must make sense. For example, if A is dependent on B and B is dependent on C, then A cannot be independent of C.
  +
  +
== Choices ==
   
 
Following this, there is a list of options, one of which will be chosen randomly. The syntax is <code style="color:darkgreen">&lt;probability&gt;: &lt;return_value&gt;;</code>. The relative probability that this option will be chosen is given by <code style="color:darkgreen">&lt;probability&gt;</code>. The chance is equal to the probability divided by the sum of all probabilities. If this sum is not equal to a power of two (2, 4, 8, 16, ...), then rounding is done and the probabilities may be inexact. For information about <code style="color:darkgreen">&lt;return_value&gt;</code>, see the [[NML:Switch|switch-block]]. Note that accessed variables in the return value are always in the scope of the item itself (i.e. <code style="color:darkgreen">SELF</code>)
 
Following this, there is a list of options, one of which will be chosen randomly. The syntax is <code style="color:darkgreen">&lt;probability&gt;: &lt;return_value&gt;;</code>. The relative probability that this option will be chosen is given by <code style="color:darkgreen">&lt;probability&gt;</code>. The chance is equal to the probability divided by the sum of all probabilities. If this sum is not equal to a power of two (2, 4, 8, 16, ...), then rounding is done and the probabilities may be inexact. For information about <code style="color:darkgreen">&lt;return_value&gt;</code>, see the [[NML:Switch|switch-block]]. Note that accessed variables in the return value are always in the scope of the item itself (i.e. <code style="color:darkgreen">SELF</code>)
   
  +
== Usage in graphics and callbacks ==
Note that re-randomizing is done only during a special callback, <code style="color:darkgreen">random_trigger</code>. This callback is called whenever a trigger event occurs. As a consequence, it's ''absolutely necessary'' for the random_switch block to be in executed during this callback, or trigger-based re-randomizing won't take place. Also, the callback may not fail (end with CB_FAILED), so return an arbitrary value or even a sprite set instead. This return value is not used anywhere.
 
  +
 
Note that re-randomizing is done only during a special callback, <code style="color:darkgreen">random_trigger</code>. This callback is called whenever a trigger event occurs. As a consequence, it's ''absolutely necessary'' for the random_switch block to be executed during this callback, or trigger-based re-randomizing won't take place. Also, the callback may not fail (end with CB_FAILED), so return an arbitrary value or even a sprite set instead. This return value is not used anywhere.
  +
  +
== Example ==
   
 
Let's conclude with an example:
 
Let's conclude with an example:

Latest revision as of 07:30, 10 September 2023

Block Syntax

Syntax

While a switch-block allows making a predictable decision, a random_switch allows a randomised choice between several options.

random_switch (<feature>, <type>, <ID>[, <triggers>]) {
	(independent: <other_random>;)*
	(dependent: <other_random>;)*
	(<probability>: <return_value>;)+
}

Feature and Type

The first parameter <feature> specifies the feature to use. <type>, the second parameter, is used to define what random data is used. The supported combinations are listed in the following table. The amount of random data is given in the third column. The maximum number of possible combinations is equal to 2^x, with x being the number of random bits. Not all combinations support re-randomizing via triggers, this is indicated in the fourth column. The last column specifies the object of which the random data is used.

Feature Type # of random bits Triggers possible? Random data used
Vehicles SELF 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 Yes Vehicle itself
Vehicles PARENT 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 No Leading engine
Vehicles BACKWARD_SELF(x) 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 No Count x vehicles backward (away from the engine), starting at the vehicle itself [1]
Vehicles FORWARD_SELF(x) 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 No Count x vehicles forward (towards the engine), starting at the vehicle itself [1]
Vehicles BACKWARD_ENGINE(x) 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 No Count x vehicles backward, starting at the leading engine [1]
Vehicles BACKWARD_SAMEID(x) 8 Supported by OpenTTD 14.014.0 Not supported by TTDPatch 16 No Count x vehicles backward, starting at the first vehicle in the chain with the same ID [1]
Stations / airport tiles SELF 16 Stations only Station
Stations / airport tiles TILE 4 Stations only Specific station tile
Canals SELF 8 No Canal tile
Houses SELF 8 Yes House tile [2]
Industry tiles SELF 8 Yes Industry tile
Industry tiles PARENT 16 Yes Industry as a whole
Industries SELF 16 No Industry (same as above)
Objects SELF 8 No Object tile (different per tile)
Railtypes SELF 2 No Rail tile (pseudo-random, based on location)
Roadtypes SELF 2 No Road tile (pseudo-random, based on location)
Tramtypes SELF 2 No Road tile (pseudo-random, based on location)
  1. 1.0 1.1 1.2 1.3 x can be any expression. It may access parameters, registers, or variables of the vehicle itself. Uses register 0x100 if x is not a constant expression between 1 and 15
  2. The random bits are initially the same for all tiles of a multi-tile house.

ID

The third parameter <ID> can be used to refer to this block from other (random-)switch-blocks.

Triggers

The last parameter <triggers> is optional and allows re-randomizing when certain conditions occur. The events and accompanying trigger names are given in the following tables. To re-randomize graphics when any of a set of events occurs, use bitmask(TRIGGER_A, TRIGGER_B, .. , TRIGGER_Z) To re-randomize only when all of the events have occured, add TRIGGER_ALL_NEEDED to the list of used triggers, e.g. use bitmask(TRIGGER_ALL_NEEDED, TRIGGER_A, ...)

Vehicles

Vehicle triggers
Trigger Event
TRIGGER_VEHICLE_NEW_LOAD Vehicle gets new load of cargo (only after it was empty)
TRIGGER_VEHICLE_SERVICE Vehicle enters a depot and is serviced
TRIGGER_VEHICLE_UNLOAD_ALL The consist has unloaded all cargo (use with type 'SELF')
TRIGGER_VEHICLE_ANY_LOAD Any vehicle of the consist receives cargo (use with type 'SELF')
TRIGGER_VEHICLE_32_CALLBACK 32-day callback returned 1

To re-randomize when the consist has been emptied and then receives new cargo, use bitmask(TRIGGER_VEHICLE_UNLOAD_ALL, TRIGGER_VEHICLE_ANY_LOAD, TRIGGER_ALL_NEEDED)

Stations

Station triggers
Trigger Event Triggered on
TRIGGER_STATION_NEW_CARGO New cargo waiting Entire station
TRIGGER_STATION_NO_MORE_CARGO No more cargo waiting Entire station
TRIGGER_STATION_TRAIN_ARRIVES Train arrives (starts loading/unloading) Platform the train is on
TRIGGER_STATION_TRAIN_LEAVES Train leaves (done loading/unloading) Platform the train is on
TRIGGER_STATION_TRAIN_LOADS_UNLOADS Train loads/unloads cargo Platform the train is on
TRIGGER_STATION_TRAIN_RESERVES Train reserves platform using PBS Platform the train is on

All triggering events involve a cargo-type (which arrives, is loaded, or unloaded). The triggers only apply to a station section, if the cargo-type is listed in the property cargo_random_triggers.

The last four triggers in the table only trigger on the platform on which they occur.

Note that triggers are only saved per-station, not per-tile, so using TRIGGER_ALL_NEEDED doesn't make a lot of sense for per-platform triggers; or in general, if a station is composed of sections from different NewGRF.

Houses

House triggers
Trigger Event
TRIGGER_HOUSE_TILELOOP The house tile is processed in the periodic tile-processing loop
TRIGGER_HOUSE_TOP_TILELOOP The top tile of the house is processed in the periodic tile-processing loop

Using TRIGGER_HOUSE_TOP_TILELOOP, it is possible to re-randomize the whole building as one unit. All tiles of a multi-tile house will get the same new random data.

Industry tiles

Industry tile triggers
Trigger Event
TRIGGER_INDUSTRYTILE_TILELOOP The industry tile is processed in the periodic tile-processing loop
TRIGGER_INDUSTRYTILE_256_TICKS Triggers simultaneously for all tiles of the industry every 256 ticks. If the industry is a primary one, output cargo is generated at the same time.
TRIGGER_INDUSTRYTILE_CARGO_DELIVERY Cargo is delivered to the industry. If the industry is a processing one, output cargo is generated at the same time.

Industry tiles can rerandomise both their own random bits as well as the random bits of the industry (via type PARENT). The triggers for rerandomisation are in both cases shared per tile (when using TRIGGER_ALL_NEEDED), i.e. the triggers are in all cases independent for different tiles. Industries have random bits. However, they can only be rerandomised by their tiles.

independent and dependent

<independent>: <other_random>; makes sure that this random_switch block and <other_random> use different (non-intersecting) random data. This allows making multiple randomized decisions that are independent of each other.

<dependent>: <other_random>;, on the other hand, lets this random_switch block and <other_random> use the same random data. To make this possible, it should not require more random data (i.e. have a higher sum of probabilities) than the block it is dependent on.

Both of these options require enough random data to be available. Also, the combination must make sense. For example, if A is dependent on B and B is dependent on C, then A cannot be independent of C.

Choices

Following this, there is a list of options, one of which will be chosen randomly. The syntax is <probability>: <return_value>;. The relative probability that this option will be chosen is given by <probability>. The chance is equal to the probability divided by the sum of all probabilities. If this sum is not equal to a power of two (2, 4, 8, 16, ...), then rounding is done and the probabilities may be inexact. For information about <return_value>, see the switch-block. Note that accessed variables in the return value are always in the scope of the item itself (i.e. SELF)

Usage in graphics and callbacks

Note that re-randomizing is done only during a special callback, random_trigger. This callback is called whenever a trigger event occurs. As a consequence, it's absolutely necessary for the random_switch block to be executed during this callback, or trigger-based re-randomizing won't take place. Also, the callback may not fail (end with CB_FAILED), so return an arbitrary value or even a sprite set instead. This return value is not used anywhere.

Example

Let's conclude with an example:

 random_switch (FEAT_TRAINS, SELF, random_42, bitmask(TRIGGER_VEHICLE_UNLOAD_ALL, TRIGGER_VEHICLE_ANY_LOAD, TRIGGER_ALL_NEEDED)) {
 	/* re-randomize when vehicle has been emptied and then received new cargo */
 	independent: random_43; // decision should be independent from random_43, which is defined elsewhere
 	6: group_open;          // 6/11 chance to display open wagon
 	3: group_closed;        // 3/11 chance to display closed wagon (with cover)
 	2: group_halfopen;      // 2/11 chance to display a half-covered wagon
 }