]> 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 804a720329a1def68713622b3e51003edd48331d..b8b4db593afca598852d4530068ee81493c41089 100644 (file)
--- a/init.lua
+++ b/init.lua
@@ -16,21 +16,57 @@ local enable_colored_metal_signs = true
 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}
@@ -113,11 +149,6 @@ signs_lib.sign_post_model = {
        }
 }
 
--- Load support for intllib.
-local MP = minetest.get_modpath(minetest.get_current_modname())
-local S, NS = dofile(MP.."/intllib.lua")
-signs_lib.gettext = S
-
 -- the list of standard sign nodes
 
 signs_lib.sign_node_list = {
@@ -153,15 +184,15 @@ 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
@@ -174,28 +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
+
+-- 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
@@ -243,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
@@ -308,6 +359,19 @@ local function fill_line(x, y, w, c)
        return table.concat(tex)
 end
 
+-- 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
@@ -344,9 +408,9 @@ local function make_line_texture(line, lineno, pos)
                                        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
@@ -387,7 +451,10 @@ local function make_line_texture(line, lineno, pos)
                        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
@@ -413,33 +480,34 @@ end
 
 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), pos)},
+               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)
@@ -452,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...
@@ -496,28 +564,14 @@ 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, pos)
-                               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)
+       local signnode = node or minetest.get_node(pos)
        local signname = signnode.name
        local textpos = minetest.registered_nodes[signname].textpos
        if textpos then
@@ -636,7 +690,7 @@ function signs_lib.receive_fields(pos, formname, fields, sender, lock)
        if fields and fields.text and fields.ok then
                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)
                ))
@@ -674,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",
@@ -725,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",
@@ -756,14 +813,15 @@ 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
@@ -802,7 +860,7 @@ minetest.register_node(":locked_sign:sign_wall_locked", {
                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)
@@ -843,7 +901,7 @@ if minetest.registered_nodes["default:sign_wall_steel"] then
                        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
        })
@@ -897,8 +955,9 @@ if enable_colored_metal_signs then
                                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
                })
        end
 end
@@ -910,16 +969,16 @@ signs_text_on_activate = function(self)
        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, 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,
 })
@@ -927,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] "..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 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]
@@ -982,14 +1041,16 @@ 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)
@@ -1012,18 +1073,18 @@ minetest.register_lbm({
        label = "Restore sign text",
        run_at_every_load = true,
        action = function(pos, node)
-               signs_lib.update_sign(pos)
+               signs_lib.update_sign(pos,nil,nil,node)
        end
 })
 
 -- locked sign
 
 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