--- --- Generated by EmmyLua. --- Created by Michieal (FaerRaven). --- DateTime: 10/14/22 4:05 PM --- --local logging = minetest.settings:get_bool("mcl_logging_mcl_signs",true) local DEBUG = minetest.settings:get_bool("mcl_logging_mcl_signs", false) -- special debug setting. if DEBUG then minetest.log("action", "[mcl_signs] Signs API Loading") end -- LOCALIZATION local S = minetest.get_translator("mcl_signs") -- Signs form local F = minetest.formspec_escape -- PATHs local modpath = minetest.get_modpath("mcl_signs") -- CONSTANTS local SIGN_WIDTH = 115 local LINE_LENGTH = 15 local NUMBER_OF_LINES = 4 local LINE_HEIGHT = 14 local CHAR_WIDTH = 5 local TIMER_INTERVAL = 40.0 -- ----------------------- -- CACHE LOCAL COPIES local table = table local string = string -- CACHE NODE_SOUNDS local node_sounds if minetest.get_modpath("mcl_sounds") then node_sounds = mcl_sounds.node_sound_wood_defaults() end -- SET UP THE CHARACTER MAPPING -- Load the characters map (characters.txt) --[[ File format of characters.txt: It's an UTF-8 encoded text file that contains metadata for all supported characters. It contains a sequence of info blocks, one for each character. Each info block is made out of 3 lines: Line 1: The literal UTF-8 encoded character Line 2: Name of the texture file for this character minus the “.png” suffix; found in the “textures/” sub-directory Line 3: Currently ignored. Previously this was for the character width in pixels After line 3, another info block may follow. This repeats until the end of the file. All character files must be 5 or 6 pixels wide (5 pixels are preferred) ]] local chars_file = io.open(modpath .. "/characters.txt", "r") -- FIXME: Support more characters (many characters are missing). Currently ASCII and Latin-1 Supplement are supported. local charmap = {} if not chars_file then minetest.log("error", "[mcl_signs] : character map file not found") else while true do local char = chars_file:read("*l") if char == nil then break end local img = chars_file:read("*l") chars_file:read("*l") charmap[char] = img end end local pi = 3.1415926 -- enough accuracy, to build an engine for a car. local math = math -- locally cached copy of the official colors; this way, it updates as mcl_colors updates. local mcl_colors_official = mcl_colors if DEBUG then minetest.log("verbose", "[mcl_signs]Official MCL_Colors:\n" .. dump(mcl_colors_official)) end -- INITIALIZE THE GLOBAL API FOR SIGNS. mcl_signs = {} -- GLOBALS mcl_signs.sign_groups = { handy = 1, axey = 1, deco_block = 1, material_wood = 1, attached_node = 1, flammable = -1 } --- colors used for wools. mcl_signs.mcl_wool_colors = { unicolor_white = "#FFFFFF", unicolor_dark_orange = "#502A00", unicolor_grey = "#5B5B5B", unicolor_darkgrey = "#303030", unicolor_blue = "#0000CC", unicolor_dark_green = "#005000", unicolor_green_or_lime = "#50CC00", unicolor_violet_purple = "#5000CC", unicolor_light_red_pink = "#FF5050", unicolor_yellow = "#CCCC00", unicolor_orange = "#CC5000", unicolor_red = "#CC0000", unicolor_cyan = "#00CCCC", unicolor_red_violet_magenta = "#CC0050", unicolor_black = "#000000", unicolor_light_blue = "#5050FF", } mcl_signs.signtext_info_wall = {} mcl_signs.signtext_info_standing = {} -- built in build_signs_info(). -- the rotational levels for all of the standing signs. mcl_signs.standing_rotation_levels = {} -- data structure block for dynamically registered signs. mcl_signs.registered_signs = {} mcl_signs.registered_signs.wall_signs = {} mcl_signs.registered_signs.standing_signs = {} mcl_signs.registered_signs.hanging_signs = {} -- unused. prepping for future use. -- DEFINE SIGN BASE TYPES mcl_signs.wall_standard = {} -- initialize mcl_signs.standing_standard = {} -- initialize function mcl_signs.build_signs_info() local n = 23 / 56 - 1 / 128 -- some required magic number from the original code. local m = -1 / 16 + 1 / 64 -- " " " " " " " " mcl_signs.signtext_info_wall = { { delta = { x = 0, y = 0, z = n }, yaw = 0 }, { delta = { x = n, y = 0, z = 0 }, yaw = pi / -2 }, { delta = { x = 0, y = 0, z = -n }, yaw = pi }, { delta = { x = -n, y = 0, z = 0 }, yaw = pi / 2 }, } -- PLACE YAW VALUES INTO THE TABLE. for rot = 0, 15 do local yaw = pi * 2 - (((pi * 2) / 16) * rot) local delta = vector.multiply(minetest.yaw_to_dir(yaw), m) -- Offset because sign is a bit above node boundaries delta.y = delta.y + 2 / 28 table.insert(mcl_signs.signtext_info_standing, { delta = delta, yaw = yaw }) end end -- wall signs' & hanging signs' base (definition) mcl_signs.wall_standard = { description = S("Sign"), _tt_help = S("Can be written"), _doc_items_longdesc = S("Signs can be written and come in two variants: Wall sign and sign on a sign post. Signs can be placed on the top and the sides of other blocks, but not below them."), _doc_items_usagehelp = S("After placing the sign, you can write something on it. You have 4 lines of text with up to 15 characters for each line; anything beyond these limits is lost. Not all characters are supported. The text can not be changed once it has been written; you have to break and place the sign again. Can be colored and made to glow."), inventory_image = "mcl_signs_default_sign.png", walkable = false, is_ground_content = false, wield_image = "mcl_signs_default_sign.png", node_placement_prediction = "", paramtype = "light", sunlight_propagates = true, paramtype2 = "wallmounted", drawtype = "mesh", mesh = "mcl_signs_signonwallmount.obj", selection_box = { type = "wallmounted", wall_side = { -0.5, -7 / 28, -0.5, -23 / 56, 7 / 28, 0.5 } }, tiles = { "mcl_signs_sign.png" }, use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, groups = mcl_signs.sign_groups, stack_max = 16, sounds = node_sounds, on_timer = function(pos) -- fix for /ClearObjects mcl_signs:update_sign(pos) -- note: update_sign decides to keep the timer running based on if there is text. -- This prevents every sign from having a timer, when not needed. end, on_place = function(itemstack, placer, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under -- Use pointed node's on_rightclick function first, if present local node_under = minetest.get_node(under) if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack end end local dir = vector.subtract(under, above) -- Only build when it's legal local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] if not abovenodedef or abovenodedef.buildable_to == false then return itemstack end local wdir = minetest.dir_to_wallmounted(dir) --local placer_pos = placer:get_pos() local fdir = minetest.dir_to_facedir(dir) local sign_info local nodeitem = ItemStack(itemstack) -- Ceiling if wdir == 0 then --how would you add sign to ceiling? return itemstack -- Floor end if wdir == 1 then -- Standing sign -- Determine the sign rotation based on player's yaw local yaw = pi * 2 - placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) if rotation_level > 15 then rotation_level = 0 elseif rotation_level < 0 then rotation_level = 15 end -- The actual rotation is a combination of predefined mesh and facedir (see node definition) if rotation_level % 4 == 0 then nodeitem:set_name("mcl_signs:standing_sign") elseif rotation_level % 4 == 1 then nodeitem:set_name("mcl_signs:standing_sign22_5") elseif rotation_level % 4 == 2 then nodeitem:set_name("mcl_signs:standing_sign45") elseif rotation_level % 4 == 3 then nodeitem:set_name("mcl_signs:standing_sign67_5") end fdir = math.floor(rotation_level / 4) -- Place the node! local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) if not success then return itemstack end if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] -- Side else -- Wall sign local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) if not success then return itemstack end sign_info = mcl_signs.signtext_info_wall[fdir + 1] end -- Determine spawn position of entity local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end local text_entity = minetest.add_entity({ x = place_pos.x + sign_info.delta.x, y = place_pos.y + sign_info.delta.y, z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") text_entity:set_yaw(sign_info.yaw) text_entity:get_luaentity()._signnodename = nodeitem:get_name() if DEBUG then minetest.log("verbose", "[mcl_signs]Placed position:" .. dump(place_pos) .. "\nSign_info: " .. dump(sign_info)) end minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) mcl_signs:show_formspec(placer, place_pos) return itemstack end, on_destruct = function(pos) mcl_signs:destruct_sign(pos) end, -- Not Useless Code. force updates the sign. on_punch = function(pos, node, puncher) mcl_signs:update_sign(pos) end, on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then local r = screwdriver.rotate.wallmounted(pos, node, mode) node.param2 = r minetest.swap_node(pos, node) mcl_signs:update_sign(pos, nil, nil, true) return true else return false end end, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) if DEBUG then minetest.log("verbose", "[mcl_signs] Wall_Sign Right Click event.") end -- make sure player is clicking if not clicker or not clicker:is_player() then return end local item = clicker:get_wielded_item() local iname = item:get_name() local protected = mcl_util.check_position_protection(pos, clicker) if node and not protected then if DEBUG then minetest.log("verbose", "[mcl_signs] Wall_Sign Right Click event on valid node.") end -- handle glow from glow_ink_sac *first* if (iname == "mcl_mobitems:glow_ink_sac") then clicker:set_wielded_item(item) local success = mcl_signs:glow_sign(pos) if success then if DEBUG then minetest.log("verbose", "[mcl_signs] Sign Glow Success.") end itemstack:take_item() end return end -- "mcl_dye:black" is a special case: it makes the sign's lettering black AND removes glow. if (iname == "mcl_dye:black") then clicker:set_wielded_item(item) local success = mcl_signs:glow_sign(pos, true) mcl_signs:color_sign(pos, mcl_colors.BLACK) if success then if DEBUG then minetest.log("verbose", "[mcl_signs] Sign Glow removal Success.") end itemstack:take_item() end return end -- check the wielded item to make sure that it is a dye. local txt_color = mcl_signs:get_color_for_sign(iname) if txt_color ~= "false" then clicker:set_wielded_item(item) local success = mcl_signs:color_sign(pos, txt_color) if success then if DEBUG then minetest.log("verbose", "[mcl_signs] Sign Color Success.") end itemstack:take_item() end end end end, _mcl_hardness = 1, _mcl_blast_resistance = 1, } -- standing sign base (definition) mcl_signs.standing_standard = { paramtype = "light", use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "opaque" or false, sunlight_propagates = true, walkable = false, is_ground_content = false, paramtype2 = "facedir", drawtype = "mesh", mesh = "mcl_signs_sign.obj", selection_box = { type = "fixed", fixed = { -0.2, -0.5, -0.2, 0.2, 0.5, 0.2 } }, tiles = { "mcl_signs_sign.png" }, groups = mcl_signs.sign_groups, drop = "mcl_signs:wall_sign", stack_max = 16, sounds = node_sounds, on_destruct = function(pos) mcl_signs:destruct_sign(pos) end, on_timer = function(pos) -- fix for /ClearObjects mcl_signs:update_sign(pos) minetest.get_node_timer(pos):start(40.0) end, -- Not Useless Code. this force updates the sign. on_punch = function(pos, node, puncher) mcl_signs:update_sign(pos) end, on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign22_5" minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end, on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) if DEBUG then minetest.log("verbose", "[mcl_signs] Standing_Sign Right Click event.") end -- make sure player is clicking if not clicker or not clicker:is_player() then return end local item = clicker:get_wielded_item() local iname = item:get_name() local protected = mcl_util.check_position_protection(pos, clicker) if node and not protected then -- handle glow from glow_ink_sac *first* if DEBUG then minetest.log("verbose", "[mcl_signs] Standing_Sign Right Click event on valid node.") end if (iname == "mcl_mobitems:glow_ink_sac") then clicker:set_wielded_item(item) local success = mcl_signs:glow_sign(pos) if success then if DEBUG then minetest.log("verbose", "[mcl_signs] Sign Glow Success.") end itemstack:take_item() end return end -- check the wielded item to make sure that it is a dye. local txt_color = mcl_signs:get_color_for_sign(iname) if txt_color ~= "false" then clicker:set_wielded_item(item) local success = mcl_signs:color_sign(pos, txt_color) if success then if DEBUG then minetest.log("verbose", "[mcl_signs] Sign Color Success.") end itemstack:take_item() end end end end, _mcl_hardness = 1, _mcl_blast_resistance = 1, } -- HELPER FUNCTIONS' VARIABLES local sign_glow = 6 local Dyes_table = { { "mcl_dye:aqua", mcl_colors_official.AQUA }, { "mcl_dye:black", mcl_colors_official.BLACK }, { "mcl_dye:blue", mcl_colors_official.BLUE }, { "mcl_dye:brown", mcl_colors_official.brown }, { "mcl_dye:cyan", mcl_signs.mcl_wool_colors.unicolor_cyan }, { "mcl_dye:green", mcl_colors_official.GREEN }, { "mcl_dye:dark_green", mcl_colors_official.DARK_GREEN }, { "mcl_dye:grey", mcl_colors_official.GRAY }, { "mcl_dye:dark_grey", mcl_colors_official.DARK_GRAY }, { "mcl_dye:lightblue", mcl_signs.mcl_wool_colors.unicolor_light_blue }, { "mcl_dye:lime", mcl_signs.unicolor_green_or_lime }, { "mcl_dye:magenta", mcl_colors_official.LIGHT_PURPLE }, { "mcl_dye:orange", mcl_signs.mcl_wool_colors.unicolor_orange }, { "mcl_dye:pink", mcl_signs.mcl_wool_colors.unicolor_light_red_pink }, { "mcl_dye:purple", mcl_colors_official.LIGHT_PURPLE }, { "mcl_dye:red", mcl_signs.mcl_wool_colors.unicolor_red }, { "mcl_dye:silver", mcl_signs.mcl_wool_colors.unicolor_grey }, { "mcl_dye:violet", mcl_colors_official.DARK_PURPLE }, { "mcl_dye:white", mcl_colors_official.WHITE }, { "mcl_dye:yellow", mcl_colors_official.YELLOW }, } local function update_sign_registry(type, name) if type == "wall" then table.insert(mcl_signs.registered_signs.wall_signs, name) end if type == "standing" then table.insert(mcl_signs.registered_signs.standing_signs, name) end if type == "hanging" then table.insert(mcl_signs.registered_signs.hanging_signs, name) end end function mcl_signs.make_lbm() local registered_sign_nodenames = {} for i = 0, #mcl_signs.registered_signs.wall_signs do table.insert(registered_sign_nodenames, mcl_signs.registered_signs.wall_signs[i]) end for i = 0, #mcl_signs.registered_signs.standing_signs do table.insert(registered_sign_nodenames, mcl_signs.registered_signs.standing_signs[i]) end for i = 0, #mcl_signs.registered_signs.hanging_signs do table.insert(registered_sign_nodenames, mcl_signs.registered_signs.hanging_signs[i]) end -- the above is not yet used. minetest.register_lbm({ name = "mcl_signs:respawn_entities", label = "Respawn sign text entities", run_at_every_load = true, nodenames = registered_sign_nodenames, action = function(pos, node) mcl_signs:update_sign(pos) end, }) end function mcl_signs.register_dye (modname, item_name, color_code) if minetest.get_modpath(modname) then table.insert(Dyes_table, { item_name, color_code }) end end --- Register a new sign, tint the textures, and gives it an unique node name. Creates both wall and standing signs. --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). --- --- color: the color code to color the base sign textures. must be a valid html color code. --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" --- --- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. --- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" function mcl_signs.register_sign (modname, color, _name, ttsign) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end local new_sign = {} if color == nil or color == "" then color = "#FFFFFF" end new_sign = table.copy(mcl_signs.wall_standard) new_sign.description = ttsign new_sign.wield_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } new_sign.inventory_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" -- currently have to do this, because of how the base node placement works. new_sign.on_place = function(itemstack, placer, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under -- Use pointed node's on_rightclick function first, if present local node_under = minetest.get_node(under) if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack end end local dir = vector.subtract(under, above) -- Only build when it's legal local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] if not abovenodedef or abovenodedef.buildable_to == false then return itemstack end local wdir = minetest.dir_to_wallmounted(dir) local fdir = minetest.dir_to_facedir(dir) local sign_info local nodeitem = ItemStack(itemstack) local yaw = 0 -- Ceiling if wdir == 0 then --how would you add sign to ceiling? simple - hanging sign. -- add code for placement underneath a node. return itemstack -- Floor elseif wdir == 1 then -- Standing sign -- Determine the sign rotation based on player's yaw yaw = pi * 2 - placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) if rotation_level > 15 then rotation_level = 0 elseif rotation_level < 0 then rotation_level = 15 end -- The actual rotation is a combination of predefined mesh and facedir (see node definition) if rotation_level % 4 == 0 then nodeitem:set_name("mcl_signs:standing_sign" .. _name) elseif rotation_level % 4 == 1 then nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) elseif rotation_level % 4 == 2 then nodeitem:set_name("mcl_signs:standing_sign45" .. _name) elseif rotation_level % 4 == 3 then nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) end fdir = math.floor(rotation_level / 4) -- Place the node! local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) if not success then return itemstack end if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] -- Side else -- Wall sign local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) if not success then return itemstack end sign_info = mcl_signs.signtext_info_wall[fdir + 1] end -- Determine spawn position of entity local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end if DEBUG then minetest.log("action", "[mcl_signs] Register_Sign::Placed position:" .. dump(place_pos) .. "\nSign_info: " .. dump(sign_info)) end local text_entity = minetest.add_entity({ x = place_pos.x + sign_info.delta.x, y = place_pos.y + sign_info.delta.y, z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") text_entity:set_yaw(sign_info.yaw) text_entity:get_luaentity()._signnodename = nodeitem:get_name() minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) mcl_signs:show_formspec(placer, place_pos) return itemstack end minetest.register_node(":mcl_signs:wall_sign" .. _name, new_sign) update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Registered: mcl_signs:wall_sign" .. _name .. color .. "\n" .. dump(new_sign)) minetest.log("action", "[mcl_signs] mcl_signs:wall_sign_standard\n" .. dump(mcl_signs.wall_standard)) end -- standing sign base. local new_sign_standing = {} new_sign_standing = table.copy(mcl_signs.standing_standard) new_sign_standing.drop = "mcl_signs:wall_sign" .. _name new_sign_standing.wield_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign_standing.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } new_sign_standing.inventory_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign_standing.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign22_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end, minetest.register_node(":mcl_signs:standing_sign" .. _name, new_sign_standing) update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Registered: mcl_signs:standing_sign" .. _name .. color .. "\n" .. dump(new_sign_standing)) end -- 22.5° local ssign22_5d = table.copy(new_sign_standing) ssign22_5d.mesh = "mcl_signs_sign22.5.obj" ssign22_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign45" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign22_5" .. _name, ssign22_5d) update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) -- 45° local ssign45d = table.copy(new_sign_standing) ssign45d.mesh = "mcl_signs_sign45.obj" ssign45d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign67_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign45" .. _name, ssign45d) update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) -- 67.5° local ssign67_5d = table.copy(new_sign_standing) ssign67_5d.mesh = "mcl_signs_sign67.5.obj" ssign67_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign" .. _name node.param2 = (node.param2 + 1) % 4 minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign67_5" .. _name, ssign67_5d) update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) -- register Doc entry if minetest.get_modpath("doc") then doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) end --register standing sign's rotation_levels table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign22_5" .. _name, 1 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign45" .. _name, 2 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign67_5" .. _name, 3 }) -- register as unpushable if minetest.get_modpath("mesecons_mvps") then mesecon.register_mvps_stopper("mcl_signs:wall_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign22_5" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign45" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign67_5" .. _name) end end --- The same as register_sign, except caller defines the textures. Note, there is a greyscale version of the sign, --- called "mcl_signs_default_sign_greyscale.png" and "mcl_signs_sign_greyscale.png" for optional use in the textures directory. --- --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" --- --- tiles: the texture file to use for the sign. --- --- color: color the texture file to use with this color. Use white (#FFFFFF) to negate the color, --- and just use the texture as is --- --- inventory_image: the texture file to use for the sign's display in inventory. --- --- wield_image: the texture file to use for the sign's weilded (in hand) object. --- --- inventory_image: the image used for in-inventory and in hand. --- --- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. --- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" function mcl_signs.register_sign_custom (modname, _name, tiles, color, inventory_image, wield_image, ttsign) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end local new_sign = {} new_sign = table.copy(mcl_signs.wall_standard) if not color or color == nil then new_sign.wield_image = wield_image new_sign.tiles = { tiles } new_sign.inventory_image = inventory_image else new_sign.wield_image = "(" .. wield_image .. "^[multiply:" .. color .. ")" new_sign.tiles = { "(" .. tiles .. "^[multiply:" .. color .. ")" } new_sign.inventory_image = "(" .. inventory_image .. "^[multiply:" .. color .. ")" end new_sign.description = ttsign -- currently have to do this, because of how the base node placement works. new_sign.on_place = function(itemstack, placer, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under -- Use pointed node's on_rightclick function first, if present local node_under = minetest.get_node(under) if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack end end local dir = vector.subtract(under, above) -- Only build when it's legal local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] if not abovenodedef or abovenodedef.buildable_to == false then return itemstack end local wdir = minetest.dir_to_wallmounted(dir) local fdir = minetest.dir_to_facedir(dir) local sign_info local nodeitem = ItemStack(itemstack) -- Ceiling if wdir == 0 then --how would you add sign to ceiling? return itemstack -- Floor elseif wdir == 1 then -- Standing sign -- Determine the sign rotation based on player's yaw local yaw = pi * 2 - placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) if rotation_level > 15 then rotation_level = 0 elseif rotation_level < 0 then rotation_level = 15 end -- The actual rotation is a combination of predefined mesh and facedir (see node definition) if rotation_level % 4 == 0 then nodeitem:set_name("mcl_signs:standing_sign" .. _name) elseif rotation_level % 4 == 1 then nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) elseif rotation_level % 4 == 2 then nodeitem:set_name("mcl_signs:standing_sign45" .. _name) elseif rotation_level % 4 == 3 then nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) end fdir = math.floor(rotation_level / 4) -- Place the node! local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) if not success then return itemstack end if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] -- Side else -- Wall sign local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) if not success then return itemstack end sign_info = mcl_signs.signtext_info_wall[fdir + 1] end -- Determine spawn position of entity local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end local text_entity = minetest.add_entity({ x = place_pos.x + sign_info.delta.x, y = place_pos.y + sign_info.delta.y, z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") text_entity:set_yaw(sign_info.yaw) text_entity:get_luaentity()._signnodename = nodeitem:get_name() minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) mcl_signs:show_formspec(placer, place_pos) return itemstack end minetest.register_node(":mcl_signs:wall_sign" .. _name, new_sign) update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) -- standing sign base. local new_sign_standing = {} new_sign_standing = table.copy(mcl_signs.standing_standard) new_sign_standing.drop = "mcl_signs:wall_sign" .. _name if not color or color == nil then new_sign_standing.wield_image = wield_image new_sign_standing.tiles = { tiles } new_sign_standing.inventory_image = inventory_image else new_sign_standing.wield_image = "(" .. wield_image .. "^[multiply:" .. color .. ")" new_sign_standing.tiles = { "(" .. tiles .. "^[multiply:" .. color .. ")" } new_sign_standing.inventory_image = "(" .. inventory_image .. "^[multiply:" .. color .. ")" end new_sign_standing.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign22_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end, minetest.register_node(":mcl_signs:standing_sign" .. _name, new_sign_standing) update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) -- 22.5° local ssign22_5d = table.copy(new_sign_standing) ssign22_5d.mesh = "mcl_signs_sign22.5.obj" ssign22_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign45" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign22_5" .. _name, ssign22_5d) update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) -- 45° local ssign45d = table.copy(new_sign_standing) ssign45d.mesh = "mcl_signs_sign45.obj" ssign45d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign67_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign45" .. _name, ssign45d) update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) -- 67.5° local ssign67_5d = table.copy(new_sign_standing) ssign67_5d.mesh = "mcl_signs_sign67.5.obj" ssign67_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign" .. _name node.param2 = (node.param2 + 1) % 4 minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.register_node(":mcl_signs:standing_sign67_5" .. _name, ssign67_5d) update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) -- register Doc entry if minetest.get_modpath("doc") then doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) end --register standing sign's rotation_levels table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign22_5" .. _name, 1 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign45" .. _name, 2 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign67_5" .. _name, 3 }) -- register as unpushable if minetest.get_modpath("mesecons_mvps") then mesecon.register_mvps_stopper("mcl_signs:wall_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign22_5" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign45" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign67_5" .. _name) end end --- Override an existing sign, tint the textures, and gives it an unique node name. Creates both wall and standing signs. --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). --- --- color: the color code to color the base sign textures. must be a valid html color code. --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" --- --- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. --- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" function mcl_signs.reregister_sign (modname, color, _name, ttsign) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end local new_sign = {} if color == nil or color == "" then color = "#FFFFFF" end new_sign = table.copy(mcl_signs.wall_standard) new_sign.description = ttsign new_sign.wield_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } new_sign.inventory_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" -- currently have to do this, because of how the base node placement works. new_sign.on_place = function(itemstack, placer, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under -- Use pointed node's on_rightclick function first, if present local node_under = minetest.get_node(under) if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack end end local dir = vector.subtract(under, above) -- Only build when it's legal local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] if not abovenodedef or abovenodedef.buildable_to == false then return itemstack end local wdir = minetest.dir_to_wallmounted(dir) local fdir = minetest.dir_to_facedir(dir) local sign_info local nodeitem = ItemStack(itemstack) -- Ceiling if wdir == 0 then --how would you add sign to ceiling? return itemstack -- Floor elseif wdir == 1 then -- Standing sign -- Determine the sign rotation based on player's yaw local yaw = pi * 2 - placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) if rotation_level > 15 then rotation_level = 0 elseif rotation_level < 0 then rotation_level = 15 end -- The actual rotation is a combination of predefined mesh and facedir (see node definition) if rotation_level % 4 == 0 then nodeitem:set_name("mcl_signs:standing_sign" .. _name) elseif rotation_level % 4 == 1 then nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) elseif rotation_level % 4 == 2 then nodeitem:set_name("mcl_signs:standing_sign45" .. _name) elseif rotation_level % 4 == 3 then nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) end fdir = math.floor(rotation_level / 4) -- Place the node! local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) if not success then return itemstack end if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] -- Side else -- Wall sign local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) if not success then return itemstack end sign_info = mcl_signs.signtext_info_wall[fdir + 1] end -- Determine spawn position of entity local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end if DEBUG then minetest.log("action", "[mcl_signs] Register_Sign::Placed position:" .. dump(place_pos) .. "\nSign_info: " .. dump(sign_info)) end local text_entity = minetest.add_entity({ x = place_pos.x + sign_info.delta.x, y = place_pos.y + sign_info.delta.y, z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") text_entity:set_yaw(sign_info.yaw) text_entity:get_luaentity()._signnodename = nodeitem:get_name() minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) mcl_signs:show_formspec(placer, place_pos) return itemstack end minetest.override_item("mcl_signs:wall_sign" .. _name, new_sign) update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Registered: mcl_signs:wall_sign" .. _name .. color .. "\n" .. dump(new_sign)) minetest.log("action", "[mcl_signs] mcl_signs:wall_sign_standard\n" .. dump(mcl_signs.wall_standard)) end -- standing sign base. local new_sign_standing = {} new_sign_standing = table.copy(mcl_signs.standing_standard) new_sign_standing.drop = "mcl_signs:wall_sign" .. _name new_sign_standing.wield_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign_standing.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } new_sign_standing.inventory_image = "(mcl_signs_default_sign.png^[multiply:" .. color .. ")" new_sign_standing.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign22_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end, minetest.override_item("mcl_signs:standing_sign" .. _name, new_sign_standing) update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Registered: mcl_signs:standing_sign" .. _name .. color .. "\n" .. dump(new_sign_standing)) end -- 22.5° local ssign22_5d = table.copy(new_sign_standing) ssign22_5d.mesh = "mcl_signs_sign22.5.obj" ssign22_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign45" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign22_5" .. _name, ssign22_5d) update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) -- 45° local ssign45d = table.copy(new_sign_standing) ssign45d.mesh = "mcl_signs_sign45.obj" ssign45d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign67_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign45" .. _name, ssign45d) update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) -- 67.5° local ssign67_5d = table.copy(new_sign_standing) ssign67_5d.mesh = "mcl_signs_sign67.5.obj" ssign67_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign" .. _name node.param2 = (node.param2 + 1) % 4 minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign67_5" .. _name, ssign67_5d) update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) -- register Doc entry if minetest.get_modpath("doc") then doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) end --register standing sign's rotation_levels table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign22_5" .. _name, 1 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign45" .. _name, 2 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign67_5" .. _name, 3 }) -- register as unpushable if minetest.get_modpath("mesecons_mvps") then mesecon.register_mvps_stopper("mcl_signs:wall_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign22_5" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign45" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign67_5" .. _name) end end --- The same as reregister_sign, except caller defines the textures. Note, there is a greyscale version of the sign, --- called "mcl_signs_default_sign_greyscale.png" and "mcl_signs_sign_greyscale.png" for optional use in the textures directory. --- --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" --- --- tiles: the texture file to use for the sign. --- --- color: color the texture file to use with this color. Use white (#FFFFFF) to negate the color, --- and just use the texture as is --- --- inventory_image: the texture file to use for the sign's display in inventory. --- --- wield_image: the texture file to use for the sign's weilded (in hand) object. --- --- inventory_image: the image used for in-inventory and in hand. --- --- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. --- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" function mcl_signs.reregister_sign_custom (modname, _name, tiles, color, inventory_image, wield_image, ttsign) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end local new_sign = {} new_sign = table.copy(mcl_signs.wall_standard) if not color or color == nil then new_sign.wield_image = wield_image new_sign.tiles = { tiles } new_sign.inventory_image = inventory_image else new_sign.wield_image = "(" .. wield_image .. "^[multiply:" .. color .. ")" new_sign.tiles = { "(" .. tiles .. "^[multiply:" .. color .. ")" } new_sign.inventory_image = "(" .. inventory_image .. "^[multiply:" .. color .. ")" end new_sign.description = ttsign -- currently have to do this, because of how the base node placement works. new_sign.on_place = function(itemstack, placer, pointed_thing) local above = pointed_thing.above local under = pointed_thing.under -- Use pointed node's on_rightclick function first, if present local node_under = minetest.get_node(under) if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack end end local dir = vector.subtract(under, above) -- Only build when it's legal local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] if not abovenodedef or abovenodedef.buildable_to == false then return itemstack end local wdir = minetest.dir_to_wallmounted(dir) local fdir = minetest.dir_to_facedir(dir) local sign_info local nodeitem = ItemStack(itemstack) -- Ceiling if wdir == 0 then --how would you add sign to ceiling? return itemstack -- Floor elseif wdir == 1 then -- Standing sign -- Determine the sign rotation based on player's yaw local yaw = pi * 2 - placer:get_look_horizontal() -- Select one of 16 possible rotations (0-15) local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) if rotation_level > 15 then rotation_level = 0 elseif rotation_level < 0 then rotation_level = 15 end -- The actual rotation is a combination of predefined mesh and facedir (see node definition) if rotation_level % 4 == 0 then nodeitem:set_name("mcl_signs:standing_sign" .. _name) elseif rotation_level % 4 == 1 then nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) elseif rotation_level % 4 == 2 then nodeitem:set_name("mcl_signs:standing_sign45" .. _name) elseif rotation_level % 4 == 3 then nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) end fdir = math.floor(rotation_level / 4) -- Place the node! local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) if not success then return itemstack end if not minetest.is_creative_enabled(placer:get_player_name()) then itemstack:take_item() end sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] -- Side else -- Wall sign local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) if not success then return itemstack end sign_info = mcl_signs.signtext_info_wall[fdir + 1] end -- Determine spawn position of entity local place_pos if minetest.registered_nodes[node_under.name].buildable_to then place_pos = under else place_pos = above end local text_entity = minetest.add_entity({ x = place_pos.x + sign_info.delta.x, y = place_pos.y + sign_info.delta.y, z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") text_entity:set_yaw(sign_info.yaw) text_entity:get_luaentity()._signnodename = nodeitem:get_name() minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) mcl_signs:show_formspec(placer, place_pos) return itemstack end minetest.override_item("mcl_signs:wall_sign" .. _name, new_sign) update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) -- standing sign base. local new_sign_standing = {} new_sign_standing = table.copy(mcl_signs.standing_standard) if not color or color == nil then new_sign_standing.wield_image = wield_image new_sign_standing.tiles = { tiles } new_sign_standing.inventory_image = inventory_image else new_sign_standing.wield_image = "(" .. wield_image .. "^[multiply:" .. color .. ")" new_sign_standing.tiles = { "(" .. tiles .. "^[multiply:" .. color .. ")" } new_sign_standing.inventory_image = "(" .. inventory_image .. "^[multiply:" .. color .. ")" end new_sign_standing.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign22_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end, minetest.override_item("mcl_signs:standing_sign" .. _name, new_sign_standing) update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) -- 22.5° local ssign22_5d = table.copy(new_sign_standing) ssign22_5d.mesh = "mcl_signs_sign22.5.obj" ssign22_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign45" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign22_5" .. _name, ssign22_5d) update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) -- 45° local ssign45d = table.copy(new_sign_standing) ssign45d.mesh = "mcl_signs_sign45.obj" ssign45d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign67_5" .. _name minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign45" .. _name, ssign45d) update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) -- 67.5° local ssign67_5d = table.copy(new_sign_standing) ssign67_5d.mesh = "mcl_signs_sign67.5.obj" ssign67_5d.on_rotate = function(pos, node, user, mode) if mode == screwdriver.ROTATE_FACE then node.name = "mcl_signs:standing_sign" .. _name node.param2 = (node.param2 + 1) % 4 minetest.swap_node(pos, node) elseif mode == screwdriver.ROTATE_AXIS then return false end mcl_signs:update_sign(pos, nil, nil, true) return true end minetest.override_item("mcl_signs:standing_sign67_5" .. _name, ssign67_5d) update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) -- register Doc entry if minetest.get_modpath("doc") then doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) end --register standing sign's rotation_levels table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign22_5" .. _name, 1 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign45" .. _name, 2 }) table.insert(mcl_signs.standing_rotation_levels, { "mcl_signs:standing_sign67_5" .. _name, 3 }) -- register as unpushable if minetest.get_modpath("mesecons_mvps") then mesecon.register_mvps_stopper("mcl_signs:wall_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign22_5" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign45" .. _name) mesecon.register_mvps_stopper("mcl_signs:standing_sign67_5" .. _name) end end --- Usage: Call this with the mod's name, the wood's item string (for the planks), and with the sign's suffix. --- Registers the crafting recipe for that sign. for every registered sign, call this function to register the --- standard recipe for the sign. Otherwise, you have to do your own register craft call. --- --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). Example: "mcl_core". --- --- wood_item_string: example: "mcl_core:wood" or "mcl_core:sprucewood" --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" function mcl_signs.register_sign_craft(modname, wood_item_string, _name) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end minetest.register_craft({ type = "fuel", recipe = "mcl_signs:wall_sign" .. _name, burntime = 10, }) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Register Sign Crafts: \n" .. modname .. "\n" .. wood_item_string .. "\n" .. _name) end -- register crafts (actual recipe) if minetest.get_modpath(modname) then local itemstring = "mcl_signs:wall_sign" minetest.register_craft({ output = itemstring .. _name .. " 3", recipe = { { wood_item_string, wood_item_string, wood_item_string }, { wood_item_string, wood_item_string, wood_item_string }, { "", "mcl_core:stick", "" }, }, }) end end function mcl_signs.register_hanging_sign_craft(modname, wood_item_string, _name) local mod_name_pass = false if modname ~= "" and modname ~= "false" then if minetest.get_modpath(modname) then mod_name_pass = true end if mod_name_pass == false then return end end minetest.register_craft({ type = "fuel", recipe = ":mcl_signs:wall_sign" .. _name, burntime = 10, }) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Register Sign Crafts: \n" .. modname .. "\n" .. wood_item_string .. "\n" .. _name) end -- register crafts (actual recipe) if minetest.get_modpath(modname) then local itemstring = ":mcl_signs:hanging_sign" local quantity = "6" local bamboo = string.find(wood_item_string, "bamboo") if bamboo then quantity = "2" end minetest.register_craft({ output = itemstring .. _name .. " " .. quantity, recipe = { { "mcl_lanterns:chain", "", "mcl_lanterns:chain" }, { wood_item_string, wood_item_string, wood_item_string }, { wood_item_string, wood_item_string, wood_item_string }, }, }) end end -- Helper functions local function string_to_array(str) local string_table = {} for i = 1, string.len(str) do table.insert(string_table, string.sub(str, i, i)) end return string_table end local function string_to_line_array(str) local linechar_table = {} local current = 1 local linechar = 1 linechar_table[1] = "" for _, char in ipairs(string_to_array(str)) do -- New line if char == "\n" then current = current + 1 linechar_table[current] = "" linechar = 1 else linechar_table[current] = linechar_table[current] .. char linechar = linechar + 1 end end return linechar_table end local function get_rotation_level(facedir, nodename) local nnames = mcl_signs.standing_rotation_levels -- functional copy... was easier this way. #LazyAF :P local rl local offset = 0 for x = 1, #nnames do if nnames[x][1] == nodename then offset = nnames[x][2] break end end rl = facedir * 4 + offset if DEBUG then minetest.log("action", "[mcl_signs] GetRotationLevel: NodeName: " .. nodename .. " RL value: " .. rl) end return rl end function mcl_signs:round(num, idp) local mult = 10 ^ (idp or 0) return math.floor(num * mult + 0.5) / mult end function mcl_signs:get_color_for_sign(item_name) for d = 1, #Dyes_table do if Dyes_table[d][1] == item_name then return Dyes_table[d][2] end end return "false" end function mcl_signs:color_sign (pos, text_color) local success = mcl_signs:update_sign(pos, nil, nil, true, text_color) -- debug step local meta = minetest.get_meta(pos) if not meta then minetest.log("error", "[mcl_signs] Sign Color Fail - Metadata.") return false end if DEBUG then minetest.log("verbose", "[mcl_signs] Post-Sign Color: " .. meta:get_string("mcl_signs:text_color") .. " " .. meta:get_string("mcl_signs:glowing_sign") .. ".\n" .. dump(pos)) end return success end function mcl_signs:glow_sign (pos, remove_glow) local success = true -- Get Meta Data for the sign. local meta = minetest.get_meta(pos) if not meta then return false end local text = meta:get_string("text") if text == nil then text = "" end -- we can't make the text glow if there isn't any text if text == "" then return false end if remove_glow == nil then remove_glow = false end -- set up text glow local objects = minetest.get_objects_inside_radius(pos, 0.5) local text_entity for _, v in ipairs(objects) do local ent = v:get_luaentity() if ent and ent.name == "mcl_signs:text" then text_entity = v break end end if remove_glow == true then text_entity:set_properties({ glow = nil, }) meta:set_string("mcl_signs:glowing_sign", "false") else text_entity:set_properties({ glow = sign_glow, }) meta:set_string("mcl_signs:glowing_sign", "true") end if not text_entity then return false end text_entity:get_luaentity()._glowing_sign = meta:get_string("mcl_signs:glowing_sign") -- debug step if DEBUG then minetest.log("verbose", "[mcl_signs] Post-Sign Glow: " .. meta:get_string("mcl_signs:text_color") .. " " .. meta:get_string("mcl_signs:glowing_sign") .. ".\n" .. dump(pos)) end return success end function mcl_signs:create_lettering(text, signnodename, sign_color) if sign_color == nil then sign_color = mcl_colors.BLACK end local texture = mcl_signs:generate_texture(mcl_signs:create_lines(text), signnodename, sign_color) -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Creating sign text; text:" .. text) end return texture end function mcl_signs:create_lines(text) local line_num = 1 local text_table = {} for _, line in ipairs(string_to_line_array(text)) do if line_num > NUMBER_OF_LINES then break end table.insert(text_table, line) line_num = line_num + 1 end return text_table end function mcl_signs:generate_line(s, ypos) local i = 1 local parsed = {} local width = 0 local chars = 0 local printed_char_width = CHAR_WIDTH + 1 while chars < LINE_LENGTH and i <= #s do local file -- Get and render character if charmap[s:sub(i, i)] then file = charmap[s:sub(i, i)] i = i + 1 elseif i < #s and charmap[s:sub(i, i + 1)] then file = charmap[s:sub(i, i + 1)] i = i + 2 else -- No character image found. -- Use replacement character: file = "_rc" i = i + 1 if DEBUG then minetest.log("verbose", "[mcl_signs] Unknown symbol in '" .. s .. "' at " .. i) end end if file then width = width + printed_char_width table.insert(parsed, file) chars = chars + 1 end end width = width - 1 local texture = "" local xpos = math.floor((SIGN_WIDTH - width) / 2) for j = 1, #parsed do texture = texture .. ":" .. xpos .. "," .. ypos .. "=" .. parsed[j] .. ".png" xpos = xpos + printed_char_width end return texture end function mcl_signs:generate_texture(lines, signnodename, letter_color) local texture = "[combine:" .. SIGN_WIDTH .. "x" .. SIGN_WIDTH local ypos = 0 -- Handle all of the dynamically created signs. for x = 1, #mcl_signs.registered_signs.wall_signs do if signnodename == mcl_signs.registered_signs.wall_signs[x] then ypos = 30 break end end for x = 1, #mcl_signs.registered_signs.standing_signs do if signnodename == mcl_signs.registered_signs.standing_signs[x] then ypos = 0 break end end -- for future inclusion, when the hanging sings are made. --[[ for x = 1, #mcl_signs.registered_signs.hanging_signs do if signnodename == mcl_signs.registered_signs.hanging_signs[x] then ypos = 30 break end end ]] -- kept in for now, compatibility with existing hard coded signs. TODO: Remove after done with api. if signnodename == "mcl_signs:wall_sign" or signnodename == "mcl_signs:wall_sign_dark" then ypos = 30 end -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Generate_Texture::Debug_Data:\nSignNodeName: " .. dump(signnodename) .. "\nYPOS: " .. ypos) end for i = 1, #lines do texture = texture .. mcl_signs:generate_line(lines[i], ypos) ypos = ypos + LINE_HEIGHT end texture = "(" .. texture .. "^[multiply:" .. letter_color .. ")" return texture end function mcl_signs:get_wall_signtext_info(param2, nodename) local dir = minetest.wallmounted_to_dir(param2) if dir.x > 0 then return 2 elseif dir.z > 0 then return 1 elseif dir.x < 0 then return 4 else return 3 end end function mcl_signs:destruct_sign(pos) local objects = minetest.get_objects_inside_radius(pos, 0.5) for _, v in ipairs(objects) do local ent = v:get_luaentity() if ent and ent.name == "mcl_signs:text" then v:remove() end end local players = minetest.get_connected_players() for p = 1, #players do if vector.distance(players[p]:get_pos(), pos) <= 30 then minetest.close_formspec(players[p]:get_player_name(), "mcl_signs:set_text_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z) end end end function mcl_signs:update_sign(pos, fields, sender, force_remove, text_color) -- Get Meta Data for the sign. local meta = minetest.get_meta(pos) if not meta then return false end local text = meta:get_string("text", "") if fields and (text == "" and fields.text) then meta:set_string("text", fields.text) text = fields.text end if text == nil then text = "" end -- find text color. local sign_color if meta:get_string("mcl_signs:text_color") == "" then -- if no sign text color has been assigned, make it black. sign_color = mcl_colors.BLACK meta:set_string("mcl_signs:text_color", sign_color) else sign_color = meta:get_string("mcl_signs:text_color") end if text_color == nil or text == "" then text_color = "false" end if text_color == "false" then text_color = sign_color --if a new color hasn't been chosen, then keep the existing color. end -- find the sign's glow value local has_glow = false if meta:get_string("mcl_signs:glowing_sign") == "" or meta:get_string("mcl_signs:glowing_sign") == "false" then has_glow = false meta:set_string("mcl_signs:glowing_sign", "false") else has_glow = true end -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Update_Signs: Pre-Sign Update: " .. sign_color .. " " .. meta:get_string("mcl_signs:glowing_sign") .. ".\n" .. dump(pos)) end local sign_info local npos = minetest.get_node(pos) local npos_name = npos.name -- Handle all of the dynamically created signs. for x = 1, #mcl_signs.registered_signs.wall_signs do if npos_name == mcl_signs.registered_signs.wall_signs[x] then sign_info = mcl_signs.signtext_info_wall[mcl_signs:get_wall_signtext_info(npos.param2)] break end end for x = 1, #mcl_signs.registered_signs.standing_signs do if npos_name == mcl_signs.registered_signs.standing_signs[x] then sign_info = mcl_signs.signtext_info_standing[get_rotation_level(npos.param2, npos_name) + 1] break end end -- for future inclusion, when the hanging sings are made. --[[ for x = 1, #mcl_signs.registered_signs.hanging_signs do if nn == mcl_signs.registered_signs.hanging_signs[x] then sign_info = mcl_signs.signtext_info_wall[mcl_signs:get_wall_signtext_info(n.param2)] break end end ]] -- the following if..elseif..end block is here for compatibility with the old code. TODO: remove this block after the new api is complete. if npos_name == "mcl_signs:standing_sign_dark" or npos_name == "mcl_signs:standing_sign22_5_dark" or npos_name == "mcl_signs:standing_sign45_dark" or npos_name == "mcl_signs:standing_sign67_5_dark" then sign_info = mcl_signs.signtext_info_standing[get_rotation_level(npos.param2, npos_name) + 1] elseif npos_name == "mcl_signs:wall_sign_dark" then sign_info = mcl_signs.signtext_info_wall[mcl_signs:get_wall_signtext_info(npos.param2)] end if sign_info == nil then minetest.log("error", "[mcl_signs] Update_Signs: Missing sign_info!") return false end local text_entity text_entity = mcl_signs:get_text_entity(pos,force_remove) if not text_entity then if DEBUG then minetest.log("action", "[mcl_signs] Update_Sign: Text_Entity - does not exist, creating it now.") end text_entity = minetest.add_entity({ x = pos.x + sign_info.delta.x, y = pos.y + sign_info.delta.y, z = pos.z + sign_info.delta.z }, "mcl_signs:text") if DEBUG then minetest.log("action", "[mcl_signs] Update_Sign: Placed position:" .. dump(pos) .. "\nSign_info: " .. dump(sign_info)) end end text_entity:get_luaentity()._signnodename = npos_name -- set up special case: Dark Oak Sign. Dark Oak signs are soooo dark, they start off with white lettering. if npos_name == "mcl_signs:wall_sign_darkwood" or npos_name == "mcl_signs:standing_sign67_5_darkwood" or npos_name == "mcl_signs:standing_sign45_darkwood" or npos_name == "mcl_signs:standing_sign22_5_darkwood" or npos_name == "mcl_signs:standing_sign_darkwood" then if text_color == "#000000" then text_color = "#ffffff" end end -- Set the actual properties for the sign text_entity:set_properties({ textures = { mcl_signs:create_lettering(text, npos_name, text_color) }, }) if has_glow then text_entity:set_properties({ glow = sign_glow, }) end text_entity:set_yaw(sign_info.yaw) if DEBUG then minetest.log("verbose", "[mcl_signs] Update_Sign: After texture recreation.") minetest.log("action", "[mcl_signs] Update_Sign: " .. npos_name .. "\nPlaced position:" .. dump(pos) .. "\nSign_info: " .. dump(sign_info)) end -- save sign metadata. meta:set_string("mcl_signs:text_color", text_color) -- Moved timer stuff to here, to make sure that it's called and only has one set of code. local timer = minetest.get_node_timer(pos) if text_entity and text ~= "" then -- Do timer related stuff - but only if there is text to display. -- Also, prevent excessive use with punching. (see node def.) if timer:is_started() == false then timer:start(TIMER_INTERVAL) else timer:stop() timer:start(TIMER_INTERVAL) end else if timer:is_started() == true then timer:stop() end end -- debug step if DEBUG then minetest.log("action", "[mcl_signs] Update_Sign: Post-Sign Update: " .. meta:get_string("mcl_signs:text_color") .. " " .. meta:get_string("mcl_signs:glowing_sign") .. ".\n" .. dump(pos)) end return true end function mcl_signs:show_formspec(player, pos) minetest.show_formspec( player:get_player_name(), "mcl_signs:set_text_" .. pos.x .. "_" .. pos.y .. "_" .. pos.z, "size[6,3]textarea[0.25,0.25;6,1.5;text;" .. F(S("Enter sign text:")) .. ";]label[0,1.5;" .. F(S("Maximum line length: 15")) .. "\n" .. F(S("Maximum lines: 4")) .. "]button_exit[0,2.5;6,1;submit;" .. F(S("Done")) .. "]" ) end function mcl_signs:get_text_entity (pos, force_remove) local objects = minetest.get_objects_inside_radius(pos, 0.5) local text_entity = false -- just to have a check for failure. for _, v in ipairs(objects) do local ent = v:get_luaentity() if ent and ent.name == "mcl_signs:text" then if force_remove ~= nil and force_remove == true then v:remove() else text_entity = v break end end end return text_entity end