]> git.lizzy.rs Git - signs_lib.git/blobdiff - init.lua
pass node information to sign update function, remove all entities on update incase...
[signs_lib.git] / init.lua
index 1f43453e6f6fe5510a6400ca38da6694febc343c..b8b4db593afca598852d4530068ee81493c41089 100644 (file)
--- a/init.lua
+++ b/init.lua
@@ -9,28 +9,68 @@
 --             { delta = {entity position for 270° yaw}, exact yaw expression }
 --             { delta = {entity position for 90° yaw}, exact yaw expression }
 -- }
+-- Made colored metal signs optionals
+local enable_colored_metal_signs = true
 
 -- CWz's keyword interact mod uses this setting.
-local current_keyword = minetest.setting_get("interact_keyword") or "iaccept"
+local current_keyword = minetest.settings:get("interact_keyword") or "iaccept"
 
 signs_lib = {}
+signs_lib.path = minetest.get_modpath(minetest.get_current_modname())
 screwdriver = screwdriver or {}
 
-signs_lib.wallmounted_rotate = function(pos, node, user, mode, new_param2)
-       if mode ~= screwdriver.ROTATE_AXIS then return false end
-       minetest.swap_node(pos, {name = node.name, param2 = (node.param2 + 1) % 6})
-       for _, v in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
-               local e = v:get_luaentity()
-               if e and e.name == "signs:text" then
-                       v:remove()
-               end
+-- Load support for intllib.
+local S, NS = dofile(signs_lib.path .. "/intllib.lua")
+signs_lib.gettext = S
+
+-- text encoding
+dofile(signs_lib.path .. "/encoding.lua");
+
+
+local wall_dir_change = {
+       [0] = 4,
+       0,
+       5,
+       1,
+       2,
+       3,
+       0
+}
+
+signs_lib.wallmounted_rotate = function(pos, node, user, mode)
+       if mode ~= screwdriver.ROTATE_FACE then return false end 
+       minetest.swap_node(pos, { name = node.name, param2 = wall_dir_change[node.param2 % 6] })
+       signs_lib.update_sign(pos,nil,nil,node)
+       return true
+end
+
+signs_lib.facedir_rotate = function(pos, node, user, mode)
+       if mode ~= screwdriver.ROTATE_FACE then return false end
+       local newparam2 = (node.param2 %8) + 1
+       if newparam2 == 5 then
+               newparam2 = 6
+       elseif newparam2 > 6 then
+               newparam2 = 0
        end
-       signs_lib.update_sign(pos)
+       minetest.swap_node(pos, { name = node.name, param2 = newparam2 })
+       signs_lib.update_sign(pos,nil,nil,node)
        return true
 end
 
+signs_lib.facedir_rotate_simple = function(pos, node, user, mode)
+       if mode ~= screwdriver.ROTATE_FACE then return false end
+       local newparam2 = (node.param2 %8) + 1
+       if newparam2 > 3 then newparam2 = 0 end
+       minetest.swap_node(pos, { name = node.name, param2 = newparam2 })
+       signs_lib.update_sign(pos,nil,nil,node)
+       return true
+end
+
+
 signs_lib.modpath = minetest.get_modpath("signs_lib")
 
+local DEFAULT_TEXT_SCALE = {x=0.8, y=0.5}
+
 signs_lib.regular_wall_sign_model = {
        nodebox = {
                type = "wallmounted",
@@ -41,10 +81,10 @@ signs_lib.regular_wall_sign_model = {
        textpos = {
                nil,
                nil,
-               {delta = {x =  0.43,  y = 0.07, z =  0     }, yaw = math.pi / -2},
-               {delta = {x = -0.43,  y = 0.07, z =  0     }, yaw = math.pi / 2},
-               {delta = {x =  0,     y = 0.07, z =  0.43  }, yaw = 0},
-               {delta = {x =  0,     y = 0.07, z = -0.43  }, yaw = math.pi},
+               {delta = { x =  0.41, y = 0.07, z =  0    }, yaw = math.pi / -2},
+               {delta = { x = -0.41, y = 0.07, z =  0    }, yaw = math.pi / 2},
+               {delta = { x =  0,    y = 0.07, z =  0.41 }, yaw = 0},
+               {delta = { x =  0,    y = 0.07, z = -0.41 }, yaw = math.pi},
        }
 }
 
@@ -54,10 +94,10 @@ signs_lib.metal_wall_sign_model = {
                fixed = {-0.4375, -0.25, 0.4375, 0.4375, 0.375, 0.5}
        },
        textpos = {
-               {delta = {x =  0,     y = 0.07, z =  0.43  }, yaw = 0},
-               {delta = {x =  0.43,  y = 0.07, z =  0     }, yaw = math.pi / -2},
-               {delta = {x =  0,     y = 0.07, z = -0.43  }, yaw = math.pi},
-               {delta = {x = -0.43,  y = 0.07, z =  0     }, yaw = math.pi / 2},
+               {delta = { x =  0,     y = 0.07, z =  0.41 }, yaw = 0},
+               {delta = { x =  0.41,  y = 0.07, z =  0    }, yaw = math.pi / -2},
+               {delta = { x =  0,     y = 0.07, z = -0.41 }, yaw = math.pi},
+               {delta = { x = -0.41,  y = 0.07, z =  0    }, yaw = math.pi / 2},
        }
 }
 
@@ -70,10 +110,10 @@ signs_lib.yard_sign_model = {
                }
        },
        textpos = {
-               {delta = {x =  0,      y = 0.07, z = -0.068}, yaw = 0},
-               {delta = {x = -0.068,  y = 0.07, z =  0    }, yaw = math.pi / -2},
-               {delta = {x =  0,      y = 0.07, z =  0.068}, yaw = math.pi},
-               {delta = {x =  0.068,  y = 0.07, z =  0    }, yaw = math.pi / 2},
+               {delta = { x =  0,    y = 0.07, z = -0.08 }, yaw = 0},
+               {delta = { x = -0.08, y = 0.07, z =  0    }, yaw = math.pi / -2},
+               {delta = { x =  0,    y = 0.07, z =  0.08 }, yaw = math.pi},
+               {delta = { x =  0.08, y = 0.07, z =  0    }, yaw = math.pi / 2},
        }
 }
 
@@ -86,10 +126,10 @@ signs_lib.hanging_sign_model = {
                }
        },
        textpos = {
-               {delta = {x =  0,      y = -0.02, z = -0.063}, yaw = 0},
-               {delta = {x = -0.063,  y = -0.02, z =  0    }, yaw = math.pi / -2},
-               {delta = {x =  0,      y = -0.02, z =  0.063}, yaw = math.pi},
-               {delta = {x =  0.063,  y = -0.02, z =  0    }, yaw = math.pi / 2},
+               {delta = { x =  0,    y = -0.02, z = -0.08 }, yaw = 0},
+               {delta = { x = -0.08, y = -0.02, z =  0    }, yaw = math.pi / -2},
+               {delta = { x =  0,    y = -0.02, z =  0.08 }, yaw = math.pi},
+               {delta = { x =  0.08, y = -0.02, z =  0    }, yaw = math.pi / 2},
        }
 }
 
@@ -102,32 +142,29 @@ signs_lib.sign_post_model = {
                }
        },
        textpos = {
-               {delta = {x = 0,      y = 0.07, z = -0.188}, yaw = 0},
-               {delta = {x = -0.188, y = 0.07, z = 0     }, yaw = math.pi / -2},
-               {delta = {x = 0,      y = 0.07, z = 0.188 }, yaw = math.pi},
-               {delta = {x = 0.188,  y = 0.07, z = 0     }, yaw = math.pi / 2},
+               {delta = { x = 0,    y = 0.07, z = -0.2 }, yaw = 0},
+               {delta = { x = -0.2, y = 0.07, z = 0    }, yaw = math.pi / -2},
+               {delta = { x = 0,    y = 0.07, z = 0.2  }, yaw = math.pi},
+               {delta = { x = 0.2,  y = 0.07, z = 0    }, yaw = math.pi / 2},
        }
 }
 
--- Boilerplate to support localized strings if intllib mod is installed.
-local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
-signs_lib.gettext = S
-
 -- the list of standard sign nodes
 
 signs_lib.sign_node_list = {
-               "default:sign_wall_wood",
-               "signs:sign_yard",
-               "signs:sign_hanging",
-               "signs:sign_wall_green",
-               "signs:sign_wall_yellow",
-               "signs:sign_wall_red",
-               "signs:sign_wall_white_red",
-               "signs:sign_wall_white_black",
-               "signs:sign_wall_orange",
-               "signs:sign_wall_blue",
-               "signs:sign_wall_brown",
-               "locked_sign:sign_wall_locked"
+       "default:sign_wall_wood",
+       "default:sign_wall_steel",
+       "signs:sign_yard",
+       "signs:sign_hanging",
+       "signs:sign_wall_green",
+       "signs:sign_wall_yellow",
+       "signs:sign_wall_red",
+       "signs:sign_wall_white_red",
+       "signs:sign_wall_white_black",
+       "signs:sign_wall_orange",
+       "signs:sign_wall_blue",
+       "signs:sign_wall_brown",
+       "locked_sign:sign_wall_locked"
 }
 
 local default_sign, default_sign_image
@@ -141,23 +178,26 @@ else
        default_sign_image = "default_sign_wall.png"
 end
 
+default_sign_metal = "default:sign_wall_steel"
+default_sign_metal_image = "default_sign_steel.png"
+
 --table copy
 
 function signs_lib.table_copy(t)
-    local nt = { };
-    for k, v in pairs(t) do
-        if type(v) == "table" then
-            nt[k] = signs_lib.table_copy(v)
-        else
-            nt[k] = v
-        end
-    end
-    return nt
+       local nt = { }
+       for k, v in pairs(t) do
+               if type(v) == "table" then
+                       nt[k] = signs_lib.table_copy(v)
+               else
+                       nt[k] = v
+               end
+       end
+       return nt
 end
 
 -- infinite stacks
 
-if minetest.get_modpath("unified_inventory") or not minetest.setting_getbool("creative_mode") then
+if not minetest.settings:get_bool("creative_mode") then
        signs_lib.expect_infinite_stacks = false
 else
        signs_lib.expect_infinite_stacks = true
@@ -165,30 +205,48 @@ end
 
 -- CONSTANTS
 
-local MP = minetest.get_modpath("signs_lib")
-
--- Used by `build_char_db' to locate the file.
-local FONT_FMT = "%s/hdf_%02x.png"
-
--- Simple texture name for building text texture.
-local FONT_FMT_SIMPLE = "hdf_%02x.png"
-
 -- Path to the textures.
-local TP = MP.."/textures"
+local TP = signs_lib.path .. "/textures"
+-- Font file formatter
+local CHAR_FILE = "%s_%02x.png"
+-- Fonts path
+local CHAR_PATH = TP .. "/" .. CHAR_FILE
 
-local TEXT_SCALE = {x=0.8, y=0.5}
+-- Font name.
+local font_name = "hdf"
 
 -- Lots of overkill here. KISS advocates, go away, shoo! ;) -- kaeza
 
 local PNG_HDR = string.char(0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A)
 
+-- check if a file does exist
+-- to avoid reopening file after checking again
+-- pass TRUE as second argument
+function file_exists(name, return_handle, mode)
+       mode = mode or "r";
+       local f = io.open(name, mode)
+       if f ~= nil then
+               if (return_handle) then
+                       return f
+               end
+               io.close(f) 
+               return true 
+       else 
+               return false 
+       end
+end
+
 -- Read the image size from a PNG file.
 -- Returns image_w, image_h.
 -- Only the LSB is read from each field!
 local function read_image_size(filename)
-       local f = io.open(filename, "rb")
+       local f = file_exists(filename, true, "rb")
+       -- file might not exist (don't crash the game)
+       if (not f) then
+               return 0, 0
+       end
        f:seek("set", 0x0)
-       local hdr = f:read(8)
+       local hdr = f:read(string.len(PNG_HDR))
        if hdr ~= PNG_HDR then
                f:close()
                return
@@ -236,8 +294,8 @@ local function build_char_db()
        local total_width = 0
        local char_count = 0
 
-       for c = 32, 126 do
-               local w, h = read_image_size(FONT_FMT:format(TP, c))
+       for c = 32, 255 do
+               local w, h = read_image_size(CHAR_PATH:format(font_name, c))
                if w and h then
                        local ch = string.char(c)
                        charwidth[ch] = w
@@ -301,14 +359,29 @@ local function fill_line(x, y, w, c)
        return table.concat(tex)
 end
 
-local function make_line_texture(line, lineno)
+-- make char texture file name
+-- if texture file does not exist use fallback texture instead
+local function char_tex(font_name, ch)
+       local c = ch:byte()
+       local exists, tex = file_exists(CHAR_PATH:format(font_name, c))
+       if exists and c ~= 14 then
+               tex = CHAR_FILE:format(font_name, c)
+       else
+               tex = CHAR_FILE:format(font_name, 0x0)
+       end
+       return tex, exists
+end
+
+local function make_line_texture(line, lineno, pos)
 
        local width = 0
        local maxw = 0
 
        local words = { }
+       local n = minetest.registered_nodes[minetest.get_node(pos).name]
+       local default_color = n.default_color or 0
 
-       local cur_color = 0
+       local cur_color = tonumber(default_color, 16)
 
        -- We check which chars are available here.
        for word_i, word in ipairs(line) do
@@ -335,9 +408,9 @@ local function make_line_texture(line, lineno)
                                        end
                                        if #chars < MAX_INPUT_CHARS then
                                                table.insert(chars, {
-                                                       off=ch_offs,
-                                                       tex=FONT_FMT_SIMPLE:format(c:byte()),
-                                                       col=("%X"):format(cur_color),
+                                                       off = ch_offs,
+                                                       tex = char_tex(font_name, c),
+                                                       col = ("%X"):format(cur_color),
                                                })
                                        end
                                        ch_offs = ch_offs + w
@@ -378,7 +451,10 @@ local function make_line_texture(line, lineno)
                        end
                        table.insert(texture, (":%d,%d=%s"):format(xpos + ch.off, ypos, ch.tex))
                end
-               table.insert(texture, (":%d,%d=hdf_20.png"):format(xpos + word.w, ypos))
+               table.insert(
+                       texture, 
+                       (":%d,%d="):format(xpos + word.w, ypos) .. char_tex(font_name, " ")
+               )
                xpos = xpos + word.w + charwidth[" "]
                if xpos >= (SIGN_WIDTH + charwidth[" "]) then break end
        end
@@ -389,12 +465,12 @@ local function make_line_texture(line, lineno)
        return table.concat(texture), lineno
 end
 
-local function make_sign_texture(lines)
+local function make_sign_texture(lines, pos)
        local texture = { ("[combine:%dx%d"):format(SIGN_WIDTH, LINE_HEIGHT * NUMBER_OF_LINES) }
        local lineno = 0
        for i = 1, #lines do
                if lineno >= NUMBER_OF_LINES then break end
-               local linetex, ln = make_line_texture(lines[i], lineno)
+               local linetex, ln = make_line_texture(lines[i], lineno, pos)
                table.insert(texture, linetex)
                lineno = ln + 1
        end
@@ -402,33 +478,36 @@ local function make_sign_texture(lines)
        return table.concat(texture, "")
 end
 
-local function set_obj_text(obj, text, new)
+local function set_obj_text(obj, text, new, pos)
        local split = new and split_lines_and_words or split_lines_and_words_old
+       local text_ansi = Utf8ToAnsi(text)
+       local n = minetest.registered_nodes[minetest.get_node(pos).name]
+       local text_scale = (n and n.text_scale) or DEFAULT_TEXT_SCALE
        obj:set_properties({
-               textures={make_sign_texture(split(text))},
-               visual_size = TEXT_SCALE,
+               textures={make_sign_texture(split(text_ansi), pos)},
+               visual_size = text_scale,
        })
 end
 
 signs_lib.construct_sign = function(pos, locked)
-    local meta = minetest.get_meta(pos)
+       local meta = minetest.get_meta(pos)
        meta:set_string(
                "formspec",
                "size[6,4]"..
                "textarea[0,-0.3;6.5,3;text;;${text}]"..
-               "button_exit[2,3.4;2,1;ok;Write]"..
+               "button_exit[2,3.4;2,1;ok;"..S("Write").."]"..
                "background[-0.5,-0.5;7,5;bg_signs_lib.jpg]")
        meta:set_string("infotext", "")
 end
 
 signs_lib.destruct_sign = function(pos)
-    local objects = minetest.get_objects_inside_radius(pos, 0.5)
-    for _, v in ipairs(objects) do
+       local objects = minetest.get_objects_inside_radius(pos, 0.5)
+       for _, v in ipairs(objects) do
                local e = v:get_luaentity()
-        if e and e.name == "signs:text" then
-            v:remove()
-        end
-    end
+               if e and e.name == "signs:text" then
+                       v:remove()
+               end
+       end
 end
 
 local function make_infotext(text)
@@ -441,7 +520,7 @@ local function make_infotext(text)
        return table.concat(lines2, "\n")
 end
 
-signs_lib.update_sign = function(pos, fields, owner)
+signs_lib.update_sign = function(pos, fields, owner, node)
 
        -- First, check if the interact keyword from CWz's mod is being set,
        -- or has been changed since the last restart...
@@ -463,7 +542,7 @@ signs_lib.update_sign = function(pos, fields, owner)
                        signs_lib.destruct_sign(pos)
                        meta:set_string("keyword", current_keyword)
                        local ownstr = ""
-                       if owner then ownstr = "Locked sign, owned by "..owner.."\n" end
+                       if owner then ownstr = S("Locked sign, owned by @1\n", owner) end
                        meta:set_string("infotext", ownstr..string.gsub(make_infotext(stored_text), "@KEYWORD", current_keyword).." ")
                end
        end
@@ -475,7 +554,7 @@ signs_lib.update_sign = function(pos, fields, owner)
                fields.text = trim_input(fields.text)
 
                local ownstr = ""
-               if owner then ownstr = "Locked sign, owned by "..owner.."\n" end
+               if owner then ownstr = S("Locked sign, owned by @1\n", owner) end
 
                meta:set_string("infotext", ownstr..string.gsub(make_infotext(fields.text), "@KEYWORD", current_keyword).." ")
                meta:set_string("text", fields.text)
@@ -485,34 +564,25 @@ signs_lib.update_sign = function(pos, fields, owner)
        else
                new = (meta:get_int("__signslib_new_format") ~= 0)
        end
+       signs_lib.destruct_sign(pos)
        local text = meta:get_string("text")
-       if text == nil then return end
-       local objects = minetest.get_objects_inside_radius(pos, 0.5)
-       local found
-       for _, v in ipairs(objects) do
-               local e = v:get_luaentity()
-               if e and e.name == "signs:text" then
-                       if found then
-                               v:remove()
-                       else
-                               set_obj_text(v, text, new)
-                               found = true
-                       end
-               end
-       end
-       if found then
-               return
-       end
+       if text == nil or text == "" then return end
+
+if node then print ("---", node.name, node.param2) end
 
-       -- if there is no entity
        local sign_info
-       local signnode = minetest.get_node(pos)
-       if signnode.name == "signs:sign_yard" then
+       local signnode = node or minetest.get_node(pos)
+       local signname = signnode.name
+       local textpos = minetest.registered_nodes[signname].textpos
+       if textpos then
+               sign_info = textpos[minetest.get_node(pos).param2 + 1]
+       elseif signnode.name == "signs:sign_yard" then
                sign_info = signs_lib.yard_sign_model.textpos[minetest.get_node(pos).param2 + 1]
        elseif signnode.name == "signs:sign_hanging" then
                sign_info = signs_lib.hanging_sign_model.textpos[minetest.get_node(pos).param2 + 1]
        elseif string.find(signnode.name, "sign_wall") then
                if signnode.name == default_sign
+                 or signnode.name == default_sign_metal
                  or signnode.name == "locked_sign:sign_wall_locked" then
                        sign_info = signs_lib.regular_wall_sign_model.textpos[minetest.get_node(pos).param2 + 1]
                else
@@ -556,8 +626,10 @@ function signs_lib.determine_sign_type(itemstack, placer, pointed_thing, locked)
 
        local node=minetest.get_node(pointed_thing.under)
 
-       if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
-               return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack)
+       if minetest.registered_nodes[node.name] and
+          minetest.registered_nodes[node.name].on_rightclick and
+          not placer:get_player_control().sneak then
+               return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack, pointed_thing)
        else
                local above = pointed_thing.above
                local under = pointed_thing.under
@@ -577,7 +649,6 @@ function signs_lib.determine_sign_type(itemstack, placer, pointed_thing, locked)
                end
 
                local fdir = minetest.dir_to_facedir(dir)
-
                local pt_name = minetest.get_node(under).name
                local signname = itemstack:get_name()
 
@@ -587,8 +658,11 @@ function signs_lib.determine_sign_type(itemstack, placer, pointed_thing, locked)
                        minetest.add_node(above, {name = "signs:sign_hanging", param2 = fdir})
                elseif wdir == 1 and signname == default_sign then
                        minetest.add_node(above, {name = "signs:sign_yard", param2 = fdir})
+               elseif signname == default_sign_metal then
+                       minetest.add_node(above, {name = signname, param2 = wdir })
                elseif signname ~= default_sign
-                 and signname ~= "locked_sign:sign_wall_locked" then -- it's a metal wall sign.
+                 and signname ~= default_sign_metal
+                 and signname ~= "locked_sign:sign_wall_locked" then -- it's a signs_lib colored metal wall sign.
                        minetest.add_node(above, {name = signname, param2 = fdir})
                else -- it must be a default or locked wooden wall sign
                        minetest.add_node(above, {name = signname, param2 = wdir }) -- note it's wallmounted here!
@@ -612,11 +686,12 @@ function signs_lib.receive_fields(pos, formname, fields, sender, lock)
                        sender:get_player_name())
                return
        end
-       local lockstr = lock and "locked " or ""
+       local lockstr = lock and S("locked ") or ""
        if fields and fields.text and fields.ok then
-               minetest.log("action", S("%s wrote \"%s\" to "..lockstr.."sign at %s"):format(
+               minetest.log("action", S("@1 wrote \"@2\" to @3sign at @4",
                        (sender:get_player_name() or ""),
-                       fields.text,
+                       fields.text:gsub('\\', '\\\\'):gsub("\n", "\\n"),
+                       lockstr,
                        minetest.pos_to_string(pos)
                ))
                if lock then
@@ -653,50 +728,52 @@ minetest.register_node(":"..default_sign, {
                signs_lib.receive_fields(pos, formname, fields, sender)
        end,
        on_punch = function(pos, node, puncher)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end,
        on_rotate = signs_lib.wallmounted_rotate
 })
 
 minetest.register_node(":signs:sign_yard", {
-    paramtype = "light",
+       paramtype = "light",
        sunlight_propagates = true,
-    paramtype2 = "facedir",
-    drawtype = "nodebox",
-    node_box = signs_lib.yard_sign_model.nodebox,
+       paramtype2 = "facedir",
+       drawtype = "nodebox",
+       node_box = signs_lib.yard_sign_model.nodebox,
        selection_box = {
                type = "fixed",
                fixed = {-0.4375, -0.5, -0.0625, 0.4375, 0.375, 0}
        },
-    tiles = {"signs_top.png", "signs_bottom.png", "signs_side.png", "signs_side.png", "signs_back.png", "signs_front.png"},
-    groups = {choppy=2, dig_immediate=2},
-    drop = default_sign,
-
-    on_construct = function(pos)
-        signs_lib.construct_sign(pos)
-    end,
-    on_destruct = function(pos)
-        signs_lib.destruct_sign(pos)
-    end,
+       tiles = {"signs_top.png", "signs_bottom.png", "signs_side.png", "signs_side.png", "signs_back.png", "signs_front.png"},
+       groups = {choppy=2, dig_immediate=2},
+       drop = default_sign,
+
+       on_construct = function(pos)
+               signs_lib.construct_sign(pos)
+       end,
+       on_destruct = function(pos)
+               signs_lib.destruct_sign(pos)
+       end,
        on_receive_fields = function(pos, formname, fields, sender)
                signs_lib.receive_fields(pos, formname, fields, sender)
        end,
        on_punch = function(pos, node, puncher)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end,
+       on_rotate = signs_lib.facedir_rotate_simple
+
 })
 
 minetest.register_node(":signs:sign_hanging", {
-    paramtype = "light",
+       paramtype = "light",
        sunlight_propagates = true,
-    paramtype2 = "facedir",
-    drawtype = "nodebox",
-    node_box = signs_lib.hanging_sign_model.nodebox,
-    selection_box = {
+       paramtype2 = "facedir",
+       drawtype = "nodebox",
+       node_box = signs_lib.hanging_sign_model.nodebox,
+       selection_box = {
                type = "fixed",
                fixed = {-0.45, -0.275, -0.049, 0.45, 0.5, 0.049}
        },
-    tiles = {
+       tiles = {
                "signs_hanging_top.png",
                "signs_hanging_bottom.png",
                "signs_hanging_side.png",
@@ -704,30 +781,31 @@ minetest.register_node(":signs:sign_hanging", {
                "signs_hanging_back.png",
                "signs_hanging_front.png"
        },
-    groups = {choppy=2, dig_immediate=2},
-    drop = default_sign,
-
-    on_construct = function(pos)
-        signs_lib.construct_sign(pos)
-    end,
-    on_destruct = function(pos)
-        signs_lib.destruct_sign(pos)
-    end,
+       groups = {choppy=2, dig_immediate=2},
+       drop = default_sign,
+
+       on_construct = function(pos)
+               signs_lib.construct_sign(pos)
+       end,
+       on_destruct = function(pos)
+               signs_lib.destruct_sign(pos)
+       end,
        on_receive_fields = function(pos, formname, fields, sender)
                signs_lib.receive_fields(pos, formname, fields, sender)
        end,
        on_punch = function(pos, node, puncher)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end,
+       on_rotate = signs_lib.facedir_rotate_simple
 })
 
 minetest.register_node(":signs:sign_post", {
-    paramtype = "light",
+       paramtype = "light",
        sunlight_propagates = true,
-    paramtype2 = "facedir",
-    drawtype = "nodebox",
-    node_box = signs_lib.sign_post_model.nodebox,
-    tiles = {
+       paramtype2 = "facedir",
+       drawtype = "nodebox",
+       node_box = signs_lib.sign_post_model.nodebox,
+       tiles = {
                "signs_post_top.png",
                "signs_post_bottom.png",
                "signs_post_side.png",
@@ -735,22 +813,23 @@ minetest.register_node(":signs:sign_post", {
                "signs_post_back.png",
                "signs_post_front.png",
        },
-    groups = {choppy=2, dig_immediate=2},
-    drop = {
+       groups = {choppy=2, dig_immediate=2},
+       drop = {
                max_items = 2,
                items = {
                        { items = { default_sign }},
                        { items = { "default:fence_wood" }},
                },
-    },
+       },
+       on_rotate = signs_lib.facedir_rotate_simple
 })
 
 -- Locked wall sign
 
-minetest.register_privilege("sign_editor", "Can edit all locked signs")
+minetest.register_privilege("sign_editor", S("Can edit all locked signs"))
 
 minetest.register_node(":locked_sign:sign_wall_locked", {
-       description = S("Sign"),
+       description = S("Locked Sign"),
        inventory_image = "signs_locked_inv.png",
        wield_image = "signs_locked_inv.png",
        node_placement_prediction = "",
@@ -774,49 +853,41 @@ minetest.register_node(":locked_sign:sign_wall_locked", {
                local meta = minetest.get_meta(pos)
                local owner = meta:get_string("owner")
                local pname = sender:get_player_name() or ""
-               if pname ~= owner and pname ~= minetest.setting_get("name")
+               if pname ~= owner and pname ~= minetest.settings:get("name")
                  and not minetest.check_player_privs(pname, {sign_editor=true}) then
                        return
                end
                signs_lib.receive_fields(pos, formname, fields, sender, true)
        end,
        on_punch = function(pos, node, puncher)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end,
        can_dig = function(pos, player)
                local meta = minetest.get_meta(pos)
                local owner = meta:get_string("owner")
                local pname = player:get_player_name()
-               return pname == owner or pname == minetest.setting_get("name")
+               return pname == owner or pname == minetest.settings:get("name")
                        or minetest.check_player_privs(pname, {sign_editor=true})
        end,
        on_rotate = signs_lib.wallmounted_rotate
 })
 
--- metal, colored signs
-
-local sign_colors = { "green", "yellow", "red", "white_red", "white_black", "orange", "blue", "brown" }
+-- default metal sign, if defined
 
-for _, color in ipairs(sign_colors) do
-       minetest.register_node(":signs:sign_wall_"..color, {
-               description = S("Sign ("..color..", metal)"),
-               inventory_image = "signs_"..color.."_inv.png",
-               wield_image = "signs_"..color.."_inv.png",
+if minetest.registered_nodes["default:sign_wall_steel"] then
+       minetest.register_node(":"..default_sign_metal, {
+               description = S("Sign"),
+               inventory_image = default_sign_metal_image,
+               wield_image = default_sign_metal_image,
                node_placement_prediction = "",
-               paramtype = "light",
                sunlight_propagates = true,
-               paramtype2 = "facedir",
+               paramtype = "light",
+               paramtype2 = "wallmounted",
                drawtype = "nodebox",
-               node_box = signs_lib.metal_wall_sign_model.nodebox,
-               tiles = {
-                       "signs_metal_tb.png",
-                       "signs_metal_tb.png",
-                       "signs_metal_sides.png",
-                       "signs_metal_sides.png",
-                       "signs_metal_back.png",
-                       "signs_"..color.."_front.png"
-               },
+               node_box = signs_lib.regular_wall_sign_model.nodebox,
+               tiles = {"signs_wall_sign_metal.png"},
                groups = sign_groups,
+
                on_place = function(itemstack, placer, pointed_thing)
                        return signs_lib.determine_sign_type(itemstack, placer, pointed_thing)
                end,
@@ -830,27 +901,84 @@ for _, color in ipairs(sign_colors) do
                        signs_lib.receive_fields(pos, formname, fields, sender)
                end,
                on_punch = function(pos, node, puncher)
-                       signs_lib.update_sign(pos)
+                       signs_lib.update_sign(pos,nil,nil,node)
                end,
+               on_rotate = signs_lib.wallmounted_rotate
        })
 end
 
+-- metal, colored signs
+if enable_colored_metal_signs then
+       -- array : color, translated color, default text color
+       local sign_colors = {
+               {"green",        S("green"),       "f"},
+               {"yellow",       S("yellow"),      "0"},
+               {"red",          S("red"),         "f"},
+               {"white_red",    S("white_red"),   "4"},
+               {"white_black",  S("white_black"), "0"},
+               {"orange",       S("orange"),      "0"},
+               {"blue",         S("blue"),        "f"},
+               {"brown",        S("brown"),       "f"},
+       }
+
+       for i, color in ipairs(sign_colors) do
+               minetest.register_node(":signs:sign_wall_"..color[1], {
+                       description = S("Sign (@1, metal)", color[2]),
+                       inventory_image = "signs_"..color[1].."_inv.png",
+                       wield_image = "signs_"..color[1].."_inv.png",
+                       node_placement_prediction = "",
+                       paramtype = "light",
+                       sunlight_propagates = true,
+                       paramtype2 = "facedir",
+                       drawtype = "nodebox",
+                       node_box = signs_lib.metal_wall_sign_model.nodebox,
+                       tiles = {
+                               "signs_metal_tb.png",
+                               "signs_metal_tb.png",
+                               "signs_metal_sides.png",
+                               "signs_metal_sides.png",
+                               "signs_metal_back.png",
+                               "signs_"..color[1].."_front.png"
+                       },
+                       default_color = color[3],
+                       groups = sign_groups,
+                       on_place = function(itemstack, placer, pointed_thing)
+                               return signs_lib.determine_sign_type(itemstack, placer, pointed_thing)
+                       end,
+                       on_construct = function(pos)
+                               signs_lib.construct_sign(pos)
+                       end,
+                       on_destruct = function(pos)
+                               signs_lib.destruct_sign(pos)
+                       end,
+                       on_receive_fields = function(pos, formname, fields, sender)
+                               signs_lib.receive_fields(pos, formname, fields, sender)
+                       end,
+                       on_punch = function(pos, node, puncher)
+                               signs_lib.update_sign(pos,nil,nil,node)
+                       end,
+                       on_rotate = signs_lib.facedir_rotate
+               })
+       end
+end
+
 local signs_text_on_activate
 
 signs_text_on_activate = function(self)
-       local meta = minetest.get_meta(self.object:getpos())
+       local pos = self.object:getpos()
+       local meta = minetest.get_meta(pos)
        local text = meta:get_string("text")
        local new = (meta:get_int("__signslib_new_format") ~= 0)
-       if text then
+       if text and minetest.registered_nodes[minetest.get_node(pos).name] then
                text = trim_input(text)
-               set_obj_text(self.object, text, new)
+               set_obj_text(self.object, text, new, pos)
        end
 end
 
 minetest.register_entity(":signs:text", {
-    collisionbox = { 0, 0, 0, 0, 0, 0 },
-    visual = "upright_sprite",
-    textures = {},
+       collisionbox = { 0, 0, 0, 0, 0, 0 },
+       visual = "upright_sprite",
+       textures = {},
 
        on_activate = signs_text_on_activate,
 })
@@ -858,17 +986,17 @@ minetest.register_entity(":signs:text", {
 -- And the good stuff here! :-)
 
 function signs_lib.register_fence_with_sign(fencename, fencewithsignname)
-    local def = minetest.registered_nodes[fencename]
-    local def_sign = minetest.registered_nodes[fencewithsignname]
-    if not (def and def_sign) then
-        minetest.log("warning", "[signs_lib] Attempt to register unknown node as fence")
-        return
-    end
-    def = signs_lib.table_copy(def)
-    def_sign = signs_lib.table_copy(def_sign)
-    fences_with_sign[fencename] = fencewithsignname
-
-    def_sign.on_place = function(itemstack, placer, pointed_thing, ...)
+       local def = minetest.registered_nodes[fencename]
+       local def_sign = minetest.registered_nodes[fencewithsignname]
+       if not (def and def_sign) then
+               minetest.log("warning", "[signs_lib] "..S("Attempt to register unknown node as fence"))
+               return
+       end
+       def = signs_lib.table_copy(def)
+       def_sign = signs_lib.table_copy(def_sign)
+       fences_with_sign[fencename] = fencewithsignname
+
+       def_sign.on_place = function(itemstack, placer, pointed_thing, ...)
                local node_above = minetest.get_node_or_nil(pointed_thing.above)
                local node_under = minetest.get_node_or_nil(pointed_thing.under)
                local def_above = node_above and minetest.registered_nodes[node_above.name]
@@ -887,7 +1015,7 @@ function signs_lib.register_fence_with_sign(fencename, fencewithsignname)
                end
 
                if def_under and def_under.on_rightclick then
-                       return def_under.on_rightclick(pointed_thing.under, node_under, placer, itemstack) or itemstack
+                       return def_under.on_rightclick(pointed_thing.under, node_under, placer, itemstack, pointed_thing) or itemstack
                elseif def_under and def_under.buildable_to then
                        minetest.add_node(pointed_thing.under, {name = fencename, param2 = fdir})
                        if not signs_lib.expect_infinite_stacks then
@@ -913,18 +1041,20 @@ function signs_lib.register_fence_with_sign(fencename, fencewithsignname)
                signs_lib.receive_fields(pos, formname, fields, sender)
        end
        def_sign.on_punch = function(pos, node, puncher, ...)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end
        local fencename = fencename
        def_sign.after_dig_node = function(pos, node, ...)
-           node.name = fencename
-           minetest.add_node(pos, node)
+               node.name = fencename
+               minetest.add_node(pos, node)
        end
-    def_sign.drop = default_sign
+       def_sign.on_rotate = signs_lib.facedir_rotate_simple
+
+       def_sign.drop = default_sign
        minetest.register_node(":"..fencename, def)
        minetest.register_node(":"..fencewithsignname, def_sign)
        table.insert(signs_lib.sign_node_list, fencewithsignname)
-       minetest.log("debug", S("Registered %s and %s"):format(fencename, fencewithsignname))
+       minetest.log("verbose", S("Registered @1 and @2", fencename, fencewithsignname))
 end
 
 build_char_db()
@@ -934,168 +1064,161 @@ minetest.register_alias("sign_wall_locked", "locked_sign:sign_wall_locked")
 
 signs_lib.register_fence_with_sign("default:fence_wood", "signs:sign_post")
 
--- restore signs' text after /clearobjects and the like
+-- restore signs' text after /clearobjects and the like, the next time
+-- a block is reloaded by the server.
 
-minetest.register_abm({
+minetest.register_lbm({
        nodenames = signs_lib.sign_node_list,
-       interval = 15,
-       chance = 1,
-       action = function(pos, node, active_object_count, active_object_count_wider)
-               signs_lib.update_sign(pos)
+       name = "signs_lib:restore_sign_text",
+       label = "Restore sign text",
+       run_at_every_load = true,
+       action = function(pos, node)
+               signs_lib.update_sign(pos,nil,nil,node)
        end
 })
 
 -- locked sign
 
 minetest.register_craft({
-       output = "locked_sign:sign_wall_locked",
-       recipe = {
-               {"group:wood", "group:wood", "group:wood"},
-               {"group:wood", "group:wood", "default:steel_ingot"},
-               {"", "group:stick", ""},
-       }
-})
-
---Alternate recipe.
-
-minetest.register_craft({
-       output = "locked_sign:sign_wall_locked",
-       recipe = {
-               {default_sign},
-               {"default:steel_ingot"},
-    },
+               output = "locked_sign:sign_wall_locked",
+               recipe = {
+                       {default_sign},
+                       {"default:steel_ingot"},
+       },
 })
 
 -- craft recipes for the metal signs
+if enable_colored_metal_signs then
 
-minetest.register_craft( {
-        output = "signs:sign_wall_green 4",
-        recipe = {
-                       { "dye:dark_green", "dye:white", "dye:dark_green" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_green",
+               recipe = {
+                               { "dye:dark_green", "dye:white", "dye:dark_green" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_green 2",
-        recipe = {
-                       { "dye:dark_green", "dye:white", "dye:dark_green" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_green 2",
+               recipe = {
+                               { "dye:dark_green", "dye:white", "dye:dark_green" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_yellow 4",
-        recipe = {
-                       { "dye:yellow", "dye:black", "dye:yellow" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_yellow",
+               recipe = {
+                               { "dye:yellow", "dye:black", "dye:yellow" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_yellow 2",
-        recipe = {
-                       { "dye:yellow", "dye:black", "dye:yellow" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_yellow 2",
+               recipe = {
+                               { "dye:yellow", "dye:black", "dye:yellow" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_red 4",
-        recipe = {
-                       { "dye:red", "dye:white", "dye:red" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_red",
+               recipe = {
+                               { "dye:red", "dye:white", "dye:red" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_red 2",
-        recipe = {
-                       { "dye:red", "dye:white", "dye:red" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_red 2",
+               recipe = {
+                               { "dye:red", "dye:white", "dye:red" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_white_red 4",
-        recipe = {
-                       { "dye:white", "dye:red", "dye:white" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_white_red",
+               recipe = {
+                               { "dye:white", "dye:red", "dye:white" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_white_red 2",
-        recipe = {
-                       { "dye:white", "dye:red", "dye:white" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_white_red 2",
+               recipe = {
+                               { "dye:white", "dye:red", "dye:white" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_white_black 4",
-        recipe = {
-                       { "dye:white", "dye:black", "dye:white" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_white_black",
+               recipe = {
+                               { "dye:white", "dye:black", "dye:white" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_white_black 2",
-        recipe = {
-                       { "dye:white", "dye:black", "dye:white" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_white_black 2",
+               recipe = {
+                               { "dye:white", "dye:black", "dye:white" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_orange 4",
-        recipe = {
-                       { "dye:orange", "dye:black", "dye:orange" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_orange",
+               recipe = {
+                               { "dye:orange", "dye:black", "dye:orange" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_orange 2",
-        recipe = {
-                       { "dye:orange", "dye:black", "dye:orange" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_orange 2",
+               recipe = {
+                               { "dye:orange", "dye:black", "dye:orange" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_blue 4",
-        recipe = {
-                       { "dye:blue", "dye:white", "dye:blue" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_blue",
+               recipe = {
+                               { "dye:blue", "dye:white", "dye:blue" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_blue 2",
-        recipe = {
-                       { "dye:blue", "dye:white", "dye:blue" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_blue 2",
+               recipe = {
+                               { "dye:blue", "dye:white", "dye:blue" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_brown 4",
-        recipe = {
-                       { "dye:brown", "dye:white", "dye:brown" },
-                       { "default:steel_ingot", "default:steel_ingot", "default:steel_ingot" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_brown",
+               recipe = {
+                               { "dye:brown", "dye:white", "dye:brown" },
+                               { "", default_sign_metal, "" }
+               },
+       })
 
-minetest.register_craft( {
-        output = "signs:sign_wall_brown 2",
-        recipe = {
-                       { "dye:brown", "dye:white", "dye:brown" },
-                       { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
-        },
-})
+       minetest.register_craft( {
+               output = "signs:sign_wall_brown 2",
+               recipe = {
+                               { "dye:brown", "dye:white", "dye:brown" },
+                               { "steel:sheet_metal", "steel:sheet_metal", "steel:sheet_metal" }
+               },
+       })
+end
 
-if minetest.setting_get("log_mods") then
-       minetest.log("action", S("signs loaded"))
+if minetest.settings:get("log_mods") then
+       minetest.log("action", S("[MOD] signs loaded"))
 end