1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-30 19:22:14 +00:00
luanti/builtin/common/settings/dlg_change_mapgen_flags.lua
2025-09-03 11:29:01 +03:00

266 lines
8.8 KiB
Lua

-- Luanti
-- Copyright (C) 2015 PilzAdam
-- SPDX-License-Identifier: LGPL-2.1-or-later
local checkboxes = {}
local function flags_to_table(flags)
return flags:gsub("%s+", ""):split(",", true) -- Remove all spaces and split
end
local function get_current_np_group(setting)
local value = core.settings:get_np_group(setting.name)
if value == nil then
return setting.values
end
local p = "%g"
return {
p:format(value.offset),
p:format(value.scale),
p:format(value.spread.x),
p:format(value.spread.y),
p:format(value.spread.z),
p:format(value.seed),
p:format(value.octaves),
p:format(value.persistence),
p:format(value.lacunarity),
value.flags
}
end
local function get_formspec(dialogdata)
local setting = dialogdata.setting
-- Final formspec will be created at the end of this function
-- Default values below, may be changed depending on setting type
local width = 10
local height = 2
local description_height = 1.5
local t = get_current_np_group(setting)
local dimension = 3
if setting.type == "noise_params_2d" then
dimension = 2
end
local fields = {}
local function add_field(x, name, label, value, tooltips)
fields[#fields + 1] = ("field[%f,%f;3.3,1;%s;%s;%s]"):format(
x, height, name, label, core.formspec_escape(value or "")
)
if tooltips then
fields[#fields + 1] = ("tooltip[%s;%s]"):format(name, table.concat(tooltips, "\n"))
end
end
-- First row
height = height + 0.3
add_field(0.3, "te_offset", fgettext("Offset"), t[1], {fgettext("This value offsets the final noise.")})
add_field(3.6, "te_scale", fgettext("Scale"), t[2], {fgettext("This value is multiplied with the noise before the offset is added.")})
add_field(6.9, "te_seed", fgettext("Seed"), t[6], {
fgettext("This value acts as a random seed for the noise. The same seed results in the same noise.")})
height = height + 1.1
-- Second row
add_field(0.3, "te_spreadx", fgettext("X spread"), t[3], {
fgettext("This value scales the noise in the X axis by this value."),
fgettext("This is also the scale of the largest structures in the X direction of the noise.")})
if dimension == 3 then
add_field(3.6, "te_spready", fgettext("Y spread"), t[4], {
fgettext("This value scales the noise in the Y axis by this value."),
fgettext("This is also the scale of the largest structures in the Y direction of the noise.")})
else
fields[#fields + 1] = "label[4," .. height - 0.2 .. ";" ..
fgettext("2D Noise") .. "]"
end
add_field(6.9, "te_spreadz", fgettext("Z spread"), t[5], {
fgettext("This value scales the noise in the Z axis by this value."),
fgettext("This is also the scale of the largest structures in the Z direction of the noise.")})
height = height + 1.1
-- Third row
add_field(0.3, "te_octaves", fgettext("Octaves"), t[7], {
fgettext("This value controls how many octaves the noise will have."),
fgettext("An octave is a simple noise generator. Its scale and amplitude will be multiplied based on the Persistence and Lacunarity settings."),
fgettext("Finally, all of the octaves will be added to generate this noise.")})
add_field(3.6, "te_persist", fgettext("Persistence"), t[8], {
fgettext("This value multiplies every octave's amplitude by persistence^(i-1) where i is the place of the octave."),
fgettext("Example: If the persistence was 0.5, the 1st octave would be amplified by 1, the 2nd would be by 0.5, the 3rd would be by 0.25, etc.")})
add_field(6.9, "te_lacun", fgettext("Lacunarity"), t[9], {
fgettext("This value multiplies every octave's scale by lacunarity^(i-1) where i is the place of the octave."),
fgettext("Example: If the lacunarity was 3, the 1st octave would be scaled by 1, the 2nd would be by 3, the 3rd would be by 9s, etc.")})
height = height + 1.1
local enabled_flags = flags_to_table(t[10])
local flags = {}
for _, name in ipairs(enabled_flags) do
-- Index by name, to avoid iterating over all enabled_flags for every possible flag.
flags[name] = true
end
for _, name in ipairs(setting.flags) do
local checkbox_name = "cb_" .. name
local is_enabled = flags[name] == true -- to get false if nil
checkboxes[checkbox_name] = is_enabled
end
local formspec = table.concat(fields)
.. "checkbox[0.5," .. height - 0.6 .. ";cb_defaults;"
--[[~ "defaults" is a noise parameter flag.
It describes the default processing options
for noise settings in the settings menu. ]]
.. fgettext("defaults") .. ";" -- defaults
.. tostring(flags["defaults"] == true) .. "]" -- to get false if nil
.. "tooltip[cb_defaults;" .. fgettext("This flag overrides the eased flag based on the noise map type.")
.. "\n" .. fgettext("2D noise will make eased on.")
.. "\n" .. fgettext("3D noise will make eased off.") .. "]"
.. "checkbox[5," .. height - 0.6 .. ";cb_eased;"
--[[~ "eased" is a noise parameter flag.
It is used to make the map smoother and
can be enabled in noise settings in
the settings menu. ]]
.. fgettext("eased") .. ";" -- eased
.. tostring(flags["eased"] == true) .. "]"
.. "tooltip[cb_eased;"
.. fgettext("This flag maps noise gradient values onto a quintic S-curve before performing interpolation.")
.. "\n" .. fgettext("This results in smooth noise instead of gridlike noise.")
.. "\n" .. fgettext("Making 3D noise eased is not recommended because it significantly increases the load.") .. "]"
.. "checkbox[5," .. height - 0.15 .. ";cb_absvalue;"
--[[~ "absvalue" is a noise parameter flag.
It is short for "absolute value".
It can be enabled in noise settings in
the settings menu. ]]
.. fgettext("absvalue") .. ";" -- absvalue
.. tostring(flags["absvalue"] == true) .. "]"
.. "tooltip[cb_absvalue;"
.. fgettext("This flag takes the absolute value of each octave while adding them together.")
.. "\n" .. fgettext("This results in spiky noise.") .. "]"
height = height + 1
-- Box good, textarea bad. Calculate textarea size from box.
local function create_textfield(size, label, text, bg_color)
local textarea = {
x = size.x + 0.3,
y = size.y,
w = size.w + 0.25,
h = size.h * 1.16 + 0.12
}
return ("box[%f,%f;%f,%f;%s]textarea[%f,%f;%f,%f;;%s;%s]"):format(
size.x, size.y, size.w, size.h, bg_color or "#000",
textarea.x, textarea.y, textarea.w, textarea.h,
core.formspec_escape(label), core.formspec_escape(text)
)
end
-- When there's an error: Shrink description textarea and add error below
if dialogdata.error_message then
local error_box = {
x = 0,
y = description_height - 0.4,
w = width - 0.25,
h = 0.5
}
formspec = formspec ..
create_textfield(error_box, "", dialogdata.error_message, "#600")
description_height = description_height - 0.75
end
-- Get description field
local description_box = {
x = 0,
y = 0.2,
w = width - 0.25,
h = description_height
}
local setting_name = setting.name
if setting.readable_name then
setting_name = fgettext_ne(setting.readable_name) ..
" (" .. setting.name .. ")"
end
local comment_text
if setting.comment == "" then
comment_text = fgettext_ne("(No description of setting given)")
else
comment_text = fgettext_ne(setting.comment)
end
return (
"size[" .. width .. "," .. height + 0.25 .. ",true]" ..
create_textfield(description_box, setting_name, comment_text) ..
formspec ..
"button[" .. width / 2 - 2.5 .. "," .. height - 0.4 .. ";2.5,1;btn_done;" ..
fgettext("Save") .. "]" ..
"button[" .. width / 2 .. "," .. height - 0.4 .. ";2.5,1;btn_cancel;" ..
fgettext("Cancel") .. "]"
)
end
local function buttonhandler(this, fields)
local setting = this.data.setting
if fields["btn_done"] or fields["key_enter"] then
local np_flags = {}
for _, name in ipairs(setting.flags) do
if checkboxes["cb_" .. name] then
table.insert(np_flags, name)
end
end
checkboxes = {}
if setting.type == "noise_params_2d" then
fields["te_spready"] = fields["te_spreadz"]
end
local new_value = {
offset = fields["te_offset"],
scale = fields["te_scale"],
spread = {
x = fields["te_spreadx"],
y = fields["te_spready"],
z = fields["te_spreadz"]
},
seed = fields["te_seed"],
octaves = fields["te_octaves"],
persistence = fields["te_persist"],
lacunarity = fields["te_lacun"],
flags = table.concat(np_flags, ", ")
}
core.settings:set_np_group(setting.name, new_value)
core.settings:write()
this:delete()
return true
end
if fields["btn_cancel"] then
this:delete()
return true
end
for name, value in pairs(fields) do
if name:sub(1, 3) == "cb_" then
checkboxes[name] = core.is_yes(value)
return false -- Don't update the formspec!
end
end
return false
end
function create_change_mapgen_flags_dlg(setting)
assert(type(setting) == "table")
local retval = dialog_create("dlg_change_mapgen_flags",
get_formspec,
buttonhandler,
nil)
retval.data.setting = setting
return retval
end