Types/NoiseExpression: Difference between revisions
(Move from User:TOGoS) |
(1.1.0) |
||
(38 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
== Basics == | == Basics == | ||
A fragment of a functional program used to generate coherent noise, probably for purposes related to terrain generation. | A fragment of a functional program used to generate coherent noise, probably for purposes related to terrain generation. | ||
Noise expressions can be provided as table literals or built using functions in the [https://github.com/wube/factorio-data/blob/master/core/lualib/noise.lua built-in <code>noise</code> library]. The built-in noise library allows writing much more concise code, so its usage will be shown in most examples on this page.<br> | |||
[https://github.com/wube/factorio-data/blob/master/core/lualib/noise.lua#L272 <code>noise.define_noise_function</code>] allows noise expressions to be defined using a shorthand | |||
that's a subset of Lua (see [[#Example definition|example definition]] for an example and its literal equivalent). | |||
'''Types/NoiseExpression''' is used by [[Prototype/NamedNoiseExpression#expression|NamedNoiseExpressionPrototype::expression]], [[Types/AutoplaceSpecification#Properties_for_Expression-based_AutoplaceSpecifications|AutoplaceSpecification::probability_expression]] and [[Types/AutoplaceSpecification#Properties_for_Expression-based_AutoplaceSpecifications|AutoplaceSpecification::richness_expression]]. | |||
== Mandatory properties == | == Mandatory properties == | ||
Line 17: | Line 21: | ||
=== variable === | === variable === | ||
Properties: | |||
* '''variable_name''': a [[Types/string]] | |||
Reference to a pre-defined variable, constant, or a [[Prototype/NamedNoiseExpression|named noise expression]]. Variables referencing named noise expressions may have their reference overridden by other named noise expression if their intended_property is the variable name and it is selected by the user in the map generator GUI. See [[Prototype/NamedNoiseExpression#Custom intended_property]]. | |||
Predefined variables: | |||
* x - number - Current x position on the map | |||
* y - number - Current y position on the map | |||
Predefined | Predefined constants (note that map gen settings can also be provided by a [[Types/MapGenPreset]]): | ||
* map_seed - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* map_width - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* map_height - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* water_level - number - Don't use; use wlc_elevation_minimum instead | |||
* finite_water_level - number - Don't use; use wlc_elevation_offset instead | |||
* wlc_elevation_offset - number - When the result of 10 × log2("water") with "water" from [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] is finite, <code>wlc_elevation_offset = -(10 * log2(water))</code>, else <code>wlc_elevation_offset = 0</code> | |||
* wlc_elevation_minimum - number - When the result of 10 × log2("water") with "water" from [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] is infinite, <code>wlc_elevation_minimum = -∞</code>, else <code>wlc_elevation_minimum = 4</code> | |||
* cliff_elevation_offset - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] ([https://lua-api.factorio.com/latest/Concepts.html#CliffPlacementSettings CliffPlacementSettings]) | |||
* cliff_elevation_interval - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] ([https://lua-api.factorio.com/latest/Concepts.html#CliffPlacementSettings CliffPlacementSettings]) | |||
* control-setting:cliffs:richness:multiplier - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] ([https://lua-api.factorio.com/latest/Concepts.html#CliffPlacementSettings CliffPlacementSettings]) | |||
* terrace_elevation_offset - number - Calculated from the cliff and water settings. | |||
* terrace_elevation_interval - number - Same as "cliff_elevation_interval" | |||
* starting_area_radius - number - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* starting_positions - map position list - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* starting_lake_positions - map position list - Calculated from starting positions and map seed | |||
* peaceful_mode - boolean - Taken from the [http://lua-api.factorio.com/latest/Concepts.html#MapGenSettings MapGenSettings] | |||
* control-setting:<prototype name>:frequency - number - Provided for all of the [[Prototype/Tile|tile]], [[Prototype/Entity|entity]], [[Prototype/Decorative|decorative]], [[Prototype/AutoplaceControl|autoplace-control]] prototypes. | |||
* control-setting:<prototype name>:size - number - Provided for all of the [[Prototype/Tile|tile]], [[Prototype/Entity|entity]], [[Prototype/Decorative|decorative]], [[Prototype/AutoplaceControl|autoplace-control]] prototypes. | |||
* control-setting:<prototype name>:richness - number - Provided for all of the [[Prototype/Tile|tile]], [[Prototype/Entity|entity]], [[Prototype/Decorative|decorative]], [[Prototype/AutoplaceControl|autoplace-control]] prototypes. | |||
A list of all named noise expression defined in the base game can be found at [[Data.raw#noise-expression]]. Notable expressions defined by the base game are: | |||
* distance - number - <code>noise.distance_from(noise.var("x"), noise.var("y"), noise.var("starting_positions"))</code>, so the distance from the closest starting position. distance is never < 0. | |||
* tier_from_start - number - <code>noise.max(0.0, noise.var("distance") - noise.var("starting_area_radius")) / noise.var("starting_area_radius)</code> | |||
* tier - number - <code>noise.var("tier_from_start")</code>, so same as tier_from_start. | |||
* starting_area_weight - number - <code>1 - noise.min(1.0, noise.var("tier_from_start") / 2.0)</code> | |||
* moisture - number - A value between 0 and 1 that determines whether a tile becomes sandy (low moisture) or grassy (high moisture). | |||
* aux - number - A value between 0 and 1 that determines whether low-moisture tiles become sand or red desert. | |||
* temperature - number - Provides a value (vaguely representing degrees Celsius, varying between -20 and 50) that is used (together with moisture and aux) as part of tree and decorative placement. | |||
* elevation - number - Tiles values less than zero become water. Cliffs are placed along certain contours according to CliffPlacementSettings. | |||
* cliffiness - number - Determines whether (when >0.5) or not (when <0.5) a cliff will be placed at an otherwise suitable (according to CliffPlacementSettings) location. | |||
* enemy-base-intensity - number - Is referenced by both enemy-base-frequency and enemy-base-radius. i.e. if this is overridden, enemy base frequency and size will both be affected and do something reasonable. By default, this expression returns a value proportional to distance from any starting point, clamped at about 7. | |||
* enemy-base-frequency - number - Represents average number of enemy bases per tile for a region, by default in terms of enemy-base-intensity. | |||
* enemy-base-radius - number - Represents the radius of an enemy base, if one were to be placed on the given tile, by default proportional to a constant plus enemy-base-intensity. | |||
Note that the named noise expressions are all defined in Lua, so mods may remove or change the notable expressions listed above or change how they are used in the map generation. | |||
Examples: | |||
<syntaxhighlight lang="lua"> | |||
local noise = require("noise") | |||
local y = | |||
{ | |||
type = "variable", | |||
variable_name = "y" -- predefined variable | |||
} | |||
local x = noise.var("x") -- predefined variable, with the noise lib | |||
local width = | |||
{ | |||
type = "variable", | |||
variable_name = "map_width" -- predefined constant | |||
} | |||
local height = noise.var("map_height") -- predefined constant, with the noise lib | |||
local aux = | |||
{ | |||
type = "variable", | |||
variable_name = "aux" -- named noise expression | |||
} | |||
local cliffiness = noise.var("cliffiness") -- named noise expression, with the noise lib | |||
</syntaxhighlight> | |||
=== function-application === | === function-application === | ||
Apply a function to a list or associative array of arguments. | Apply a function to a list or associative array of arguments. Some functions expect arguments to be named and some expect them not to be. | ||
Some functions expect arguments to be named and some expect them not to be. | |||
Function calls are their own class of expression | Function calls are their own class of expression (as opposed to every function just being its own expression type) because function calls all have similar properties -- arguments are themselves expressions, a function call with all-constant arguments can be constant-folded (due to [[Wikipedia:Referential_transparency|referential transparency]]), etc. | ||
(as opposed to every function just being its own expression type) | |||
because function calls all have similar properties -- | |||
arguments are themselves expressions, | |||
a call to | |||
Properties: | Properties: | ||
* '''function_name''' (a string; see | * '''function_name''' (a string; see [[#Functions]], below) | ||
* '''arguments''' (a list or associative array of argument expressions) | * '''arguments''' (a list or associative array of argument expressions) | ||
=== literal-boolean === | |||
Evaluates to the same boolean value (true or false) every time, given by the '''literal_value''' property. May be used as a number value, evaluates to 1 for true and 0 for false. | |||
=== literal-number === | === literal-number === | ||
Evaluates to the same number every time, given by the '''literal_value''' property. | Evaluates to the same number every time, given by the '''literal_value''' property. All numbers are treated as [[Types/float]]s internally unless otherwise specified. May be used as a boolean value, evaluates to true for numbers > 0, anything else evaluates to false. | ||
Example: | |||
<syntaxhighlight lang="lua"> | |||
local ten = | |||
{ | |||
type = "literal-number", | |||
literal_value = 10 | |||
} | |||
-- or with the noise lib, see the "Basics" section above | |||
local noise = require("noise") | |||
local twenty_point_five = noise.to_noise_expression(20.5) | |||
</syntaxhighlight> | |||
=== literal-string === | === literal-string === | ||
Evaluates to the same | Evaluates to the same string every time, given by the '''literal_value''' property. | ||
Since the noise generation runtime has no notion of strings or use for them, | Since the noise generation runtime has no notion of strings or use for them, | ||
Line 61: | Line 138: | ||
e.g. | e.g. | ||
< | <syntaxhighlight lang="lua"> | ||
{ | { | ||
type = "literal-object", | type = "literal-object", | ||
Line 73: | Line 150: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
Since the noise generation runtime has no notion of objects or use for them, | Since the noise generation runtime has no notion of objects or use for them, | ||
this is useful only in constant contexts, such as the ''' | this is useful only in constant contexts, such as the argument | ||
of the '''autoplace-probability''' function (where the 'literal object' is an [[Types/AutoplaceSpecification|AutoplaceSpecitication]]) | |||
=== literal-expression === | |||
Returns the expression represented by its '''literal-value''' property. | |||
Useful mostly for passing expressions (to be evaluated later) to the [[#spot-noise|'''spot-noise''']] function. | |||
=== array-construction === | |||
'''value_expressions''' property should be a list of expressions, | |||
each of which will be evaluated to come up with the corresponding value | |||
in the resulting array. | |||
Used to construct map positions ({x, y}) and map position lists ({{x0,y0}, {y1,y1}, ...}) for [[#offset-points|offset-points]] and [[#distance-from-nearest-point|distance-from-nearest-point]]. | |||
Examples of constructing a map position and map position list: | |||
<syntaxhighlight lang="lua"> | |||
local noise = require("noise") | |||
local tne = noise.to_noise_expression | |||
local map_pos_1 = -- the map position {x = 100, y = -200} specified directly | |||
{ | |||
type = "array-construction", | |||
value_expressions = {tne(100), tne(-200)} | |||
} | |||
-- or with make_array from the noise lib required above | |||
local map_pos_2 = noise.make_array({100, 200}) | |||
local map_pos_list = -- a map position list: {{x = 100, y = -200}, {x = 100, y = 200}} | |||
{ | |||
type = "array-construction", | |||
value_expressions = {map_pos_1, map_pos_2} | |||
} | |||
-- or with the noise lib | |||
local also_map_post_list = noise.make_point_list({{100, -200}, {100, 200}}) | |||
</syntaxhighlight> | |||
=== procedure-delimiter === | |||
Evaluates and returns the value of its '''expression''' property, which is itself an expression. | |||
This hints to the compiler that it should break the subexpression into its own procedure | |||
so that the result can be re-used in multiple places. | |||
For instance if you want to re-use the same multioctave noise for determining probability | |||
of multiple tiles/entities, wrap the multioctave noise expression in a procedure-delimiter. | |||
Alternatively, make the noise its own [[Prototype/NamedNoiseExpression|NamedNoiseExpression]] and reference it by name, using a variable. | |||
=== if-else-chain === | |||
Has an '''arguments''' property that is a list of condition-result expression pairs followed by a default result expression, like so: | |||
<syntaxhighlight lang="lua"> | |||
{ | |||
type = "if-else-chain", | |||
arguments = { | |||
condition1, result1, | |||
condition2, result2, | |||
... | |||
defaultResult | |||
} | |||
} | |||
</syntaxhighlight > | |||
The result of the if-else-chain is the value of the first result expression whose condition expression evaluated to true, | |||
or the value of the default result ('else') expression. | |||
== Functions == | == Functions == | ||
Line 83: | Line 226: | ||
=== add === | === add === | ||
'''Arguments (positional)''': | '''Arguments (positional)''': between 0 and 999 numbers | ||
Takes | Takes the positional arguments and adds them. | ||
=== subtract === | === subtract === | ||
'''Arguments (positional)''': | |||
'''Arguments (positional)''': minuend | * '''minuend''' - number | ||
* '''subtrahend''' - number | |||
Takes 2 positional arguments and subtracts the second from the first. | Takes 2 positional arguments and subtracts the second from the first. | ||
=== multiply === | === multiply === | ||
'''Arguments (positional)''': between 0 and 999 numbers | |||
Takes the positional arguments and multiplies them. | |||
Takes | |||
=== divide === | === divide === | ||
'''Arguments (positional)''': | |||
'''Arguments (positional)''': dividend | * '''dividend''' - number | ||
* '''divisor''' - number | |||
Takes 2 positional arguments and divides the first by the second. | Takes 2 positional arguments and divides the first by the second. | ||
=== exponentiate === | === exponentiate === | ||
'''Arguments (positional)''': | |||
'''Arguments (positional)''': base | * '''base''' - number | ||
* '''exponent''' - number | |||
Takes 2 positional arguments, and raises the first to the second power. | Takes 2 positional arguments, and raises the first to the second power. | ||
=== absolute-value === | === absolute-value === | ||
'''Arguments (positional)''': value to be absoluted | '''Arguments (positional)''': value to be absoluted | ||
Line 118: | Line 262: | ||
=== clamp === | === clamp === | ||
'''Arguments (positional)''': | |||
* '''value''' - number to be clamped | |||
* '''floor''' - lower limit | |||
* '''ceiling''' - upper limit | |||
First argument is clamped between the second and third. The second is treated as a lower limit and the third the upper limit. | |||
=== compile-time-log === | |||
'''Arguments''': Between 1 and 999 values of any type | |||
Prints all of its arguments to the [[log file]] when the expression is compiled. For that it needs to part of another expression that is compiled. The last argument of the compile-time-log is returned as the "result" of the compile-time-log. | |||
Example of usage inside a [[Prototype/NamedNoiseExpression|NamedNoiseExpression]]: | |||
<syntaxhighlight lang="lua"> | |||
local noise = require("noise") | |||
local tne = noise.to_noise_expression | |||
-- see the named noise expression docs linked above the code for how this works | |||
data:extend{{ | |||
type = "noise-expression", | |||
name = "compile-log-test", | |||
intended_property = "elevation", | |||
expression = noise.compile_time_log(2000, noise.var("y"), tne(100) - noise.var("distance")) | |||
}} | |||
-- When "compile-log-test" is selected as the map type and a map preview or map is generated, this logs: | |||
-- Info data-updates.lua:24: 2000.000000 reference to variable 'y' subtract | |||
-- Furthermore, the elevation noise expression is set to 'tne(100) - noise.var("distance")', producing a circular island with a 100 tile radius | |||
</syntaxhighlight> | |||
=== distance-from-nearest-point === | |||
'''Arguments (named)''': | |||
* '''x''' - number | |||
* '''y''' - number | |||
* '''points''' - list of map positions | |||
* '''maximum_distance''' (constant, default: max double) - number | |||
Computes the [[Wikipedia:Euclidean_distance|euclidean distance]] of the position {x, y} to all position listed in '''points''' and returns the shortest distance. The returned distance can be '''maximum_distance''' at most. | |||
See [[#array-construction|array-construction]] for how to specify a map position list. | |||
Example: | |||
<syntaxhighlight lang="lua"> | |||
-- Shortest distance at the current {x, y} from the two given points, but at most 1000 | |||
local noise = require("noise") | |||
local tne = noise.to_noise_expression | |||
local positions = noise.make_point_list({{-100, -40}, {-50, -200}}) | |||
local shortest_distance = | |||
{ | |||
type = "function-application", | |||
function_name = "distance-from-nearest-point", | |||
arguments = {x = noise.var("x"), y = noise.var("y"), points = positions, maximum_distance = tne(1000)} | |||
} | |||
-- or with the noise lib | |||
local also_shortest_distance = noise.function_application("distance-from-nearest-point", {x = noise.var("x"), y = noise.var("y"), points = positions, maximum_distance = 1000}) | |||
</syntaxhighlight> | |||
=== ridge === | === ridge === | ||
'''Arguments (positional)''': | |||
'''Arguments (positional)''': value to be ridged | * '''value''' - number to be ridged | ||
* '''floor''' - lower limit | |||
* '''ceiling''' - upper limit | |||
Similar to clamp but the input value is folded back across the upper and lower limits | Similar to clamp but the input value is folded back across the upper and lower limits | ||
until it lies between them. | until it lies between them. | ||
Example: | |||
<syntaxhighlight lang="lua"> | |||
local noise = require("noise") | |||
local ridge_1 = noise.ridge(6, 1, 5) -- this returns 4 | |||
local ridge_2 = noise.ridge(-1, 1, 5) -- this returns 3 | |||
</syntaxhighlight> | |||
=== terrace === | |||
'''Arguments (positional)''': | |||
* '''value''' - number | |||
* '''offset''' (constant) - number | |||
* '''width''' (constant) - number | |||
* '''strength''' - number | |||
=== modulo === | |||
'''Arguments (positional)''': | |||
* '''dividend''' - number | |||
* '''divisor''' - number | |||
Takes 2 positional arguments and divides the first by the second and returns the remainder. This is implemented using [https://en.cppreference.com/w/cpp/numeric/math/fmod fmod(double, double)]. | |||
=== floor === | |||
'''Arguments (positional)''': | |||
* '''value''' - number | |||
Takes one 1 numeric value and returns its floor. | |||
=== ceil === | |||
'''Arguments (positional)''': | |||
* '''value''' - number | |||
Takes one 1 numeric value and returns its ceiling. | |||
=== bitwise-and === | |||
'''Arguments (positional)''': between 0 and 999 numbers | |||
Casts the positional arguments to signed 32-bit integers and performs bitwise AND on them. | |||
=== bitwise-or === | |||
'''Arguments (positional)''': between 0 and 999 numbers | |||
Casts the positional arguments to signed 32-bit integers and performs bitwise OR on them. | |||
=== bitwise-xor === | |||
'''Arguments (positional)''': between 0 and 999 numbers | |||
Casts the positional arguments to signed 32-bit integers and performs bitwise EXCLUSIVE OR on them. | |||
=== bitwise-not === | |||
'''Arguments (positional)''': | |||
* '''value''' - number to be negated | |||
Casts the positional argument to a signed 32-bit integer and bitwise negates it. | |||
=== sin === | |||
'''Arguments (positional)''': | |||
* '''value''' - number | |||
Takes one 1 value and returns its sine. | |||
=== cos === | |||
'''Arguments (positional)''': | |||
* '''value''' - number | |||
Takes one 1 value and returns its cosine. | |||
=== atan2 === | |||
'''Arguments (positional)''': | |||
* '''y''' - number | |||
* '''x''' - number | |||
Returns the arc tangent of y/x using the signs of arguments to determine the correct quadrant. | |||
=== less-than === | |||
'''Arguments (positional)''': | |||
* '''lhs''' - number | |||
* '''rhs''' - number | |||
Returns the result of lhs < rhs as literal number that is 0 for false and 1 for true. | |||
=== less-or-equal === | |||
'''Arguments (positional)''': | |||
* '''lhs''' - number | |||
* '''rhs''' - number | |||
Returns the result of lhs <= rhs as literal number that is 0 for false and 1 for true. | |||
=== equals === | |||
'''Arguments (positional)''': | |||
* '''lhs''' - number | |||
* '''rhs''' - number | |||
Returns the result of lhs == rhs as literal number that is 0 for false and 1 for true. | |||
=== factorio-basis-noise === | === factorio-basis-noise === | ||
'''Arguments (named)''': | |||
* '''x''' | |||
* '''y''' | |||
* '''seed0''' (constant) - integer between 0 and 4294967295 (inclusive) used to populate the backing random noise | |||
* '''seed1''' (constant) - integer between 0 and 255 (inclusive) used to provide extra randomness when sampling | |||
* '''input_scale''' (constant, default: 1) - x and y will be multiplied by this before sampling | |||
* '''output_scale''' (constant, default: 1) - output will be multiplied by this before being returned | |||
Scaling input and output can be accomplished other ways, but are done so commonly | |||
as to be built into this function for performance reasons. | |||
=== factorio-quick-multioctave-noise === | |||
'''Arguments (named)''': | |||
* '''x''' - number | |||
* '''y''' - number | |||
* '''seed0''' (constant) - number | |||
* '''seed1''' (constant) - number | |||
* '''input_scale''' (constant, default: 1) - number | |||
* '''output_scale''' (constant, default: 1) - number | |||
* '''octaves''' (constant) - number | |||
* '''octave_input_scale_multiplier''' (constant, default: 0.5) - number | |||
* '''octave_output_scale_multiplier''' (constant, default: 2) - number | |||
* '''octave_seed0_shift''' (constant, default: 1) - number | |||
=== random-penalty === | |||
'''Arguments (named)''': | |||
* '''x''' - number | |||
* '''y''' - number | |||
* '''source''' - number | |||
* '''seed''' (constant, default: 1) - number | |||
* '''amplitude''' (constant, default: 1) - number | |||
=== log2 === | |||
'''Argument (positional)''': value (number) | |||
=== noise-layer-name-to-id === | |||
'''Argument (positional)''': value (string) | |||
=== autoplace-probability === | |||
'''Argument (positional)''': value (object) | |||
=== autoplace-richness === | |||
'''Argument (positional)''': value (object) | |||
=== offset-points === | |||
'''Arguments (positional)''': | |||
* '''offset''' - map position - Vector of how the positions should be shifted | |||
* '''positions''' - list of map positions - The positions that should be shifted | |||
See [[#array-construction|array-construction]] for how to specify map positions. | |||
Example: | |||
<syntaxhighlight lang="lua"> | |||
-- Shifts "positions" by {100, 90} | |||
local noise = require("noise") | |||
local positions = noise.make_point_list({{-10, -40}, {-50, -20}}) | |||
local offset = noise.make_array({100, 90}) | |||
local offset_positions = | |||
{ | |||
type = "function-application", | |||
function_name = "offset-points", | |||
arguments = {offset, positions} | |||
} | |||
-- or with the noise lib | |||
local also_offset_positions = noise.function_application("offset-points", {offset, positions}) | |||
</syntaxhighlight> | |||
=== factorio-multioctave-noise === | === factorio-multioctave-noise === | ||
'''Arguments (named)''': | |||
* '''x''' | |||
* '''y''' | |||
* '''persistence''' (constant) - how strong is each layer compared to the next larger one | |||
* '''seed0''' (constant) - integer between 0 and 4294967295 (inclusive) used to populate the backing random noise | |||
* '''seed1''' (constant) - integer between 0 and 255 (inclusive) used to provide extra randomness when sampling | |||
* '''input_scale''' (constant, default: 1) - x and y will be multiplied by this before sampling | |||
* '''output_scale''' (constant, default: 1) - output will be multiplied by this before being returned | |||
* '''octaves''' (constant) - how many layers of noise at different scales to sum | |||
=== spot-noise === | |||
Generates random conical spots. The map is divided into square regions, and within each region, candidate points are chosen at random and target density, spot quantity, and radius are calculated for each point (or one of every '''skip_span''' candidate points) by configured expressions. Each spot contributes a quantity to a regional target total (which is the average of sampled target densities times the area of the region) until the total has been reached or a maximum spot count is hit. The output value of the function is the maximum height of any spot at a given point. | |||
The parameters that provide expressions to be evaluated for each point (all named '''something_expression''') need to actually return expression objects. | |||
The quantity of the spot is assumed to be the same as its volume. Since the volume of a cone is '''pi * radius^2 * height / 3''', | |||
the height ('peak value') of any given spot is calculated as '''3 * quantity / (pi * radius^2)''' | |||
'''Arguments (named)''': | |||
* '''x''' (number) | |||
* '''y''' (number) | |||
* '''seed0''' (constant integer) - random seed, part 1 - usually the map seed is used | |||
* '''seed1''' (constant integer) - random seed, part 2 - usually chosen to identify the noise layer | |||
* '''region_size''' (constant integer, default: 512) - width/height of each region | |||
* '''skip_offset''' (constant integer, default: 0) - offset of the first candidate point to use | |||
* '''skip_span''' (constant integer, default: 1) - number of candidate points to skip over after each one used as a spot, including the used one | |||
* '''candidate_point_count''' (constant integer, default:256) - how many candidate points to generate | |||
* '''candidate_spot_count''' (constant integer, default depends on skip_span) - an alternative to candidate_point_count - number of spots to generate: '''candidate_spot_count = X''' is equivalent to '''candidate_point_count / skip_span = X''' | |||
* '''suggested_minimum_candidate_point_spacing''' (constant number, default depends on region size and candidate_point_count) - minimum spacing to *try* to achieve while randomly picking points; spot noise may end up placing spots closer than this in crowded regions | |||
* '''hard_region_target_quantity''' (constant boolean, default: true) - whether to place a hard limit on the total quantity in each region by reducing the size of any spot (which will be the last spot chosen) that would put it over the limit. | |||
* '''density_expression''' (number-returningexpression) - an expression that will be evaluated for each candidate spot to calculate density at that point | |||
* '''spot_quantity_expression''' (number-returningexpression) - an expression that will be evaluated for each candidate spot to calculate the spot's quantity | |||
* '''spot_radius_expression''' (number-returning expression) - an expression that will be evaluated for each candidate spot to calculate the spot's radius (this, together with quantity, will determine the spots peak value) | |||
* '''spot_favorability_expression''' (number-returning expression) - an expression that will be evaluated for each candidate spot to calculate the spot's favorability; spots with higher favorability will be considered first when building the final list of spots for a region | |||
* '''basement_value''' (constant) - number | |||
* '''maximum_spot_basement_radius''' (constant) - number | |||
* '''comment''' (constant) - comment string | |||
The infinite series of candidate points (of which '''candidate_point_count''' are actually considered) generated by '''spot-noise''' expressions with the same '''seed0''', '''seed1''', '''region_size''', and '''suggested_minimum_candidate_point_spacing''' will be identical. This allows multiple spot-noise expressions (e.g. for different ore patches) to avoid overlap by using different points from the same list, determined by '''skip_span''' and '''skip_offset'''. | |||
== Example definition == | |||
To override the 'temperature' named noise expression with one that linearly increases to the southeast: | |||
<syntaxhighlight lang="lua"> | |||
local noise = require("noise"); | |||
data:extend{ | |||
{ | |||
type = "noise-expression", | |||
name = "new-temperature-function", | |||
intended_property = "temperature", -- Makes this available in the 'temperature generator' drop-down | |||
expression = noise.define_noise_function( function(x,y,tile,map) | |||
return (x + y) / 1000 | |||
end) | |||
} | |||
} | |||
</syntaxhighlight> | |||
Which is equivalent to: | |||
<syntaxhighlight lang="lua"> | |||
data:extend{ | |||
{ | |||
type = "noise-expression", | |||
name = "new-temperature-function", | |||
intended_property = "temperature", | |||
expression = { | |||
type = "function-application", | |||
function_name = "divide", | |||
arguments = { | |||
{ | |||
type = "function-application", | |||
function_name = "add", | |||
arguments = { | |||
{ | |||
type = "variable", | |||
variable_name = "x" | |||
}, | |||
{ | |||
type = "variable", | |||
variable_name = "y" | |||
} | |||
} | |||
}, | |||
{ | |||
type = "literal-number", | |||
literal_value = 1000 | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
== See also == | |||
* [https://togos.github.io/togos-example-noise-programs/ A tutorial on authoring noise functions] |
Latest revision as of 15:28, 25 November 2020
Basics
A fragment of a functional program used to generate coherent noise, probably for purposes related to terrain generation.
Noise expressions can be provided as table literals or built using functions in the built-in noise
library. The built-in noise library allows writing much more concise code, so its usage will be shown in most examples on this page.
noise.define_noise_function
allows noise expressions to be defined using a shorthand
that's a subset of Lua (see example definition for an example and its literal equivalent).
Types/NoiseExpression is used by NamedNoiseExpressionPrototype::expression, AutoplaceSpecification::probability_expression and AutoplaceSpecification::richness_expression.
Mandatory properties
type
Type: Types/string
Name of the type of this expression. Which other properties apply depend on the expression type.
Expression types
variable
Properties:
- variable_name: a Types/string
Reference to a pre-defined variable, constant, or a named noise expression. Variables referencing named noise expressions may have their reference overridden by other named noise expression if their intended_property is the variable name and it is selected by the user in the map generator GUI. See Prototype/NamedNoiseExpression#Custom intended_property.
Predefined variables:
- x - number - Current x position on the map
- y - number - Current y position on the map
Predefined constants (note that map gen settings can also be provided by a Types/MapGenPreset):
- map_seed - number - Taken from the MapGenSettings
- map_width - number - Taken from the MapGenSettings
- map_height - number - Taken from the MapGenSettings
- water_level - number - Don't use; use wlc_elevation_minimum instead
- finite_water_level - number - Don't use; use wlc_elevation_offset instead
- wlc_elevation_offset - number - When the result of 10 × log2("water") with "water" from MapGenSettings is finite,
wlc_elevation_offset = -(10 * log2(water))
, elsewlc_elevation_offset = 0
- wlc_elevation_minimum - number - When the result of 10 × log2("water") with "water" from MapGenSettings is infinite,
wlc_elevation_minimum = -∞
, elsewlc_elevation_minimum = 4
- cliff_elevation_offset - number - Taken from the MapGenSettings (CliffPlacementSettings)
- cliff_elevation_interval - number - Taken from the MapGenSettings (CliffPlacementSettings)
- control-setting:cliffs:richness:multiplier - number - Taken from the MapGenSettings (CliffPlacementSettings)
- terrace_elevation_offset - number - Calculated from the cliff and water settings.
- terrace_elevation_interval - number - Same as "cliff_elevation_interval"
- starting_area_radius - number - Taken from the MapGenSettings
- starting_positions - map position list - Taken from the MapGenSettings
- starting_lake_positions - map position list - Calculated from starting positions and map seed
- peaceful_mode - boolean - Taken from the MapGenSettings
- control-setting:<prototype name>:frequency - number - Provided for all of the tile, entity, decorative, autoplace-control prototypes.
- control-setting:<prototype name>:size - number - Provided for all of the tile, entity, decorative, autoplace-control prototypes.
- control-setting:<prototype name>:richness - number - Provided for all of the tile, entity, decorative, autoplace-control prototypes.
A list of all named noise expression defined in the base game can be found at Data.raw#noise-expression. Notable expressions defined by the base game are:
- distance - number -
noise.distance_from(noise.var("x"), noise.var("y"), noise.var("starting_positions"))
, so the distance from the closest starting position. distance is never < 0. - tier_from_start - number -
noise.max(0.0, noise.var("distance") - noise.var("starting_area_radius")) / noise.var("starting_area_radius)
- tier - number -
noise.var("tier_from_start")
, so same as tier_from_start. - starting_area_weight - number -
1 - noise.min(1.0, noise.var("tier_from_start") / 2.0)
- moisture - number - A value between 0 and 1 that determines whether a tile becomes sandy (low moisture) or grassy (high moisture).
- aux - number - A value between 0 and 1 that determines whether low-moisture tiles become sand or red desert.
- temperature - number - Provides a value (vaguely representing degrees Celsius, varying between -20 and 50) that is used (together with moisture and aux) as part of tree and decorative placement.
- elevation - number - Tiles values less than zero become water. Cliffs are placed along certain contours according to CliffPlacementSettings.
- cliffiness - number - Determines whether (when >0.5) or not (when <0.5) a cliff will be placed at an otherwise suitable (according to CliffPlacementSettings) location.
- enemy-base-intensity - number - Is referenced by both enemy-base-frequency and enemy-base-radius. i.e. if this is overridden, enemy base frequency and size will both be affected and do something reasonable. By default, this expression returns a value proportional to distance from any starting point, clamped at about 7.
- enemy-base-frequency - number - Represents average number of enemy bases per tile for a region, by default in terms of enemy-base-intensity.
- enemy-base-radius - number - Represents the radius of an enemy base, if one were to be placed on the given tile, by default proportional to a constant plus enemy-base-intensity.
Note that the named noise expressions are all defined in Lua, so mods may remove or change the notable expressions listed above or change how they are used in the map generation.
Examples:
local noise = require("noise")
local y =
{
type = "variable",
variable_name = "y" -- predefined variable
}
local x = noise.var("x") -- predefined variable, with the noise lib
local width =
{
type = "variable",
variable_name = "map_width" -- predefined constant
}
local height = noise.var("map_height") -- predefined constant, with the noise lib
local aux =
{
type = "variable",
variable_name = "aux" -- named noise expression
}
local cliffiness = noise.var("cliffiness") -- named noise expression, with the noise lib
function-application
Apply a function to a list or associative array of arguments. Some functions expect arguments to be named and some expect them not to be.
Function calls are their own class of expression (as opposed to every function just being its own expression type) because function calls all have similar properties -- arguments are themselves expressions, a function call with all-constant arguments can be constant-folded (due to referential transparency), etc.
Properties:
- function_name (a string; see #Functions, below)
- arguments (a list or associative array of argument expressions)
literal-boolean
Evaluates to the same boolean value (true or false) every time, given by the literal_value property. May be used as a number value, evaluates to 1 for true and 0 for false.
literal-number
Evaluates to the same number every time, given by the literal_value property. All numbers are treated as Types/floats internally unless otherwise specified. May be used as a boolean value, evaluates to true for numbers > 0, anything else evaluates to false.
Example:
local ten =
{
type = "literal-number",
literal_value = 10
}
-- or with the noise lib, see the "Basics" section above
local noise = require("noise")
local twenty_point_five = noise.to_noise_expression(20.5)
literal-string
Evaluates to the same string every time, given by the literal_value property.
Since the noise generation runtime has no notion of strings or use for them, this is useful only in constant contexts.
literal-object
Evaluates to the same object every time, given by the literal_value property.
e.g.
{
type = "literal-object",
literal_value = {
name = "Bob Hope",
birth_date = {
year = 1903,
month = 5,
day_of_month = 29
}
}
}
Since the noise generation runtime has no notion of objects or use for them, this is useful only in constant contexts, such as the argument of the autoplace-probability function (where the 'literal object' is an AutoplaceSpecitication)
literal-expression
Returns the expression represented by its literal-value property.
Useful mostly for passing expressions (to be evaluated later) to the spot-noise function.
array-construction
value_expressions property should be a list of expressions, each of which will be evaluated to come up with the corresponding value in the resulting array.
Used to construct map positions ({x, y}) and map position lists ({{x0,y0}, {y1,y1}, ...}) for offset-points and distance-from-nearest-point.
Examples of constructing a map position and map position list:
local noise = require("noise")
local tne = noise.to_noise_expression
local map_pos_1 = -- the map position {x = 100, y = -200} specified directly
{
type = "array-construction",
value_expressions = {tne(100), tne(-200)}
}
-- or with make_array from the noise lib required above
local map_pos_2 = noise.make_array({100, 200})
local map_pos_list = -- a map position list: {{x = 100, y = -200}, {x = 100, y = 200}}
{
type = "array-construction",
value_expressions = {map_pos_1, map_pos_2}
}
-- or with the noise lib
local also_map_post_list = noise.make_point_list({{100, -200}, {100, 200}})
procedure-delimiter
Evaluates and returns the value of its expression property, which is itself an expression.
This hints to the compiler that it should break the subexpression into its own procedure so that the result can be re-used in multiple places. For instance if you want to re-use the same multioctave noise for determining probability of multiple tiles/entities, wrap the multioctave noise expression in a procedure-delimiter. Alternatively, make the noise its own NamedNoiseExpression and reference it by name, using a variable.
if-else-chain
Has an arguments property that is a list of condition-result expression pairs followed by a default result expression, like so:
{
type = "if-else-chain",
arguments = {
condition1, result1,
condition2, result2,
...
defaultResult
}
}
The result of the if-else-chain is the value of the first result expression whose condition expression evaluated to true, or the value of the default result ('else') expression.
Functions
add
Arguments (positional): between 0 and 999 numbers
Takes the positional arguments and adds them.
subtract
Arguments (positional):
- minuend - number
- subtrahend - number
Takes 2 positional arguments and subtracts the second from the first.
multiply
Arguments (positional): between 0 and 999 numbers
Takes the positional arguments and multiplies them.
divide
Arguments (positional):
- dividend - number
- divisor - number
Takes 2 positional arguments and divides the first by the second.
exponentiate
Arguments (positional):
- base - number
- exponent - number
Takes 2 positional arguments, and raises the first to the second power.
absolute-value
Arguments (positional): value to be absoluted
Takes a single positional argument and returns its absolute value. i.e. If the argument is negative, it is inverted.
clamp
Arguments (positional):
- value - number to be clamped
- floor - lower limit
- ceiling - upper limit
First argument is clamped between the second and third. The second is treated as a lower limit and the third the upper limit.
compile-time-log
Arguments: Between 1 and 999 values of any type
Prints all of its arguments to the log file when the expression is compiled. For that it needs to part of another expression that is compiled. The last argument of the compile-time-log is returned as the "result" of the compile-time-log.
Example of usage inside a NamedNoiseExpression:
local noise = require("noise")
local tne = noise.to_noise_expression
-- see the named noise expression docs linked above the code for how this works
data:extend{{
type = "noise-expression",
name = "compile-log-test",
intended_property = "elevation",
expression = noise.compile_time_log(2000, noise.var("y"), tne(100) - noise.var("distance"))
}}
-- When "compile-log-test" is selected as the map type and a map preview or map is generated, this logs:
-- Info data-updates.lua:24: 2000.000000 reference to variable 'y' subtract
-- Furthermore, the elevation noise expression is set to 'tne(100) - noise.var("distance")', producing a circular island with a 100 tile radius
distance-from-nearest-point
Arguments (named):
- x - number
- y - number
- points - list of map positions
- maximum_distance (constant, default: max double) - number
Computes the euclidean distance of the position {x, y} to all position listed in points and returns the shortest distance. The returned distance can be maximum_distance at most.
See array-construction for how to specify a map position list.
Example:
-- Shortest distance at the current {x, y} from the two given points, but at most 1000
local noise = require("noise")
local tne = noise.to_noise_expression
local positions = noise.make_point_list({{-100, -40}, {-50, -200}})
local shortest_distance =
{
type = "function-application",
function_name = "distance-from-nearest-point",
arguments = {x = noise.var("x"), y = noise.var("y"), points = positions, maximum_distance = tne(1000)}
}
-- or with the noise lib
local also_shortest_distance = noise.function_application("distance-from-nearest-point", {x = noise.var("x"), y = noise.var("y"), points = positions, maximum_distance = 1000})
ridge
Arguments (positional):
- value - number to be ridged
- floor - lower limit
- ceiling - upper limit
Similar to clamp but the input value is folded back across the upper and lower limits until it lies between them.
Example:
local noise = require("noise")
local ridge_1 = noise.ridge(6, 1, 5) -- this returns 4
local ridge_2 = noise.ridge(-1, 1, 5) -- this returns 3
terrace
Arguments (positional):
- value - number
- offset (constant) - number
- width (constant) - number
- strength - number
modulo
Arguments (positional):
- dividend - number
- divisor - number
Takes 2 positional arguments and divides the first by the second and returns the remainder. This is implemented using fmod(double, double).
floor
Arguments (positional):
- value - number
Takes one 1 numeric value and returns its floor.
ceil
Arguments (positional):
- value - number
Takes one 1 numeric value and returns its ceiling.
bitwise-and
Arguments (positional): between 0 and 999 numbers
Casts the positional arguments to signed 32-bit integers and performs bitwise AND on them.
bitwise-or
Arguments (positional): between 0 and 999 numbers
Casts the positional arguments to signed 32-bit integers and performs bitwise OR on them.
bitwise-xor
Arguments (positional): between 0 and 999 numbers
Casts the positional arguments to signed 32-bit integers and performs bitwise EXCLUSIVE OR on them.
bitwise-not
Arguments (positional):
- value - number to be negated
Casts the positional argument to a signed 32-bit integer and bitwise negates it.
sin
Arguments (positional):
- value - number
Takes one 1 value and returns its sine.
cos
Arguments (positional):
- value - number
Takes one 1 value and returns its cosine.
atan2
Arguments (positional):
- y - number
- x - number
Returns the arc tangent of y/x using the signs of arguments to determine the correct quadrant.
less-than
Arguments (positional):
- lhs - number
- rhs - number
Returns the result of lhs < rhs as literal number that is 0 for false and 1 for true.
less-or-equal
Arguments (positional):
- lhs - number
- rhs - number
Returns the result of lhs <= rhs as literal number that is 0 for false and 1 for true.
equals
Arguments (positional):
- lhs - number
- rhs - number
Returns the result of lhs == rhs as literal number that is 0 for false and 1 for true.
factorio-basis-noise
Arguments (named):
- x
- y
- seed0 (constant) - integer between 0 and 4294967295 (inclusive) used to populate the backing random noise
- seed1 (constant) - integer between 0 and 255 (inclusive) used to provide extra randomness when sampling
- input_scale (constant, default: 1) - x and y will be multiplied by this before sampling
- output_scale (constant, default: 1) - output will be multiplied by this before being returned
Scaling input and output can be accomplished other ways, but are done so commonly as to be built into this function for performance reasons.
factorio-quick-multioctave-noise
Arguments (named):
- x - number
- y - number
- seed0 (constant) - number
- seed1 (constant) - number
- input_scale (constant, default: 1) - number
- output_scale (constant, default: 1) - number
- octaves (constant) - number
- octave_input_scale_multiplier (constant, default: 0.5) - number
- octave_output_scale_multiplier (constant, default: 2) - number
- octave_seed0_shift (constant, default: 1) - number
random-penalty
Arguments (named):
- x - number
- y - number
- source - number
- seed (constant, default: 1) - number
- amplitude (constant, default: 1) - number
log2
Argument (positional): value (number)
noise-layer-name-to-id
Argument (positional): value (string)
autoplace-probability
Argument (positional): value (object)
autoplace-richness
Argument (positional): value (object)
offset-points
Arguments (positional):
- offset - map position - Vector of how the positions should be shifted
- positions - list of map positions - The positions that should be shifted
See array-construction for how to specify map positions.
Example:
-- Shifts "positions" by {100, 90}
local noise = require("noise")
local positions = noise.make_point_list({{-10, -40}, {-50, -20}})
local offset = noise.make_array({100, 90})
local offset_positions =
{
type = "function-application",
function_name = "offset-points",
arguments = {offset, positions}
}
-- or with the noise lib
local also_offset_positions = noise.function_application("offset-points", {offset, positions})
factorio-multioctave-noise
Arguments (named):
- x
- y
- persistence (constant) - how strong is each layer compared to the next larger one
- seed0 (constant) - integer between 0 and 4294967295 (inclusive) used to populate the backing random noise
- seed1 (constant) - integer between 0 and 255 (inclusive) used to provide extra randomness when sampling
- input_scale (constant, default: 1) - x and y will be multiplied by this before sampling
- output_scale (constant, default: 1) - output will be multiplied by this before being returned
- octaves (constant) - how many layers of noise at different scales to sum
spot-noise
Generates random conical spots. The map is divided into square regions, and within each region, candidate points are chosen at random and target density, spot quantity, and radius are calculated for each point (or one of every skip_span candidate points) by configured expressions. Each spot contributes a quantity to a regional target total (which is the average of sampled target densities times the area of the region) until the total has been reached or a maximum spot count is hit. The output value of the function is the maximum height of any spot at a given point.
The parameters that provide expressions to be evaluated for each point (all named something_expression) need to actually return expression objects.
The quantity of the spot is assumed to be the same as its volume. Since the volume of a cone is pi * radius^2 * height / 3, the height ('peak value') of any given spot is calculated as 3 * quantity / (pi * radius^2)
Arguments (named):
- x (number)
- y (number)
- seed0 (constant integer) - random seed, part 1 - usually the map seed is used
- seed1 (constant integer) - random seed, part 2 - usually chosen to identify the noise layer
- region_size (constant integer, default: 512) - width/height of each region
- skip_offset (constant integer, default: 0) - offset of the first candidate point to use
- skip_span (constant integer, default: 1) - number of candidate points to skip over after each one used as a spot, including the used one
- candidate_point_count (constant integer, default:256) - how many candidate points to generate
- candidate_spot_count (constant integer, default depends on skip_span) - an alternative to candidate_point_count - number of spots to generate: candidate_spot_count = X is equivalent to candidate_point_count / skip_span = X
- suggested_minimum_candidate_point_spacing (constant number, default depends on region size and candidate_point_count) - minimum spacing to *try* to achieve while randomly picking points; spot noise may end up placing spots closer than this in crowded regions
- hard_region_target_quantity (constant boolean, default: true) - whether to place a hard limit on the total quantity in each region by reducing the size of any spot (which will be the last spot chosen) that would put it over the limit.
- density_expression (number-returningexpression) - an expression that will be evaluated for each candidate spot to calculate density at that point
- spot_quantity_expression (number-returningexpression) - an expression that will be evaluated for each candidate spot to calculate the spot's quantity
- spot_radius_expression (number-returning expression) - an expression that will be evaluated for each candidate spot to calculate the spot's radius (this, together with quantity, will determine the spots peak value)
- spot_favorability_expression (number-returning expression) - an expression that will be evaluated for each candidate spot to calculate the spot's favorability; spots with higher favorability will be considered first when building the final list of spots for a region
- basement_value (constant) - number
- maximum_spot_basement_radius (constant) - number
- comment (constant) - comment string
The infinite series of candidate points (of which candidate_point_count are actually considered) generated by spot-noise expressions with the same seed0, seed1, region_size, and suggested_minimum_candidate_point_spacing will be identical. This allows multiple spot-noise expressions (e.g. for different ore patches) to avoid overlap by using different points from the same list, determined by skip_span and skip_offset.
Example definition
To override the 'temperature' named noise expression with one that linearly increases to the southeast:
local noise = require("noise");
data:extend{
{
type = "noise-expression",
name = "new-temperature-function",
intended_property = "temperature", -- Makes this available in the 'temperature generator' drop-down
expression = noise.define_noise_function( function(x,y,tile,map)
return (x + y) / 1000
end)
}
}
Which is equivalent to:
data:extend{
{
type = "noise-expression",
name = "new-temperature-function",
intended_property = "temperature",
expression = {
type = "function-application",
function_name = "divide",
arguments = {
{
type = "function-application",
function_name = "add",
arguments = {
{
type = "variable",
variable_name = "x"
},
{
type = "variable",
variable_name = "y"
}
}
},
{
type = "literal-number",
literal_value = 1000
}
}
}
}
}