--[[ Raw Ore Blocks — adds block forms of metal lumps to Luanti Copyright © 2022-2026, Silver Sandstone <@SilverSandstone@craftodon.social> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ]] --- Public API functions. -- @module api local S = core.get_translator('lumpblocks'); local get_sounds; if core.get_modpath('default') then get_sounds = default.node_sound_metal_defaults or default.node_sound_stone_defaults; elseif core.get_modpath('mcl_sounds') then get_sounds = mcl_sounds.node_sounds_metal_defaults; elseif core.get_modpath('rp_sounds') then get_sounds = rp_sounds.node_sound_defaults; end; if not get_sounds then function get_sounds(sounds) return sounds or {}; end; end; local function update(dest, ...) for index = 1, select('#', ...) do local src = select(index, ...); if src then for key, value in pairs(src) do dest[key] = value; end; end; end; return dest; end; --- Registers a raw ore block. -- @param name [string] The name of the raw ore block to register. -- @param options [table] A table of options. -- @param options.lump [string] The name of the lump item. -- @param options.texture [string] Overrides the node's texture. -- @param options.light_colour [ColourSpec] The lighter colour of the texture. -- @param options.dark_colour [ColourSpec] The darker (or only) colour of the texture. -- @param options.colour [ColourSpec] Alias for `dark_colour`. -- @param options.colours [ColourSpec[2]] A table of {dark_colour, light_colour}. -- @param options.description [string] Overrides the node's description. -- @param options.groups [{string: integer}] Overrides the node's groups. -- @param options.def [NodeDef] Overrides arbitrary properties of the node's definition. -- @return [string|nil] The name of the registered node, or nil on failure. function lumpblocks.register_lump_block(name, options) if type(name) == 'table' then options = name; name = nil; end; local lump_name; local texture; local dark_colour; local light_colour; local description; local override; local groups = {}; for key, value in pairs(options) do if key == 'base_name' or key == 1 then name = ('lumpblocks:%s_block'):format(value); elseif key == 'lump' or key == 2 then lump_name = value; elseif key == 'name' then name = value; elseif key == 'texture' then texture = value; elseif key == 'dark_colour' or key == 'colour' then dark_colour = value; elseif key == 'light_colour' then light_colour = value; elseif key == 'colours' then dark_colour, light_colour = unpack(value); elseif key == 'description' then description = value; elseif key == 'def' then override = value; elseif key == 'groups' then groups = value; else core.log('error', ('Invalid key [%q] in lumpblocks.register_lump_block().'):format(key)); end; end; assert(name, 'No block name specified!'); assert(lump_name, 'No lump name specified!'); assert(texture or dark_colour, 'No texture or colour specified!'); local lump_def = core.registered_items[lump_name]; if not lump_def then return nil; end; local def = {}; def.description = description or S('@1 Block', lump_def.description); def.groups = update({cracky = 3, lump_block = 1}, groups); def.tiles = {texture or lumpblocks.generate_lumpblock_texture(dark_colour, light_colour)}; def.sounds = update(get_sounds(), options.sounds); def._doc_items_longdesc = S('A compressed block form of @1 for decoration or efficient storage.', lump_def.description); update(def, override); core.register_node(':' .. name, def); -- Crafting recipes: core.register_craft( { output = name; recipe = { {lump_name, lump_name, lump_name}, {lump_name, lump_name, lump_name}, {lump_name, lump_name, lump_name}, }; }); core.register_craft( { type = 'shapeless'; output = lump_name .. ' 9'; recipe = {name}; }); if core.get_modpath('rp_crafting') then crafting.register_craft( { output = name; items = {lump_name .. ' 9'}; }); crafting.register_craft( { output = lump_name .. ' 9'; items = {name}; }); end; return name; end; -- Generates a raw ore block texture in the specified colours. -- @param dark_colour [ColourSpec] The darker (or only) colour. -- @param light_colour [ColourSpec|nil] The lighter colour. -- @return [string] A texture string. function lumpblocks.generate_lumpblock_texture(dark_colour, light_colour) assert(dark_colour, 'No colour specified!'); if light_colour then -- Gradient-based colouring system: dark_colour = core.colorspec_to_colorstring(dark_colour); light_colour = core.colorspec_to_colorstring(light_colour); local mask = 'lumpblocks_lump_block_mask.png'; return ('(%s^[multiply:#00000000^[invert:a^[colorize:%s:255)^(%s^[multiply:%s)'):format(mask, dark_colour, mask, light_colour); else -- Multiplication-based colouring system: local colour = core.colorspec_to_colorstring(dark_colour); local inverted = lumpblocks.invert_colour(colour); local base = 'lumpblocks_lump_block.png'; return ('((%s^[invert:rgb)^[multiply:%s^[invert:rgb)^(%s^[multiply:%s^[opacity:127)'):format(base, inverted, base, colour); end; end; --- Inverts a colour in RGB space. -- @param colour [ColourSpec] The colour to invert. -- @return [ColourString] The inverted colour. function lumpblocks.invert_colour(colour) local bytes = core.colorspec_to_bytes(colour); local values = {nil, nil, nil, bytes:byte(4)}; for index = 1, 3 do values[index] = 255 - bytes:byte(index); end; return ('#%02X%02X%02X%02X'):format(unpack(values)); end;