mirror of
https://git.minetest.land/VoxeLibre/VoxeLibre.git
synced 2025-04-23 07:35:16 +02:00
Decouple mcl_signs/init.lua
This commit is contained in:
parent
723814acd6
commit
02de0103b1
2 changed files with 410 additions and 407 deletions
407
mods/ITEMS/mcl_signs/api.lua
Normal file
407
mods/ITEMS/mcl_signs/api.lua
Normal file
|
@ -0,0 +1,407 @@
|
|||
local function table_merge(t, ...)
|
||||
local t2 = table.copy(t)
|
||||
return table.update(t2, ...)
|
||||
end
|
||||
|
||||
local SIGN_WIDTH = 115
|
||||
|
||||
local LINE_LENGTH = 15
|
||||
local NUMBER_OF_LINES = 4
|
||||
|
||||
local LINE_HEIGHT = 14
|
||||
local CHAR_WIDTH = 5
|
||||
|
||||
local DEFAULT_COLOR = "#000000"
|
||||
|
||||
local SIGN_GLOW_INTENSITY = 14
|
||||
|
||||
local S = core.get_translator(core.get_current_modname())
|
||||
local F = core.formspec_escape
|
||||
|
||||
-- Template definition
|
||||
local sign_tpl = {
|
||||
_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."),
|
||||
use_texture_alpha = "opaque",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
is_ground_content = false,
|
||||
paramtype2 = "degrotate",
|
||||
drawtype = "mesh",
|
||||
mesh = "mcl_signs_sign.obj",
|
||||
paramtype = "light",
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.2, -0.5, -0.2, 0.2, 0.5, 0.2}
|
||||
},
|
||||
groups = {axey = 1, handy = 2, sign = 1, not_in_creative_inventory = 1},
|
||||
stack_max = 16,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
node_placement_prediction = "",
|
||||
_mcl_sign_type = "standing"
|
||||
}
|
||||
|
||||
-- Signs data / meta
|
||||
local function normalize_rotation(rot)
|
||||
return math.floor(0.5 + rot / 15) * 15
|
||||
end
|
||||
|
||||
local function get_signdata(pos)
|
||||
local node = core.get_node(pos)
|
||||
local def = core.registered_nodes[node.name]
|
||||
if not def or core.get_item_group(node.name, "sign") < 1 then return end
|
||||
local meta = core.get_meta(pos)
|
||||
local text = meta:get_string("text")
|
||||
local color = meta:get_string("color")
|
||||
local glow = meta:get_string("glow")
|
||||
if glow == "true" then
|
||||
glow = true
|
||||
else
|
||||
glow = false
|
||||
end
|
||||
local yaw, spos
|
||||
local typ = "standing"
|
||||
if def.paramtype2 == "wallmounted" then
|
||||
typ = "wall"
|
||||
local dir = core.wallmounted_to_dir(node.param2)
|
||||
spos = vector.add(vector.offset(pos,0,-0.25,0),dir * 0.41 )
|
||||
yaw = core.dir_to_yaw(dir)
|
||||
else
|
||||
yaw = math.rad(((node.param2 * 1.5 ) + 1 ) % 360)
|
||||
local dir = core.yaw_to_dir(yaw)
|
||||
spos = vector.add(vector.offset(pos,0,0.08,0),dir * -0.05)
|
||||
end
|
||||
if color == "" then color = DEFAULT_COLOR end
|
||||
return {
|
||||
text = text,
|
||||
color = color,
|
||||
yaw = yaw,
|
||||
node = node,
|
||||
typ = typ,
|
||||
glow = glow,
|
||||
text_pos = spos,
|
||||
}
|
||||
end
|
||||
|
||||
local function set_signmeta(pos,def)
|
||||
local meta = core.get_meta(pos)
|
||||
if def.text then meta:set_string("text",def.text) end
|
||||
if def.color then meta:set_string("color",def.color) end
|
||||
if def.glow then meta:set_string("glow",def.glow) end
|
||||
end
|
||||
|
||||
-- Text/texture
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
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.
|
||||
assert(chars_file, "mcl_signs/characters.txt not found")
|
||||
|
||||
local charmap = {}
|
||||
while true do
|
||||
local char = chars_file:read("*l")
|
||||
if char == nil then
|
||||
break
|
||||
end
|
||||
local img = chars_file:read("*l")
|
||||
local _ = chars_file:read("*l")
|
||||
charmap[char] = img
|
||||
end
|
||||
|
||||
local function string_to_line_array(str)
|
||||
local linechar_table = {}
|
||||
local current = 1
|
||||
local linechar = 1
|
||||
local cr_last = false
|
||||
linechar_table[current] = ""
|
||||
for char in str:gmatch(".") do
|
||||
local add
|
||||
local is_cr, is_lf = char == "\r", char == "\n"
|
||||
|
||||
if is_cr and not cr_last then
|
||||
cr_last = true
|
||||
add = false
|
||||
elseif is_lf or cr_last or linechar > 15 then
|
||||
cr_last = is_cr
|
||||
add = not (is_cr or is_lf)
|
||||
current = current + 1
|
||||
linechar_table[current] = ""
|
||||
linechar = 1
|
||||
else
|
||||
add = true
|
||||
end
|
||||
|
||||
if add then
|
||||
linechar_table[current] = linechar_table[current] .. char
|
||||
linechar = linechar + 1
|
||||
end
|
||||
end
|
||||
return linechar_table
|
||||
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
|
||||
-- Use replacement character:
|
||||
file = "_rc"
|
||||
i = i + 1
|
||||
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 _, file in ipairs(parsed) do
|
||||
texture = texture .. ":" .. xpos .. "," .. ypos .. "=" .. file.. ".png"
|
||||
xpos = xpos + printed_char_width
|
||||
end
|
||||
return texture
|
||||
end
|
||||
|
||||
function mcl_signs.generate_texture(data)
|
||||
local lines = mcl_signs.create_lines(data.text or "")
|
||||
local texture = "[combine:" .. SIGN_WIDTH .. "x" .. SIGN_WIDTH
|
||||
local ypos = 0
|
||||
local letter_color = data.color or DEFAULT_COLOR
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
texture = texture .. mcl_signs.generate_line(line, ypos)
|
||||
ypos = ypos + LINE_HEIGHT
|
||||
end
|
||||
|
||||
texture = "(" .. texture .. "^[multiply:" .. letter_color .. ")"
|
||||
return texture
|
||||
end
|
||||
|
||||
function sign_tpl.on_place(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local under = pointed_thing.under
|
||||
local node = core.get_node(under)
|
||||
local def = core.registered_nodes[node.name]
|
||||
if not def then return itemstack end
|
||||
|
||||
if mcl_util.call_on_rightclick(itemstack, placer, pointed_thing) then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local above = pointed_thing.above
|
||||
local dir = vector.subtract(under, above)
|
||||
local wdir = core.dir_to_wallmounted(dir)
|
||||
|
||||
local itemstring = itemstack:get_name()
|
||||
local placestack = ItemStack(itemstack)
|
||||
local def = itemstack:get_definition()
|
||||
|
||||
local pos
|
||||
-- place on wall
|
||||
if wdir ~= 0 and wdir ~= 1 then
|
||||
placestack:set_name("mcl_signs:wall_sign_"..def._mcl_sign_wood)
|
||||
itemstack, pos = core.item_place_node(placestack, placer, pointed_thing, wdir)
|
||||
elseif wdir == 1 then -- standing, not ceiling
|
||||
placestack:set_name("mcl_signs:standing_sign_"..def._mcl_sign_wood)
|
||||
-- param2 value is degrees / 1.5
|
||||
local rot = normalize_rotation(placer:get_look_horizontal() * 180 / math.pi / 1.5)
|
||||
itemstack, pos = core.item_place_node(placestack, placer, pointed_thing, rot)
|
||||
else
|
||||
return itemstack
|
||||
end
|
||||
|
||||
mcl_signs.show_formspec(placer, pos)
|
||||
itemstack:set_name(itemstring)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function sign_tpl.on_rightclick(pos, _, clicker, itemstack)
|
||||
if itemstack:get_name() == "mcl_mobitems:glow_ink_sac" then
|
||||
local data = get_signdata(pos)
|
||||
if data then
|
||||
if data.color == "#000000" then
|
||||
data.color = "#7e7e7e" --black doesn't glow in the dark
|
||||
end
|
||||
set_signmeta(pos, {glow ="true", color = data.color})
|
||||
mcl_signs.update_sign(pos)
|
||||
if not core.is_creative_enabled(clicker:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
end
|
||||
elseif not mcl_util.check_position_protection(pos, clicker) then
|
||||
mcl_signs.show_formspec(clicker, pos)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function sign_tpl.on_destruct(pos)
|
||||
mcl_signs.get_text_entity(pos, true)
|
||||
end
|
||||
|
||||
function sign_tpl._on_dye_place(pos, color)
|
||||
set_signmeta(pos,{
|
||||
color = mcl_dyes.colors[color].rgb
|
||||
})
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
|
||||
local sign_wall = table_merge(sign_tpl, {
|
||||
mesh = "mcl_signs_signonwallmount.obj",
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = {-0.5, -7/28, -0.5, -23/56, 7/28, 0.5}
|
||||
},
|
||||
groups = {axey = 1, handy = 2, sign = 1},
|
||||
_mcl_sign_type = "wall",
|
||||
})
|
||||
|
||||
-- Formspec
|
||||
function mcl_signs.show_formspec(player, pos)
|
||||
if not pos then return end
|
||||
local old_text = core.get_meta(pos):get_string("text")
|
||||
core.show_formspec(player:get_player_name(), "mcl_signs:set_text_"..pos.x.."_"..pos.y.."_"..pos.z, table.concat({
|
||||
"size[6,3]textarea[0.25,0.25;6,1.5;text;",
|
||||
F(S("Enter sign text:")), ";", core.formspec_escape(old_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
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname:find("mcl_signs:set_text_") == 1 then
|
||||
local x, y, z = formname:match("mcl_signs:set_text_(.-)_(.-)_(.*)")
|
||||
local pos = vector.new(tonumber(x), tonumber(y), tonumber(z))
|
||||
if not fields or not fields.text then return end
|
||||
if not mcl_util.check_position_protection(pos, player) then
|
||||
set_signmeta(pos, {
|
||||
-- limit saved text to 256 characters
|
||||
-- (4 lines x 15 chars = 60 so this should be more than is ever needed)
|
||||
text = tostring(fields.text):sub(1, 256)
|
||||
})
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Text entity handling
|
||||
function mcl_signs.get_text_entity(pos, force_remove)
|
||||
local objects = core.get_objects_inside_radius(pos, 0.5)
|
||||
local text_entity
|
||||
local i = 0
|
||||
for _, v in pairs(objects) do
|
||||
local ent = v:get_luaentity()
|
||||
if ent and ent.name == "mcl_signs:text" then
|
||||
i = i + 1
|
||||
if i > 1 or force_remove == true then
|
||||
v:remove()
|
||||
else
|
||||
text_entity = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return text_entity
|
||||
end
|
||||
|
||||
function mcl_signs.update_sign(pos)
|
||||
local data = get_signdata(pos)
|
||||
|
||||
local text_entity = mcl_signs.get_text_entity(pos)
|
||||
if text_entity and not data then
|
||||
text_entity:remove()
|
||||
return false
|
||||
elseif not data then
|
||||
return false
|
||||
elseif not text_entity then
|
||||
text_entity = core.add_entity(data.text_pos, "mcl_signs:text")
|
||||
if not text_entity or not text_entity:get_pos() then return end
|
||||
end
|
||||
|
||||
local glow
|
||||
if data.glow then
|
||||
glow = SIGN_GLOW_INTENSITY
|
||||
end
|
||||
text_entity:set_properties({
|
||||
textures = {mcl_signs.generate_texture(data)},
|
||||
glow = glow,
|
||||
})
|
||||
text_entity:set_yaw(data.yaw)
|
||||
text_entity:set_armor_groups({immortal = 1})
|
||||
return true
|
||||
end
|
||||
|
||||
core.register_lbm({
|
||||
nodenames = {"group:sign"},
|
||||
name = "mcl_signs:restore_entities",
|
||||
label = "Restore sign text",
|
||||
run_at_every_load = true,
|
||||
action = function(pos)
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
})
|
||||
|
||||
core.register_entity("mcl_signs:text", {
|
||||
initial_properties = {
|
||||
pointable = false,
|
||||
visual = "upright_sprite",
|
||||
physical = false,
|
||||
collide_with_objects = false,
|
||||
},
|
||||
on_activate = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
mcl_signs.update_sign(pos)
|
||||
local props = self.object:get_properties()
|
||||
local t = props and props.textures
|
||||
if type(t) ~= "table" or #t == 0 then self.object:remove() end
|
||||
end,
|
||||
})
|
||||
|
||||
local function colored_texture(texture, color)
|
||||
return texture.."^[multiply:"..color
|
||||
end
|
||||
|
||||
function mcl_signs.register_sign(name, color, def)
|
||||
local newfields = {
|
||||
tiles = {colored_texture("mcl_signs_sign_greyscale.png", color)},
|
||||
inventory_image = colored_texture("mcl_signs_default_sign_greyscale.png", color),
|
||||
wield_image = colored_texture("mcl_signs_default_sign_greyscale.png", color),
|
||||
drop = "mcl_signs:wall_sign_"..name,
|
||||
_mcl_sign_wood = name,
|
||||
}
|
||||
|
||||
def = def or {}
|
||||
core.register_node(":mcl_signs:standing_sign_"..name, table_merge(sign_tpl, newfields, def))
|
||||
core.register_node(":mcl_signs:wall_sign_"..name, table_merge(sign_wall, newfields, def))
|
||||
end
|
|
@ -1,410 +1,6 @@
|
|||
mcl_signs = {}
|
||||
|
||||
local function table_merge(t, ...)
|
||||
local t2 = table.copy(t)
|
||||
return table.update(t2, ...)
|
||||
end
|
||||
|
||||
local SIGN_WIDTH = 115
|
||||
|
||||
local LINE_LENGTH = 15
|
||||
local NUMBER_OF_LINES = 4
|
||||
|
||||
local LINE_HEIGHT = 14
|
||||
local CHAR_WIDTH = 5
|
||||
|
||||
local DEFAULT_COLOR = "#000000"
|
||||
|
||||
local SIGN_GLOW_INTENSITY = 14
|
||||
|
||||
local S = core.get_translator(core.get_current_modname())
|
||||
local F = core.formspec_escape
|
||||
|
||||
-- Template definition
|
||||
local sign_tpl = {
|
||||
_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."),
|
||||
use_texture_alpha = "opaque",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
is_ground_content = false,
|
||||
paramtype2 = "degrotate",
|
||||
drawtype = "mesh",
|
||||
mesh = "mcl_signs_sign.obj",
|
||||
paramtype = "light",
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-0.2, -0.5, -0.2, 0.2, 0.5, 0.2}
|
||||
},
|
||||
groups = {axey = 1, handy = 2, sign = 1, not_in_creative_inventory = 1},
|
||||
stack_max = 16,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
node_placement_prediction = "",
|
||||
_mcl_sign_type = "standing"
|
||||
}
|
||||
|
||||
-- Signs data / meta
|
||||
local function normalize_rotation(rot)
|
||||
return math.floor(0.5 + rot / 15) * 15
|
||||
end
|
||||
|
||||
local function get_signdata(pos)
|
||||
local node = core.get_node(pos)
|
||||
local def = core.registered_nodes[node.name]
|
||||
if not def or core.get_item_group(node.name, "sign") < 1 then return end
|
||||
local meta = core.get_meta(pos)
|
||||
local text = meta:get_string("text")
|
||||
local color = meta:get_string("color")
|
||||
local glow = meta:get_string("glow")
|
||||
if glow == "true" then
|
||||
glow = true
|
||||
else
|
||||
glow = false
|
||||
end
|
||||
local yaw, spos
|
||||
local typ = "standing"
|
||||
if def.paramtype2 == "wallmounted" then
|
||||
typ = "wall"
|
||||
local dir = core.wallmounted_to_dir(node.param2)
|
||||
spos = vector.add(vector.offset(pos,0,-0.25,0),dir * 0.41 )
|
||||
yaw = core.dir_to_yaw(dir)
|
||||
else
|
||||
yaw = math.rad(((node.param2 * 1.5 ) + 1 ) % 360)
|
||||
local dir = core.yaw_to_dir(yaw)
|
||||
spos = vector.add(vector.offset(pos,0,0.08,0),dir * -0.05)
|
||||
end
|
||||
if color == "" then color = DEFAULT_COLOR end
|
||||
return {
|
||||
text = text,
|
||||
color = color,
|
||||
yaw = yaw,
|
||||
node = node,
|
||||
typ = typ,
|
||||
glow = glow,
|
||||
text_pos = spos,
|
||||
}
|
||||
end
|
||||
|
||||
local function set_signmeta(pos,def)
|
||||
local meta = core.get_meta(pos)
|
||||
if def.text then meta:set_string("text",def.text) end
|
||||
if def.color then meta:set_string("color",def.color) end
|
||||
if def.glow then meta:set_string("glow",def.glow) end
|
||||
end
|
||||
|
||||
-- Text/texture
|
||||
local modpath = core.get_modpath(core.get_current_modname())
|
||||
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.
|
||||
assert(chars_file, "mcl_signs/characters.txt not found")
|
||||
|
||||
local charmap = {}
|
||||
while true do
|
||||
local char = chars_file:read("*l")
|
||||
if char == nil then
|
||||
break
|
||||
end
|
||||
local img = chars_file:read("*l")
|
||||
local _ = chars_file:read("*l")
|
||||
charmap[char] = img
|
||||
end
|
||||
|
||||
local function string_to_line_array(str)
|
||||
local linechar_table = {}
|
||||
local current = 1
|
||||
local linechar = 1
|
||||
local cr_last = false
|
||||
linechar_table[current] = ""
|
||||
for char in str:gmatch(".") do
|
||||
local add
|
||||
local is_cr, is_lf = char == "\r", char == "\n"
|
||||
|
||||
if is_cr and not cr_last then
|
||||
cr_last = true
|
||||
add = false
|
||||
elseif is_lf or cr_last or linechar > 15 then
|
||||
cr_last = is_cr
|
||||
add = not (is_cr or is_lf)
|
||||
current = current + 1
|
||||
linechar_table[current] = ""
|
||||
linechar = 1
|
||||
else
|
||||
add = true
|
||||
end
|
||||
|
||||
if add then
|
||||
linechar_table[current] = linechar_table[current] .. char
|
||||
linechar = linechar + 1
|
||||
end
|
||||
end
|
||||
return linechar_table
|
||||
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
|
||||
-- Use replacement character:
|
||||
file = "_rc"
|
||||
i = i + 1
|
||||
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 _, file in ipairs(parsed) do
|
||||
texture = texture .. ":" .. xpos .. "," .. ypos .. "=" .. file.. ".png"
|
||||
xpos = xpos + printed_char_width
|
||||
end
|
||||
return texture
|
||||
end
|
||||
|
||||
function mcl_signs.generate_texture(data)
|
||||
local lines = mcl_signs.create_lines(data.text or "")
|
||||
local texture = "[combine:" .. SIGN_WIDTH .. "x" .. SIGN_WIDTH
|
||||
local ypos = 0
|
||||
local letter_color = data.color or DEFAULT_COLOR
|
||||
|
||||
for _, line in ipairs(lines) do
|
||||
texture = texture .. mcl_signs.generate_line(line, ypos)
|
||||
ypos = ypos + LINE_HEIGHT
|
||||
end
|
||||
|
||||
texture = "(" .. texture .. "^[multiply:" .. letter_color .. ")"
|
||||
return texture
|
||||
end
|
||||
|
||||
function sign_tpl.on_place(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local under = pointed_thing.under
|
||||
local node = core.get_node(under)
|
||||
local def = core.registered_nodes[node.name]
|
||||
if not def then return itemstack end
|
||||
|
||||
if mcl_util.call_on_rightclick(itemstack, placer, pointed_thing) then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local above = pointed_thing.above
|
||||
local dir = vector.subtract(under, above)
|
||||
local wdir = core.dir_to_wallmounted(dir)
|
||||
|
||||
local itemstring = itemstack:get_name()
|
||||
local placestack = ItemStack(itemstack)
|
||||
local def = itemstack:get_definition()
|
||||
|
||||
local pos
|
||||
-- place on wall
|
||||
if wdir ~= 0 and wdir ~= 1 then
|
||||
placestack:set_name("mcl_signs:wall_sign_"..def._mcl_sign_wood)
|
||||
itemstack, pos = core.item_place_node(placestack, placer, pointed_thing, wdir)
|
||||
elseif wdir == 1 then -- standing, not ceiling
|
||||
placestack:set_name("mcl_signs:standing_sign_"..def._mcl_sign_wood)
|
||||
local rot = normalize_rotation(placer:get_look_horizontal() * 180 / math.pi / 1.5)
|
||||
itemstack, pos = core.item_place_node(placestack, placer, pointed_thing, rot) -- param2 value is degrees / 1.5
|
||||
else
|
||||
return itemstack
|
||||
end
|
||||
mcl_signs.show_formspec(placer, pos)
|
||||
itemstack:set_name(itemstring)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function sign_tpl.on_rightclick(pos, _, clicker, itemstack)
|
||||
if itemstack:get_name() == "mcl_mobitems:glow_ink_sac" then
|
||||
local data = get_signdata(pos)
|
||||
if data then
|
||||
if data.color == "#000000" then
|
||||
data.color = "#7e7e7e" --black doesn't glow in the dark
|
||||
end
|
||||
set_signmeta(pos,{glow="true",color=data.color})
|
||||
mcl_signs.update_sign(pos)
|
||||
if not core.is_creative_enabled(clicker:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
end
|
||||
elseif not mcl_util.check_position_protection(pos, clicker) then
|
||||
mcl_signs.show_formspec(clicker, pos)
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function sign_tpl.on_destruct(pos)
|
||||
mcl_signs.get_text_entity(pos, true)
|
||||
end
|
||||
|
||||
function sign_tpl._on_dye_place(pos, color)
|
||||
set_signmeta(pos,{
|
||||
color = mcl_dyes.colors[color].rgb
|
||||
})
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
|
||||
local sign_wall = table_merge(sign_tpl, {
|
||||
mesh = "mcl_signs_signonwallmount.obj",
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = {-0.5, -7/28, -0.5, -23/56, 7/28, 0.5}
|
||||
},
|
||||
groups = {axey = 1, handy = 2, sign = 1},
|
||||
_mcl_sign_type = "wall",
|
||||
})
|
||||
|
||||
-- Formspec
|
||||
function mcl_signs.show_formspec(player, pos)
|
||||
if not pos then return end
|
||||
local old_text = core.get_meta(pos):get_string("text")
|
||||
core.show_formspec(player:get_player_name(), "mcl_signs:set_text_"..pos.x.."_"..pos.y.."_"..pos.z, table.concat({
|
||||
"size[6,3]textarea[0.25,0.25;6,1.5;text;",
|
||||
F(S("Enter sign text:")), ";", core.formspec_escape(old_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
|
||||
|
||||
core.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname:find("mcl_signs:set_text_") == 1 then
|
||||
local x, y, z = formname:match("mcl_signs:set_text_(.-)_(.-)_(.*)")
|
||||
local pos = vector.new(tonumber(x), tonumber(y), tonumber(z))
|
||||
if not fields or not fields.text then return end
|
||||
if not mcl_util.check_position_protection(pos, player) then
|
||||
set_signmeta(pos, {
|
||||
-- limit saved text to 256 characters
|
||||
-- (4 lines x 15 chars = 60 so this should be more than is ever needed)
|
||||
text = tostring(fields.text):sub(1, 256)
|
||||
})
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Text entity handling
|
||||
function mcl_signs.get_text_entity(pos, force_remove)
|
||||
local objects = core.get_objects_inside_radius(pos, 0.5)
|
||||
local text_entity
|
||||
local i = 0
|
||||
for _, v in pairs(objects) do
|
||||
local ent = v:get_luaentity()
|
||||
if ent and ent.name == "mcl_signs:text" then
|
||||
i = i + 1
|
||||
if i > 1 or force_remove == true then
|
||||
v:remove()
|
||||
else
|
||||
text_entity = v
|
||||
end
|
||||
end
|
||||
end
|
||||
return text_entity
|
||||
end
|
||||
|
||||
function mcl_signs.update_sign(pos)
|
||||
local data = get_signdata(pos)
|
||||
|
||||
local text_entity = mcl_signs.get_text_entity(pos)
|
||||
if text_entity and not data then
|
||||
text_entity:remove()
|
||||
return false
|
||||
elseif not data then
|
||||
return false
|
||||
elseif not text_entity then
|
||||
text_entity = core.add_entity(data.text_pos, "mcl_signs:text")
|
||||
if not text_entity or not text_entity:get_pos() then return end
|
||||
end
|
||||
|
||||
local glow
|
||||
if data.glow then
|
||||
glow = SIGN_GLOW_INTENSITY
|
||||
end
|
||||
text_entity:set_properties({
|
||||
textures = {mcl_signs.generate_texture(data)},
|
||||
glow = glow,
|
||||
})
|
||||
text_entity:set_yaw(data.yaw)
|
||||
text_entity:set_armor_groups({immortal = 1})
|
||||
return true
|
||||
end
|
||||
|
||||
core.register_lbm({
|
||||
nodenames = {"group:sign"},
|
||||
name = "mcl_signs:restore_entities",
|
||||
label = "Restore sign text",
|
||||
run_at_every_load = true,
|
||||
action = function(pos)
|
||||
mcl_signs.update_sign(pos)
|
||||
end
|
||||
})
|
||||
|
||||
core.register_entity("mcl_signs:text", {
|
||||
initial_properties = {
|
||||
pointable = false,
|
||||
visual = "upright_sprite",
|
||||
physical = false,
|
||||
collide_with_objects = false,
|
||||
},
|
||||
on_activate = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
mcl_signs.update_sign(pos)
|
||||
local props = self.object:get_properties()
|
||||
local t = props and props.textures
|
||||
if type(t) ~= "table" or #t == 0 then self.object:remove() end
|
||||
end,
|
||||
})
|
||||
|
||||
local function colored_texture(texture, color)
|
||||
return texture.."^[multiply:"..color
|
||||
end
|
||||
|
||||
function mcl_signs.register_sign(name, color, def)
|
||||
local newfields = {
|
||||
tiles = {colored_texture("mcl_signs_sign_greyscale.png", color)},
|
||||
inventory_image = colored_texture("mcl_signs_default_sign_greyscale.png", color),
|
||||
wield_image = colored_texture("mcl_signs_default_sign_greyscale.png", color),
|
||||
drop = "mcl_signs:wall_sign_"..name,
|
||||
_mcl_sign_wood = name,
|
||||
}
|
||||
|
||||
def = def or {}
|
||||
core.register_node(":mcl_signs:standing_sign_"..name, table_merge(sign_tpl, newfields, def))
|
||||
core.register_node(":mcl_signs:wall_sign_"..name, table_merge(sign_wall, newfields, def))
|
||||
end
|
||||
|
||||
dofile(modpath.."/register.lua")
|
||||
dofile(modpath.."/compat.lua")
|
||||
dofile(modpath .. "/api.lua")
|
||||
dofile(modpath .. "/register.lua")
|
||||
dofile(modpath .. "/compat.lua")
|
||||
|
|
Loading…
Add table
Reference in a new issue