319 lines
9.5 KiB
Lua

local STAIR_BURNTIME_RATIO = 0.75
local SLAB_BURNTIME_RATIO = 0.5
local FALLBACK_BURNTIME = 7
--
-- Partial blocks API
--
local adv_slab_tex = function(tiles, tex_prefix, force_white)
local t1 = tiles[1]
local t2 = tex_prefix.."_slab.png"
if force_white then
t2 = { name = t2, color = "white" }
end
return { t1, t1, t2 }
end
local adv_stair_tex = function(tiles, tex_prefix, force_white)
local t1 = tiles[1]
local t2 = tex_prefix.."_stair.png"
local t3 = tex_prefix.."_slab.png"
local t4 = tex_prefix.."_stair.png^[transformFX"
if force_white then
t2 = { name = t2, color = "white" }
t3 = { name = t3, color = "white" }
t4 = { name = t4, color = "white" }
end
return { t3, t1, t4, t2, t1, t3 }
end
local parse_slab_tiles = function(tiles_slab_def, tiles_fallback)
local tiles
if tiles_slab_def then
-- Advanced slab tiles
if type(tiles_slab_def) == "string" and string.sub(tiles_slab_def, 1, 2) == "a|" then
local texpref = string.sub(tiles_slab_def, 3)
tiles = adv_slab_tex(tiles_fallback, texpref)
elseif type(tiles_slab_def) == "string" and string.sub(tiles_slab_def, 1, 2) == "A|" then
local texpref = string.sub(tiles_slab_def, 3)
tiles = adv_slab_tex(tiles_fallback, texpref, true)
else
-- Explicit slab tiles
tiles = tiles_slab_def
end
else
-- Slab tiles from base node
tiles = tiles_fallback
end
return tiles
end
local parse_stair_tiles = function(tiles_stair_def, tiles_fallback)
local tiles
if tiles_stair_def then
-- Advanced stair tiles
if type(tiles_stair_def) == "string" and string.sub(tiles_stair_def, 1, 2) == "a|" then
local texpref = string.sub(tiles_stair_def, 3)
tiles = adv_stair_tex(tiles_fallback, texpref)
elseif type(tiles_stair_def) == "string" and string.sub(tiles_stair_def, 1, 2) == "A|" then
local texpref = string.sub(tiles_stair_def, 3)
tiles = adv_stair_tex(tiles_fallback, texpref, true)
elseif tiles_stair_def == "w" then
-- World-aligned stair textures
if tiles_fallback then
local tex1 = tiles_fallback[1]
if type(tex1) == "string" then
tiles = {{ name = tex1, align_style = "world" }}
elseif type(tex1) == "table" then
tiles = { table.copy(tex1) }
tiles[1].align_style = "world"
else
minetest.log("error", "[rp_partialblocks] Failed to generate world-aligned stair texture!")
end
end
else
-- Explicit stair tiles
tiles = tiles_stair_def
end
else
-- Stair tiles from base node
tiles = tiles_fallback
end
return tiles
end
function partialblocks.register_material(name, desc_slab, desc_stair, node, groups, is_fuel, tiles_slab, tiles_stair, overlay_tiles_slab, overlay_tiles_stair, register_crafts)
local nodedef = minetest.registered_nodes[node]
if register_crafts == nil then
register_crafts = true
end
if nodedef == nil then
minetest.log("warning", "[rp_partialblocks] Cannot find node for partialblock: " .. node)
return
end
-- Slab
local tiles = parse_slab_tiles(tiles_slab, nodedef.tiles)
local overlay_tiles = parse_slab_tiles(overlay_tiles_slab, nodedef.overlay_tiles)
local groups_slab
if not groups then
groups_slab = table.copy(nodedef.groups)
if groups_slab.level then
groups_slab.level = math.max(-32737, groups_slab.level - 1)
else
groups_slab.level = -1
end
else
groups_slab = table.copy(groups)
if not groups_slab.level then
groups_slab.level = -1
end
end
groups_slab.slab = 1
local paramtype2_slab = "none"
local paramtype2_stair = "4dir"
local palette_slab, palette_stair
local drop_slab, drop_stair
if nodedef.groups and nodedef.groups.paintable then
if nodedef.groups.paintable == 1 then
paramtype2_slab = "color"
paramtype2_stair = "color4dir"
palette_slab = "rp_paint_palette_256.png"
palette_stair = "rp_paint_palette_64.png"
end
drop_slab = "rp_partialblocks:slab_" .. name
drop_stair = "rp_partialblocks:stair_" .. name
if string.sub(name, -8, -1) == "_painted" then
drop_slab = string.sub(drop_slab, 1, -9)
drop_stair = string.sub(drop_stair, 1, -9)
end
end
minetest.register_node(
"rp_partialblocks:slab_" .. name,
{
tiles = tiles,
overlay_tiles = overlay_tiles,
groups = groups_slab,
sounds = nodedef.sounds,
description = desc_slab,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
},
paramtype = "light",
paramtype2 = paramtype2_slab,
use_texture_alpha = nodedef.use_texture_alpha,
palette = palette_slab,
is_ground_content = nodedef.is_ground_content,
drop = drop_slab,
on_place = function(itemstack, placer, pointed_thing)
-- Slab on slab placement creates full block
if not (pointed_thing.above.y > pointed_thing.under.y) then
itemstack = minetest.item_place(itemstack, placer, pointed_thing)
return itemstack
end
local pos = pointed_thing.under
local shift = false
if placer:is_player() then
-- Place node normally when sneak is pressed
shift = placer:get_player_control().sneak
end
-- If stacking paintable stacks, check for matching color
local old_node = minetest.get_node(pos)
local paint_match = true
if minetest.get_item_group(old_node.name, "paintable") == 1 then
local old_node_paint_index = old_node.param2
local imeta = itemstack:get_meta()
local item_paint_index = imeta:get_int("palette_index") or 0
paint_match = old_node_paint_index == item_paint_index
end
-- Create full block if both slabs are compatible
-- and not sneaking
if (not shift) and old_node.name == itemstack:get_name()
and itemstack:get_count() >= 1 and paint_match then
minetest.swap_node(pos, {name = node, param2 = old_node.param2})
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
else
itemstack = minetest.item_place(itemstack, placer, pointed_thing)
end
return itemstack
end,
})
if register_crafts then
crafting.register_craft({ -- 1 block --> 2 slabs
output = "rp_partialblocks:slab_" .. name .. " 2",
items = {
node,
},
})
crafting.register_craft({ -- 2 slabs --> 1 block
output = node,
items = {
"rp_partialblocks:slab_" .. name .. " 2",
},
})
end
local full_node_burntime
local output = minetest.get_craft_result({
method = "fuel",
width = 1,
items = {node},
})
full_node_burntime = output.time
if is_fuel then
local burntime
if full_node_burntime > 0 then
-- Burntime is based on the origin node (if a fuel recipe was available)
burntime = math.max(1, math.floor(full_node_burntime * SLAB_BURNTIME_RATIO))
else
-- Fallback burntime
burntime = FALLBACK_BURNTIME
end
minetest.register_craft({ -- Fuel
type = "fuel",
recipe = "rp_partialblocks:slab_" .. name,
burntime = burntime,
})
end
-- Stair
tiles = parse_stair_tiles(tiles_stair, nodedef.tiles)
overlay_tiles = parse_stair_tiles(overlay_tiles_stair, nodedef.overlay_tiles)
local groups_stair
if not groups then
groups_stair = table.copy(nodedef.groups)
if groups_stair.level then
groups_stair.level = math.max(-32737, groups_stair.level - 1)
else
groups_stair.level = -1
end
else
groups_stair = table.copy(groups)
if not groups_stair.level then
groups_stair.level = -1
end
end
groups_stair.stair = 1
minetest.register_node(
"rp_partialblocks:stair_" .. name,
{
tiles = tiles,
overlay_tiles = overlay_tiles,
groups = groups_stair,
sounds = nodedef.sounds,
description = desc_stair,
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
paramtype = "light",
paramtype2 = paramtype2_stair,
palette = palette_stair,
use_texture_alpha = nodedef.use_texture_alpha,
is_ground_content = nodedef.is_ground_content,
drop = drop_stair,
})
if register_crafts then
crafting.register_craft({ -- 3 blocks --> 4 stairs
output = "rp_partialblocks:stair_" .. name .. " 4",
items = {
node .. " 3",
},
})
crafting.register_craft({ -- 2 stairs --> 3 slabs
output = "rp_partialblocks:slab_" .. name .. " 3",
items = {
"rp_partialblocks:stair_" .. name .. " 2",
},
})
end
if is_fuel then
local burntime
if full_node_burntime > 0 then
-- Burntime is based on the origin node (if a fuel recipe was available)
burntime = math.max(1, math.floor(full_node_burntime * STAIR_BURNTIME_RATIO))
else
-- Fallback burntime
burntime = FALLBACK_BURNTIME
end
minetest.register_craft({ -- Fuel
type = "fuel",
recipe = "rp_partialblocks:stair_" .. name,
burntime = burntime,
})
end
end