Bin no_trees_on_this_level, use exp. decay away from snow line.
Probability of placing an arctic tree is now an exponential decay function of height distance from the snow line, instead of the previous 50% blocks. This results in a more gradual thinning out of arctic trees in each direction. The algorithm is: p = exp(-3 * distance / range_setting), using a rather crude approximation of the exponential function. The no_trees_on_this_level setting is not really useful, and its dual behaviour to disallow discrete height levels and turn on the snow line behaviour is unintuitive. Replace it with a simple on/off setting.
This commit is contained in:
@@ -311,7 +311,7 @@ struct ConstructionSettings {
|
||||
bool freeform_edges; ///< allow terraforming the tiles at the map edges
|
||||
uint8 extra_tree_placement; ///< (dis)allow building extra trees in-game
|
||||
uint8 trees_around_snow_line_range; ///< range around snowline for mixed and arctic forest.
|
||||
uint32 no_trees_on_this_level; ///< option to avoid growth of trees on certain tile level.
|
||||
bool trees_around_snow_line_enabled; ///< enable mixed and arctic forest around snowline, and no trees above snowline
|
||||
uint8 command_pause_level; ///< level/amount of commands that can't be executed while paused
|
||||
|
||||
uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames?
|
||||
|
@@ -2310,23 +2310,22 @@ strhelp = STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT
|
||||
strval = STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE
|
||||
cat = SC_BASIC
|
||||
|
||||
[SDT_BOOL]
|
||||
base = GameSettings
|
||||
var = construction.trees_around_snow_line_enabled
|
||||
def = true
|
||||
cat = SC_BASIC
|
||||
patxname = ""everest_treeline.construction.trees_around_snow_line_enabled""
|
||||
|
||||
[SDT_VAR]
|
||||
base = GameSettings
|
||||
var = construction.trees_around_snow_line_range
|
||||
type = SLE_UINT8
|
||||
def = 0
|
||||
min = 0
|
||||
max = 15
|
||||
cat = SC_BASIC
|
||||
|
||||
[SDT_VAR]
|
||||
base = GameSettings
|
||||
var = construction.no_trees_on_this_level
|
||||
type = SLE_UINT32
|
||||
def = 0
|
||||
min = 0
|
||||
max = UINT32_MAX
|
||||
def = 8
|
||||
min = 1
|
||||
max = 20
|
||||
cat = SC_BASIC
|
||||
patxname = ""everest_treeline.construction.trees_around_snow_line_range""
|
||||
|
||||
[SDT_VAR]
|
||||
base = GameSettings
|
||||
|
@@ -118,6 +118,50 @@ static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, uint
|
||||
MakeTree(tile, treetype, count, growth, ground, density);
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous value of _settings_game.construction.trees_around_snow_line_range
|
||||
* used to calculate _arctic_tree_occurance
|
||||
*/
|
||||
static uint8 _previous_trees_around_snow_line_range = 255;
|
||||
|
||||
/**
|
||||
* Array of probabilities for artic trees to appear,
|
||||
* by normalised distance from snow line
|
||||
*/
|
||||
static uint8 _arctic_tree_occurance[24];
|
||||
|
||||
/** Recalculate _arctic_tree_occurance */
|
||||
static void RecalculateArcticTreeOccuranceArray()
|
||||
{
|
||||
/*
|
||||
* Approximate: 256 * exp(-3 * distance / range)
|
||||
* By using:
|
||||
* 256 * ((1 + (-3 * distance / range) / 6) ** 6)
|
||||
* ((256 - (128 * distance / range)) ** 6) >> (5 * 8);
|
||||
*/
|
||||
uint8 range = _settings_game.construction.trees_around_snow_line_range;
|
||||
_previous_trees_around_snow_line_range = range;
|
||||
_arctic_tree_occurance[0] = 255;
|
||||
uint i = 1;
|
||||
for (; i < lengthof(_arctic_tree_occurance); i++) {
|
||||
if (range == 0) break;
|
||||
uint x = 256 - ((128 * i) / range);
|
||||
uint32 output = x;
|
||||
output *= x;
|
||||
output *= x;
|
||||
output *= x;
|
||||
output >>= 16;
|
||||
output *= x;
|
||||
output *= x;
|
||||
output >>= 24;
|
||||
if (output == 0) break;
|
||||
_arctic_tree_occurance[i] = output;
|
||||
}
|
||||
for (; i < lengthof(_arctic_tree_occurance); i++) {
|
||||
_arctic_tree_occurance[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a random TreeType for the given tile based on a given seed
|
||||
*
|
||||
@@ -131,33 +175,33 @@ static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, uint
|
||||
*/
|
||||
static TreeType GetRandomTreeType(TileIndex tile, uint seed)
|
||||
{
|
||||
/* no_trees_on_this_level example: 0xDC96521 is no trees on z levels 13,12,9,6,5,2,1. Set to 0 gives you original gameplay. (See openttd.cfg) */
|
||||
uint32 no_tree = _settings_game.construction.no_trees_on_this_level;
|
||||
byte range = _settings_game.construction.trees_around_snow_line_range;
|
||||
|
||||
switch (_settings_game.game_creation.landscape) {
|
||||
case LT_TEMPERATE:
|
||||
if (no_tree == 0) return (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
|
||||
return (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
|
||||
|
||||
case LT_ARCTIC: {
|
||||
if (no_tree == 0) return (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC);
|
||||
if (!_settings_game.construction.trees_around_snow_line_enabled) {
|
||||
return (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC);
|
||||
}
|
||||
|
||||
uint8 range = _settings_game.construction.trees_around_snow_line_range;
|
||||
if (range != _previous_trees_around_snow_line_range) RecalculateArcticTreeOccuranceArray();
|
||||
|
||||
int z = GetTileZ(tile);
|
||||
if (z > _settings_game.game_creation.snow_line_height + (2 * range)) return TREE_INVALID; // Above tree line.
|
||||
|
||||
/* no_trees_on_this_level */
|
||||
for (; no_tree != 0;) {
|
||||
if ((int)(no_tree & 0xF) == z) return TREE_INVALID;
|
||||
no_tree = no_tree >> 4;
|
||||
int height_above_snow_line = z - _settings_game.game_creation.snow_line_height;
|
||||
uint normalised_distance = (height_above_snow_line < 0) ? -height_above_snow_line : height_above_snow_line + 1;
|
||||
bool arctic_tree = false;
|
||||
if (normalised_distance < lengthof(_arctic_tree_occurance)) {
|
||||
uint adjusted_seed = (seed ^ tile) & 0xFF;
|
||||
arctic_tree = adjusted_seed < _arctic_tree_occurance[normalised_distance];
|
||||
}
|
||||
if (z > (int)_settings_game.game_creation.snow_line_height - range) {
|
||||
/* Below snow level mixed forest. Above is Arctic trees and thinning out. */
|
||||
if (z < _settings_game.game_creation.snow_line_height) {
|
||||
return (seed & 1) ? (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC) : (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
|
||||
} else {
|
||||
return (seed & 1) ? TREE_INVALID : (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC);
|
||||
}
|
||||
if (height_above_snow_line < 0) {
|
||||
/* Below snow level mixed forest. */
|
||||
return (arctic_tree) ? (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC) : (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
|
||||
} else {
|
||||
/* Above is Arctic trees and thinning out. */
|
||||
return (arctic_tree) ? (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC) : TREE_INVALID;
|
||||
}
|
||||
return (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE);
|
||||
}
|
||||
case LT_TROPIC:
|
||||
switch (GetTropicZone(tile)) {
|
||||
|
Reference in New Issue
Block a user