|
local noise = require("noise") |
|
local expression_to_ascii_math = require("noise.expression-to-ascii-math") |
|
local tne = noise.to_noise_expression |
|
local litexp = noise.literal_expression |
|
|
|
local function get_patch_metaset_patch_set_index(patch_metaset, patch_set_name) |
|
if patch_metaset.patch_set_indexes[patch_set_name] == nil then |
|
patch_metaset.patch_set_indexes[patch_set_name] = patch_metaset.next_patch_set_index |
|
patch_metaset.next_patch_set_index = patch_metaset.next_patch_set_index + 1 |
|
data.raw["noise-expression"][patch_metaset.count_expression_name].expression = tne(patch_metaset.next_patch_set_index) |
|
end |
|
return patch_metaset.patch_set_indexes[patch_set_name] |
|
end |
|
|
|
local function new_patch_metaset(params) |
|
data.raw["noise-expression"][params.count_expression_name] = |
|
{ |
|
type = "noise-expression", |
|
name = params.count_expression_name, |
|
expression = tne(0) |
|
} |
|
|
|
return |
|
{ |
|
count_expression_name = params.count_expression_name, |
|
next_patch_set_index = 0, |
|
patch_set_indexes = {}, |
|
get_patch_set_index = get_patch_metaset_patch_set_index |
|
} |
|
end |
|
|
|
|
|
|
|
|
|
if not resource_autoplace__patch_metasets then |
|
resource_autoplace__patch_metasets = |
|
{ |
|
regular = new_patch_metaset{ count_expression_name = "regular-resource-patch-set-count" }, |
|
starting = new_patch_metaset{ count_expression_name = "starting-resource-patch-set-count" } |
|
} |
|
end |
|
|
|
local regular_patch_metaset = resource_autoplace__patch_metasets.regular |
|
local starting_patch_metaset = resource_autoplace__patch_metasets.starting |
|
|
|
|
|
|
|
|
|
local function initialize_patch_set(patch_set_name, has_starting_area_placement) |
|
regular_patch_metaset:get_patch_set_index(patch_set_name) |
|
if has_starting_area_placement then |
|
starting_patch_metaset:get_patch_set_index(patch_set_name) |
|
end |
|
end |
|
|
|
local pointillist_mode = false |
|
local patch_blobbiness_enabled = true |
|
|
|
local function dump_expression(name, expr) |
|
log(name..":\n"..tostring(expression_to_ascii_math(expr))) |
|
end |
|
|
|
local onethird = tne(1)/3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local function resource_autoplace_settings(params) |
|
local name = params.name |
|
local order = params.order or "d" |
|
|
|
local patch_set_name = params.patch_set_name or name |
|
local autoplace_control_name = params.autoplace_control_name or name |
|
|
|
|
|
local base_density = params.base_density |
|
|
|
|
|
local random_probability = params.random_probability or 1 |
|
local base_spots_per_km2 = params.base_spots_per_km2 or 2.5 |
|
local random_spot_size_minimum = params.random_spot_size_minimum or 0.25 |
|
local random_spot_size_maximum = params.random_spot_size_maximum or 2.00 |
|
|
|
local regular_blob_amplitude_multiplier = 1/8 * (params.regular_blob_amplitude_multiplier or 1) |
|
local starting_blob_amplitude_multiplier = 1/8 * (params.starting_blob_amplitude_multiplier or 1) |
|
|
|
local control_setting = noise.get_control_setting(autoplace_control_name) |
|
local frequency_multiplier = control_setting.frequency_multiplier |
|
local size_multiplier = control_setting.size_multiplier |
|
local density_multiplier = frequency_multiplier * size_multiplier |
|
|
|
|
|
|
|
|
|
|
|
|
|
local additional_richness = params.additional_richness or 0 |
|
|
|
|
|
local minimum_richness = params.minimum_richness or 0 |
|
|
|
|
|
local richness_post_multiplier = (params.richness_post_multiplier or 1) * control_setting.richness_multiplier |
|
|
|
local seed1 = params.seed1 or 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
local regular_rq_factor = (params.regular_rq_factor_multiplier or 1) * 1 / 10 |
|
local starting_rq_factor = (params.starting_rq_factor_multiplier or 1) * 1 / 7 |
|
|
|
local elevation = noise.var("elevation") |
|
local distance = noise.var("distance") |
|
|
|
|
|
|
|
|
|
|
|
|
|
local starting_resource_placement_radius = 120 |
|
local regular_modulation |
|
|
|
|
|
|
|
|
|
|
|
local regular_patch_fade_in_distance = 300 |
|
local regular_ns_multiplier_at |
|
if params.has_starting_area_placement == nil then |
|
regular_ns_multiplier_at = function(dist) return 1 end |
|
else |
|
regular_ns_multiplier_at = function(dist) |
|
return noise.clamp((dist - starting_resource_placement_radius) / regular_patch_fade_in_distance, 0, 1) |
|
end |
|
end |
|
local double_density_distance = 1300 |
|
|
|
|
|
local regular_blob_amplitude_maximum_distance = double_density_distance |
|
local spot_enlargement_maximum_distance = regular_blob_amplitude_maximum_distance |
|
|
|
|
|
local function size_effective_distance_at(dist) |
|
if params.has_starting_area_placement == nil then |
|
return dist |
|
else |
|
|
|
return dist - regular_patch_fade_in_distance |
|
end |
|
end |
|
|
|
local function regular_density_at(dist) |
|
|
|
|
|
effective_distance = noise.clamp(size_effective_distance_at(dist), 0, spot_enlargement_maximum_distance) |
|
local distance_density_multiplier = 1 + effective_distance / double_density_distance |
|
return base_density * density_multiplier * distance_density_multiplier * regular_ns_multiplier_at(dist) |
|
end |
|
local spots_per_km2_near_start = base_spots_per_km2 * frequency_multiplier |
|
local candidate_spot_count = params.candidate_spot_count or 21 |
|
|
|
if pointillist_mode then |
|
|
|
|
|
candidate_spot_count = 10000 |
|
spots_per_km2_near_start = candidate_spot_count |
|
end |
|
|
|
|
|
local function regular_spot_quantity_base_at(dist) |
|
return regular_density_at(dist) * 1000000 / spots_per_km2_near_start |
|
end |
|
|
|
local function regular_spot_quantity_typical_at(dist) |
|
local average_random_size_multiplier = (random_spot_size_minimum + random_spot_size_maximum) / 2 |
|
return average_random_size_multiplier * regular_spot_quantity_base_at(dist) |
|
end |
|
local function regular_spot_height_typical_at(dist) |
|
return regular_spot_quantity_typical_at(dist)^(onethird) / ((math.pi/3) * regular_rq_factor^2) |
|
end |
|
|
|
local regular_density_expression = regular_density_at(distance) |
|
local regular_spot_quantity_expression = noise.random_between(random_spot_size_minimum, random_spot_size_maximum) * regular_spot_quantity_base_at(distance) |
|
local regular_spot_radius_expression = noise.min(32, regular_rq_factor * regular_spot_quantity_expression ^ (onethird)) |
|
|
|
if params.has_starting_area_placement ~= nil then |
|
regular_blob_amplitude_maximum_distance = regular_blob_amplitude_maximum_distance + regular_patch_fade_in_distance |
|
end |
|
local function regular_blob_amplitude_at(dist) |
|
return regular_blob_amplitude_multiplier * noise.min( |
|
regular_spot_height_typical_at(regular_blob_amplitude_maximum_distance), |
|
regular_spot_height_typical_at(dist) |
|
) |
|
end |
|
local regular_blob_amplitude_maximum = regular_blob_amplitude_at(regular_blob_amplitude_maximum_distance) |
|
local regular_blob_amplitude_expression = regular_blob_amplitude_at(distance) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local starting_frequency_multiplier = ((frequency_multiplier - 1) * 0.5) + 1 |
|
local starting_amount = 40000 * base_density * starting_frequency_multiplier * size_multiplier |
|
|
|
local starting_area_sharpness = tne(math.huge) |
|
local starting_resource_placement_area = math.pi*starting_resource_placement_radius*starting_resource_placement_radius |
|
local starting_density = starting_amount / starting_resource_placement_area |
|
|
|
local starting_modulation = |
|
noise.clamp((starting_resource_placement_radius - distance) * starting_area_sharpness, 0, 1) |
|
local starting_feasibility = |
|
noise.clamp((elevation - 1) / 10, 0, 1) * starting_modulation |
|
|
|
|
|
|
|
|
|
|
|
|
|
local minimum_favorability_for_full_placement = 1/2 |
|
local starting_spot_count = frequency_multiplier |
|
local starting_area_spot_quantity = starting_amount / minimum_favorability_for_full_placement / starting_spot_count |
|
local starting_spot_height = starting_area_spot_quantity ^ (1/3) / ((math.pi/3) * starting_rq_factor^2) |
|
local starting_blob_amplitude = starting_blob_amplitude_multiplier * starting_spot_height |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local basement_value = noise.min(-6 * regular_blob_amplitude_maximum, |
|
-6 * starting_blob_amplitude) |
|
|
|
local regular_spots = tne{ |
|
type = "function-application", |
|
function_name = "spot-noise", |
|
arguments = |
|
{ |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
seed0 = noise.var("map_seed"), |
|
seed1 = tne(seed1), |
|
region_size = tne(1024), |
|
candidate_spot_count = tne(candidate_spot_count), |
|
suggested_minimum_candidate_point_spacing = tne(45.254833995939045), |
|
skip_span = noise.var("regular-resource-patch-set-count"), |
|
skip_offset = tne(regular_patch_metaset:get_patch_set_index(patch_set_name)), |
|
density_expression = litexp(regular_density_expression), |
|
spot_quantity_expression = litexp(regular_spot_quantity_expression), |
|
hard_region_target_quantity = tne(false), |
|
spot_radius_expression = litexp(regular_spot_radius_expression), |
|
spot_favorability_expression = litexp(1), |
|
basement_value = basement_value, |
|
maximum_spot_basement_radius = tne(128) |
|
} |
|
} |
|
|
|
|
|
local starting_patch_set_index = 0 |
|
if params.has_starting_area_placement == true then |
|
starting_patch_set_index = tne(starting_patch_metaset:get_patch_set_index(patch_set_name)) |
|
end |
|
|
|
|
|
|
|
local starting_spots = tne{ |
|
type = "function-application", |
|
function_name = "spot-noise", |
|
arguments = |
|
{ |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
seed0 = noise.var("map_seed"), |
|
seed1 = tne(seed1+1), |
|
skip_span = noise.var("starting-resource-patch-set-count"), |
|
skip_offset = starting_patch_set_index, |
|
region_size = tne(starting_resource_placement_radius * 2), |
|
candidate_spot_count = tne(32), |
|
minimum_candidate_point_spacing = tne(32), |
|
density_expression = litexp(starting_density * starting_modulation), |
|
spot_quantity_expression = litexp(starting_area_spot_quantity), |
|
hard_region_target_quantity = tne(true), |
|
spot_radius_expression = litexp(starting_rq_factor * starting_area_spot_quantity ^ (onethird)), |
|
spot_favorability_expression = litexp( |
|
starting_feasibility * 2 - |
|
1 * distance / starting_resource_placement_radius + |
|
noise.random(0.5) |
|
), |
|
basement_value = basement_value, |
|
maximum_spot_basement_radius = tne(128) |
|
} |
|
} |
|
|
|
if pointillist_mode or not patch_blobbiness_enabled then |
|
regular_blob_amplitude_expression = 0 |
|
end |
|
if not patch_blobbiness_enabled then |
|
starting_blob_amplitude = 0 |
|
end |
|
|
|
|
|
local blobs0 = tne{ |
|
type = "function-application", |
|
function_name = "factorio-basis-noise", |
|
arguments = |
|
{ |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
seed0 = noise.var("map_seed"), |
|
seed1 = tne(seed1), |
|
input_scale = tne(1/8), |
|
output_scale = tne(1) |
|
} |
|
} + tne{ |
|
type = "function-application", |
|
function_name = "factorio-basis-noise", |
|
arguments = |
|
{ |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
seed0 = noise.var("map_seed"), |
|
seed1 = tne(seed1), |
|
input_scale = tne(1/24), |
|
output_scale = tne(1) |
|
} |
|
} |
|
local blobs0f = blobs0 - 1/4 |
|
|
|
local blobs1 = blobs0 + tne{ |
|
type = "function-application", |
|
function_name = "factorio-basis-noise", |
|
arguments = |
|
{ |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
seed0 = noise.var("map_seed"), |
|
seed1 = tne(seed1), |
|
input_scale = tne(1/64), |
|
output_scale = tne(1.5) |
|
} |
|
} |
|
local blobs1f = blobs1 - onethird |
|
|
|
local regular_patches = regular_spots + blobs1f * regular_blob_amplitude_expression |
|
local starting_patches = starting_spots + blobs0f * starting_blob_amplitude |
|
|
|
local all_patches |
|
if params.has_starting_area_placement == true then |
|
all_patches = noise.max(starting_patches, regular_patches) |
|
elseif params.has_starting_area_placement == false then |
|
all_patches = regular_patches |
|
else |
|
all_patches = regular_patches |
|
end |
|
|
|
local richness_expression = noise.delimit_procedure(all_patches) |
|
local probability_expression = noise.clamp(richness_expression, 0, 1) |
|
if random_probability < 1 then |
|
richness_expression = richness_expression / random_probability |
|
probability_expression = probability_expression * tne{ |
|
type = "function-application", |
|
function_name = "random-penalty", |
|
arguments = |
|
{ |
|
source = tne(1), |
|
x = noise.var("x"), |
|
y = noise.var("y"), |
|
amplitude = tne(1/random_probability) |
|
} |
|
} |
|
end |
|
if additional_richness > 0 then |
|
richness_expression = richness_expression + additional_richness |
|
end |
|
if minimum_richness > 0 then |
|
richness_expression = noise.max(richness_expression, minimum_richness) |
|
end |
|
|
|
|
|
local function post_semd_richness_distance_multiplier_at(sed) |
|
local ddd = double_density_distance |
|
local semd = spot_enlargement_maximum_distance |
|
|
|
|
|
|
|
return (ddd + sed)/(ddd + semd) |
|
end |
|
local richness_distance_multiplier = noise.max(1, post_semd_richness_distance_multiplier_at(size_effective_distance_at(distance))) |
|
|
|
richness_expression = richness_expression * richness_distance_multiplier * richness_post_multiplier |
|
|
|
local ret = |
|
{ |
|
order = order, |
|
control = autoplace_control_name, |
|
probability_expression = probability_expression, |
|
richness_expression = richness_expression |
|
} |
|
|
|
return ret |
|
end |
|
|
|
return |
|
{ |
|
initialize_patch_set = initialize_patch_set, |
|
resource_autoplace_settings = resource_autoplace_settings |
|
} |
|
|