Browse Source

Fix colored slopes palette on change, add color conversion function

master
Karamel 1 year ago
parent
commit
fee4600988
  1. 5
      naturalslopeslib_api.txt
  2. 41
      register_slopes.lua
  3. 126
      update_shape.lua

5
naturalslopeslib_api.txt

@ -128,7 +128,7 @@ Good practices are setting the defaults before registering your slopes, then cal
* Resets naturalslopeslib.default_definition to the less-impacting values.
* These defaults are as follow {drop_source = false, tiles = {}, groups = {}}
### naturalslopeslib.register_slope(base_node_name, def_changes, update_chance, factors)
### naturalslopeslib.register_slope(base_node_name, def_changes, update_chance, factors, color_convert)
* Registers all slope shapes and automatic stomping for a full node.
* `base_node_name` the full block node name.
@ -143,9 +143,10 @@ Good practices are setting the defaults before registering your slopes, then cal
* Then they are changed from def_changes. Use "nil" string to explicitely erase a value (an not nil).
* `update_chance` inverted chance for the node to be updated.
* `factors` optional table for chance factors. By default each factor is 1.
* `color_convert` optional function to convert color palettes (see below). Ignored when paramtype2 from the base node is not "color". By default, it matches the first 8 values, and other color values are set to 0.
* returns ReplacementTable.
Warning: The palette for slopes can only have 8 colors while the original one can hold up to 256 colors. A reduced palette must be provided for nodes which paramtype2 is "color" even if not all colors are used.
About color palettes: The palette for slopes can only have 8 colors while the original one can hold up to 256 colors. A reduced palette must be provided for nodes which paramtype2 is "color" even if not all colors are used. To control how the palette values are converted, you may pass a function(int, bool) as `color_convert`. When the second parameter is true, the first parameter is the full block color index (from 0 to 255) and it must return an index for the slope color (from 0 to 7). When false the first parameter is the slope color index (from 0 to 7) and it must return an index for the full block color index (from 0 to 255).
### naturalslopeslib.set_slopes(base_node_name, straight_name, inner_name, outer_name, pike_name, update_chance, factors)

41
register_slopes.lua

@ -1,9 +1,29 @@
-- Default color index conversion: match values for 0-7 and set to 0 for other values.
local function default_color_convert(color_index, to_slope)
if to_slope then
if color_index > 7 then
return 0
else
return color_index
end
else
return color_index
end
end
-- Table of replacement from solid block to slopes.
-- Populated on slope node registration with add_replacement
-- @param colored_source (boolean) true when paramtype2 is color for the source node
-- color_convert is a function(int, int, bool) to convert the color palette values,
-- it is ignored when colored_source is false.
local replacements = {}
local replacement_ids = {}
local function add_replacement(source_name, update_chance, chance_factors, fixed_replacements)
local function add_replacement(source_name, update_chance, chance_factors, fixed_replacements, colored_source, color_to_slope, color_convert)
if not colored_source then
color_convert = nil
elseif color_convert == nil then
color_convert = default_color_convert
end
local subname = string.sub(source_name, string.find(source_name, ':') + 1)
local straight_name = nil
local ic_name = nil
@ -33,7 +53,9 @@ local function add_replacement(source_name, update_chance, chance_factors, fixed
outer = oc_name,
pike = pike_name,
chance = update_chance,
chance_factors = chance_factors
chance_factors = chance_factors,
_colored_source = colored_source,
_color_convert = color_convert
}
local dest_data_id = {
source = source_id,
@ -42,7 +64,9 @@ local function add_replacement(source_name, update_chance, chance_factors, fixed
outer = oc_id,
pike = pike_id,
chance = update_chance,
chance_factors = chance_factors
chance_factors = chance_factors,
_colored_source = colored_source,
_color_convert = color_convert
}
-- Block
replacements[source_name] = dest_data
@ -305,8 +329,9 @@ end
-- @param node_desc: base for slope node descriptions.
-- @param update_chance: inverted chance for the node to be updated.
-- @param factors (optional): chance factor for each type.
-- @param color_convert (optional): the function to convert color palettes
-- @return Table of slope names: [straight, inner, outer, pike] or nil on error.
function naturalslopeslib.register_slope(base_node_name, def_changes, update_chance, factors)
function naturalslopeslib.register_slope(base_node_name, def_changes, update_chance, factors, color_convert)
if not update_chance then
minetest.log('error', 'Natural slopes: chance is not set for node ' .. base_node_name)
return
@ -347,7 +372,8 @@ function naturalslopeslib.register_slope(base_node_name, def_changes, update_cha
end
end
-- Register replacements
add_replacement(base_node_name, update_chance, chance_factors, slope_names)
local colored = base_node_def.paramtype2 == "color"
add_replacement(base_node_name, update_chance, chance_factors, slope_names, colored, color_convert)
-- Enable on walk update for base node
if naturalslopeslib.setting_enable_shape_on_walk() then
poschangelib.register_stomp(base_node_name,
@ -368,7 +394,7 @@ function naturalslopeslib.register_slope(base_node_name, def_changes, update_cha
end
--- Add a slopping behaviour to existing nodes.
function naturalslopeslib.set_slopes(base_node_name, straight_name, inner_name, outer_name, pike_name, update_chance, factors)
function naturalslopeslib.set_slopes(base_node_name, straight_name, inner_name, outer_name, pike_name, update_chance, factors, color_convert)
-- Defensive checks
if not minetest.registered_nodes[base_node_name] then
if not base_node_name then
@ -392,7 +418,8 @@ function naturalslopeslib.set_slopes(base_node_name, straight_name, inner_name,
local chance_factors = default_factors(factors)
-- Set shape update data
local slope_names = {straight_name, inner_name, outer_name, pike_name}
add_replacement(base_node_name, update_chance, chance_factors, slope_names)
local colored = minetest.registered_nodes[base_node_name].paramtype2 == "color"
add_replacement(base_node_name, update_chance, chance_factors, slope_names, colored, color_convert)
-- Set surface update
if naturalslopeslib.setting_enable_surface_update() then
local time_factor = naturalslopeslib.setting_time_factor()

126
update_shape.lua

@ -6,18 +6,60 @@ Describes the falling/eroding effect for slopes
Pick replacement, node and area
--]]
--- {Private} Pick a replacement node and set it at pos.
-- Manage color for param2
-- @param replacement the replacement table
-- @param source the name or id of the node being transformed
-- @param dest the name or id of the new shape
-- @param param2_source the param2 value before transformation
-- @param param2_dest the param2 value for facedir (if any) after transformation
-- @return a new param2 value for dest node with color if necessary
local function manage_param2_color(replacement, source, dest, param2_source, param2_dest)
if not replacement._colored_source then
return param2_dest
end
if dest == replacement.source then
-- param2_source will hold a 'color' value
if source == replacement.source then
-- from 'color' to 'color'
return param2_source
else
-- from 'color' to 'colorfacedir'
local new_color_index = replacement._color_convert(param2_source, true) % 8
return param2_dest + (new_color_index * 32)
end
else
-- param2_source will hold a 'colorfacedir' value
if dest == replacement.source then
-- from 'colorfacedir' to 'color'
local old_color = math.floor(param2_source / 32)
return replacement._color_convert(old_color, false) % 256
else
-- from 'colorfacedir' to an other 'colorfacedir'
local color = math.floor(param2_source / 32)
return param2_dest + (color * 32)
end
end
end
--- {Private} Pick a replacement node.
-- @param type The replacement shape. Either 'block', 'straight', 'ic' or 'oc'
-- @param name The name of the node to replace.
-- @param pos The position of the node to replace
-- @param param2 Optional value to orient the new node.
-- @return True if the node is replaced, false otherwise.
local function pick_replacement(slope_type, name, pos, param2)
local replacement = naturalslopeslib.get_replacement(name)
-- @param name The name (or id for area) of the node to replace.
-- @param old_param2 The current value of param2 for the node to replace
-- @param param2 Facedir value to orient the new node.
-- @param for_area True when picking for an area, changes the parameter types
-- @return node {name=new_name, param2=new_param2} or area data {id=new_id, param2_data=new_param2}
-- or nil if dest node is not found.
local function pick_replacement(slope_type, name, old_param2, param2, for_area)
local replacement
if for_area then
replacement = naturalslopeslib.get_replacement_id(name)
else
replacement = naturalslopeslib.get_replacement(name)
end
if not replacement then return nil end
local dest_node_name = nil
if slope_type == 'block' and replacement.source then
return {name=replacement.source}
dest_node_name = replacement.source
elseif slope_type == 'pike' and replacement.pike then
dest_node_name = replacement.pike
elseif slope_type == 'straight' and replacement.straight then
@ -28,31 +70,13 @@ local function pick_replacement(slope_type, name, pos, param2)
dest_node_name = replacement.outer
end
if dest_node_name then
return {name = dest_node_name, paramtype2='facedir',
param2 = param2}
end
return nil
end
local function area_pick_replacement(slope_type, data, param2_data, id, index, param2)
local replacement = naturalslopeslib.get_replacement_id(id)
if not replacement then return false end
local dest_node_id = nil
local paramtype2 = nil
if slope_type == 'block' and replacement.source then
return {id = replacement.source}
elseif slope_type == 'pike' and replacement.pike then
dest_node_id = replacement.pike
elseif slope_type == 'straight' and replacement.straight then
dest_node_id = replacement.straight
elseif slope_type == 'ic' and replacement.inner then
dest_node_id = replacement.inner
elseif slope_type == 'oc' and replacement.outer then
dest_node_id = replacement.outer
end
if dest_node_id then
return {id = dest_node_id, paramtype2="facedir",
param2_data = param2}
if param2 == nil then param2 = 0 end
local color_param2 = manage_param2_color(replacement, name, dest_node_name, old_param2, param2)
if for_area then
return {id = dest_node_name, param2_data = color_param2}
else
return {name = dest_node_name, param2 = color_param2}
end
end
return nil
end
@ -98,7 +122,10 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
local new_pos = nil
local replacement = nil
local node_name = nil -- Either name or id
local for_area = false
local old_param2 = 0
if area then
for_area = true
is_free = function (at_index) -- always use with new_pos
return naturalslopeslib.area_is_free_for_shape_update(area, data, at_index)
end
@ -106,16 +133,13 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
local area_pos = area:position(pos)
return area:indexp(vector.add(area_pos, add))
end
replacement = function(slope_type, name, pos, pointing)
return area_pick_replacement(slope_type,
data, param2_data, name, pos, pointing)
end
node_name = node
old_param2 = param2_data[pos]
else
is_free = naturalslopeslib.is_free_for_shape_update
new_pos = function(add) return vector.add(pos, add) end
replacement = pick_replacement
node_name = node.name
old_param2 = node.param2
end
local is_ground -- ground or ceiling node
local pointing_y = -1
@ -132,7 +156,7 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
is_ground = false
pointing_y = 5
else -- nothing below and above
return replacement("block", node_name, pos)
return pick_replacement("block", node_name, old_param2, 0, for_area)
end
-- Check blocks around
local airXP = is_free(new_pos({x=1, y=0, z=0}))
@ -151,26 +175,26 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
if free_neighbors == 4 or free_neighbors == 3 then
local param2 = 0
if is_ground == false then param2 = 20 end
return replacement("pike", node_name, pos, param2)
return pick_replacement("pike", node_name, old_param2, param2, for_area)
-- For two free neighbors
elseif free_neighbors == 2 then
-- at opposite sides, block
local param2
if (airXP and airXM) or (airZP and airZM) then
return replacement('block', node_name, pos)
return pick_replacement('block', node_name, old_param2, 0, for_area)
-- side by side, outer corner
elseif (airXP and airZP) then
if is_ground then param2 = 3 else param2 = 22 end
return replacement("oc", node_name, pos, param2)
return pick_replacement("oc", node_name, old_param2, param2, for_area)
elseif (airXP and airZM) then
if is_ground then param2 = 0 else param2 = 21 end
return replacement("oc", node_name, pos, param2)
return pick_replacement("oc", node_name, old_param2, param2, for_area)
elseif (airXM and airZP) then
if is_ground then param2 = 2 else param2 = 23 end
return replacement("oc", node_name, pos, param2)
return pick_replacement("oc", node_name, old_param2, param2, for_area)
elseif (airXM and airZM) then
if is_ground then param2 = 1 else param2 = 20 end
return replacement("oc", node_name, pos, param2)
return pick_replacement("oc", node_name, old_param2, param2, for_area)
end
-- For one free neighbor, straight slope
elseif free_neighbors == 1 then
@ -180,7 +204,7 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
elseif airZP then if is_ground then param2 = 2 else param2 = 6 end
elseif airZM then if is_ground then param2 = 0 else param2 = 8 end
end
return replacement("straight", node_name, pos, param2)
return pick_replacement("straight", node_name, old_param2, param2, for_area)
-- For no free neighbor check for a free diagonal for an inner corner
-- or fully surrounded for a rebuild
else
@ -191,18 +215,18 @@ function naturalslopeslib.get_replacement_node(pos, node, area, data, param2_dat
local param2
if airXPZP and not airXPZM and not airXMZP and not airXMZM then
if is_ground then param2 = 3 else param2 = 15 end
return replacement("ic", node_name, pos, param2)
return pick_replacement("ic", node_name, old_param2, param2, for_area)
elseif not airXPZP and airXPZM and not airXMZP and not airXMZM then
if is_ground then param2 = 0 else param2 = 8 end
return replacement("ic", node_name, pos, param2)
return pick_replacement("ic", node_name, old_param2, param2, for_area)
elseif not airXPZP and not airXPZM and airXMZP and not airXMZM then
if is_ground then param2 = 2 else param2 = 23 end
return replacement("ic", node_name, pos, param2)
return pick_replacement("ic", node_name, old_param2, param2, for_area)
elseif not airXPZP and not airXPZM and not airXMZP and airXMZM then
if is_ground then param2 = 1 else param2 = 17 end
return replacement("ic", node_name, pos, param2)
return pick_replacement("ic", node_name, old_param2, param2, for_area)
else
return replacement('block', node_name, pos)
return pick_replacement('block', node_name, old_param2, 0, for_area)
end
end
end

Loading…
Cancel
Save