From d4b9918ed42f0888ee17dc351606742e8fd6ca06 Mon Sep 17 00:00:00 2001 From: Michieal Date: Sun, 23 Oct 2022 03:20:34 -0400 Subject: [PATCH] Added in Documentation, changed the inventory image to be more minecraft-like (hand made), changed some licensing, and tracked down an out of place debug log line. --- mods/ITEMS/mcl_signs/README.txt | 7 +- mods/ITEMS/mcl_signs/SIGNS_API_DOC.txt | 122 +++++ mods/ITEMS/mcl_signs/init.lua | 14 +- mods/ITEMS/mcl_signs/signs_api.lua | 515 ++++++++++++++++-- .../ITEMS/mcl_signs/textures/default_sign.png | Bin 243 -> 5305 bytes .../mcl_signs/textures/default_sign_dark.png | Bin 746 -> 5459 bytes .../textures/default_sign_greyscale.png | Bin 717 -> 5286 bytes 7 files changed, 608 insertions(+), 50 deletions(-) create mode 100644 mods/ITEMS/mcl_signs/SIGNS_API_DOC.txt diff --git a/mods/ITEMS/mcl_signs/README.txt b/mods/ITEMS/mcl_signs/README.txt index a5887f2a2..5ef65481c 100644 --- a/mods/ITEMS/mcl_signs/README.txt +++ b/mods/ITEMS/mcl_signs/README.txt @@ -23,7 +23,12 @@ License of code and font: MIT License Font source: 04.jp.org, some modifications and additions were made (added support for Latin-1 Supplement) Original font license text states: “YOU MAY USE THEM AS YOU LIKE” (in about.gif file distributed with the font) -License of textures: See README.md in top directory of MineClone 2. +License of textures: See README.md in top directory of MineClone 2, with the exception of the following: +default_sign.png, default_sign_dark.png, default_sign_greyscale.png, mcl_signs_sign_dark.png, +mcl_signs_sign_greyscale.png are licensed as follows: +Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) (https://creativecommons.org/licenses/by-sa/4.0/). +Credit Michieal (Faerraven). The extra sign textures are provided for you to use, modify, etc., with the goal being to +make the game better. (All of these textures were changed / created by me, to make them usable / better.) License of models: GPLv3 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/mods/ITEMS/mcl_signs/SIGNS_API_DOC.txt b/mods/ITEMS/mcl_signs/SIGNS_API_DOC.txt new file mode 100644 index 000000000..e98741137 --- /dev/null +++ b/mods/ITEMS/mcl_signs/SIGNS_API_DOC.txt @@ -0,0 +1,122 @@ +--- +--- Generated by EmmyLua. +--- Created by Michieal (FaerRaven). +--- DateTime: 10/22/22 3:44 PM +--- + +SIGNS API + +--- How to Use: + +The simplest way to create a new sign is to use mcl_signs.register_sign [mcl_signs.register_sign (modname, color, _name, +ttsign)]. It's an all-in-one sign creator. It makes use of the standard textures for the signs, and colors them based on +the color code that you give it, and names it "mcl_signs:wall_sign" + _name. So, using the spruce sign to illustrate, it +would be named "mcl_signs:wall_sign_sprucewood", as we made _name equal to "_sprucewood" after the name of the +registered wood. + +To create a sign with specific textures: use the mcl_signs.register_sign_custom [mcl_signs.register_sign_custom +(modname, _name, tiles, color, inventory_image, wield_image, ttsign)]. Like the register_sign() function, this is also an +all-in-one sign creation function. With this function you can designate what textures to use, and give them a specified +color. This function follows the same naming conventions. + +If you wish to override / recreate one of the predefined signs, you may also do that. The reregister_sign() and +reregister_sign_custom() functions will replace an existing sign's definition with a new one. Caution, ONLY use this on +existing signs. If the sign doesn't exist, use the regular register_sign* functions. + +--- What the parameters mean, and what they do: + +* modname: optional (pass "" or "false" to ignore), for using mcl_signs with other mods to allow the creation of a sign +from the mod's wood (if installed). Use this to prevent failures of the specific mod is not installed that has the needed +information (textures, wood, etc.) Setting this is important, because it prevents items from being registered if the +mod in not installed. + +* tiles: the texture file to use for the sign's node. + +* color: color the texture file to use with this color. Use white (#FFFFFF) to negate the color, and just use the +texture as is. + +* inventory_image: the texture file to use for the sign's display in inventory. + +* wield_image: the texture file to use for the sign's weilded (in hand) object. + +* _name: the sign's name suffix, such as "_dark" or "_sprucewood", etc., appended to "wall_sign" or "standing_sign" + +* ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. ttsign stands +for translated tooltip sign. + +* wood_item_string: example: "mcl_core:wood", "mcl_core:sprucewood" or "mymod:mywood". This is used when defining the +recipe for the sign. + +--- Other Functions of Importance: + +* register_dye [mcl_signs.register_dye (modname, item_name, color_code)] -- this registers a new dye that the sign knows +about so that the player can color their signs with the dye. +Parameters: + modname: your mod / module's name. make sure to use this for compatibility. + item_name: the item_string of the dye to register. + color_code: the hex code for the color to make the lettering. Also called HTML color code. Ex. "#FFFFFF" is white. + +* register_sign_craft [mcl_signs.register_sign_craft(modname, wood_item_string, _name)] -- this is what creates the +recipes for the sign, and makes the sign "burnable". Typically called right after the register_sign* functions. +Parameters: + _name: MUST be the same name as used for the sign. So, if your sign _name is "_sprucewood" then this should be too. + wood_item_string: the item_string of the wood to use for the sign's recipe. Example: "mcl_core:wood" (default oak). + modname: like with the other functions that has this parameter, used to make sure that nothing breaks. + +* make_lbm() [mcl_signs.make_lbm()] -- This innocuous function is very important. This is the function that makes the +signs work after reloading the game. This function is the last to be called in your sign creation work flow. Note, you +do not need to call this function after every definition, just at the end of the last definition. +(See Example WorkFlow below.) + +--- Example Workflow for sign creation. + +* these are, at the time of writing, a selection of the actual signs' definitions. Note the functions called, and when. + +-- ---------------------------- -- +-- Register Signs for use. -- +-- ---------------------------- -- + +-- sprucewood Sign +mcl_signs.register_sign_custom("mcl_core", "_sprucewood", + "mcl_signs_sign_dark.png","#ffffff", "default_sign_dark.png", + "default_sign_dark.png", "Spruce Sign" +) +mcl_signs.register_sign_craft("mcl_core", "mcl_core:sprucewood", "_sprucewood") + +-- darkwood Sign +mcl_signs.register_sign_custom("mcl_core", "_darkwood", + "mcl_signs_sign_greyscale.png","#856443", "default_sign_greyscale.png", + "default_sign_greyscale.png", "Dark Oak Sign" +) +mcl_signs.register_sign_craft("mcl_core", "mcl_core:darkwood", "_darkwood") + +-- acaciawood Sign +mcl_signs.register_sign("mcl_core", "#ea7479", "_acaciawood", "Acacia Sign") +mcl_signs.register_sign_craft("mcl_core", "mcl_core:acaciawood", "_acaciawood") + +-- junglewood Sign +mcl_signs.register_sign("mcl_core", "#866249", "_junglewood", "Jungle Sign") +mcl_signs.register_sign_craft("mcl_core", "mcl_core:junglewood", "_junglewood") + +-- Register the LBMs for the created signs. +mcl_signs.make_lbm() + +--- ----------------------------------------------------------------------------- + +* If you wish to use a recipe other than the standard sign recipe, you will need to define your own recipe. In doing so, +use this output line: + output = "mcl_signs:wall_sign" .. _name .. " 3", +where _name is the same string that you have used throughout your sign's workflow. That way, when players make the recipe, +they get your sign (x3). + +--- Future landmarks on the horizon for the Signs API: + +* Once the forthcoming Hanging Signs are in Minecraft, and we implement the code for them in here, hanging signs will +automatically exist as part of the signs' package. You won't have to change any of your code, it'll just be more +functional. :) + +* if you have suggestions, comments, etc., please contact me on MineClone 2's Discord server. + +And that... is all there is to it! + +-- written by Michieal. \ No newline at end of file diff --git a/mods/ITEMS/mcl_signs/init.lua b/mods/ITEMS/mcl_signs/init.lua index d07b36a65..6643b978a 100644 --- a/mods/ITEMS/mcl_signs/init.lua +++ b/mods/ITEMS/mcl_signs/init.lua @@ -1,5 +1,5 @@ --- ---- Generated by EmmyLua(https://github.com/EmmyLua) +--- Generated by EmmyLua. --- Created by Michieal (FaerRaven). --- DateTime: 10/14/22 4:05 PM --- @@ -25,6 +25,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) +-- This defines the text entity for the lettering of the sign. -- FIXME: Prevent entity destruction by /clearobjects minetest.register_entity("mcl_signs:text", { pointable = false, @@ -90,19 +91,16 @@ mcl_signs.build_signs_info() -- ---------------------------- -- -- Register Signs for use. -- -- ---------------------------- -- -local mcl_colors_official = mcl_colors -- Standard (original) Sign mcl_signs.register_sign("mcl_core", "#ffffff", "", "Sign") mcl_signs.register_sign_craft("mcl_core", "mcl_core:wood", "") --- birchwood Sign ---mcl_signs.register_sign("mcl_core", "#d5cb8d", "_birchwood", "Birch Sign") +-- birchwood Sign "#d5cb8d" / "#ffdba7" mcl_signs.register_sign_custom("mcl_core", "_birchwood", - "mcl_signs_sign_greyscale.png",mcl_colors_official.YELLOW, "default_sign_greyscale.png", + "mcl_signs_sign_greyscale.png","#ffdba7", "default_sign_greyscale.png", "default_sign_greyscale.png", "Birch Sign" ) - mcl_signs.register_sign_craft("mcl_core", "mcl_core:birchwood", "_birchwood") -- sprucewood Sign @@ -112,13 +110,11 @@ mcl_signs.register_sign_custom("mcl_core", "_sprucewood", ) mcl_signs.register_sign_craft("mcl_core", "mcl_core:sprucewood", "_sprucewood") --- darkwood Sign ---mcl_signs.register_sign("mcl_core","#291f1a", "_darkwood", "Dark Oak Sign") +-- darkwood Sign "#291f1a" / "#856443" mcl_signs.register_sign_custom("mcl_core", "_darkwood", "mcl_signs_sign_greyscale.png","#856443", "default_sign_greyscale.png", "default_sign_greyscale.png", "Dark Oak Sign" ) - mcl_signs.register_sign_craft("mcl_core", "mcl_core:darkwood", "_darkwood") -- junglewood Sign diff --git a/mods/ITEMS/mcl_signs/signs_api.lua b/mods/ITEMS/mcl_signs/signs_api.lua index 0931e419f..b5643a1c2 100644 --- a/mods/ITEMS/mcl_signs/signs_api.lua +++ b/mods/ITEMS/mcl_signs/signs_api.lua @@ -1,5 +1,5 @@ --- ---- Generated by EmmyLua(https://github.com/EmmyLua) +--- Generated by EmmyLua. --- Created by Michieal (FaerRaven). --- DateTime: 10/14/22 4:05 PM --- @@ -439,6 +439,43 @@ mcl_signs.standing_standard = { _mcl_blast_resistance = 1, } +-- HELPER FUNCTIONS' VARIABLES +local sign_glow = 6 +local Dyes_table = { + { "mcl_dye:aqua", mcl_colors_official.AQUA }, + { "mcl_dye:black", mcl_colors_official.BLACK }, + { "mcl_dye:blue", mcl_colors_official.BLUE }, + { "mcl_dye:brown", mcl_colors_official.brown }, + { "mcl_dye:cyan", mcl_signs.mcl_wool_colors.unicolor_cyan }, + { "mcl_dye:green", mcl_colors_official.GREEN }, + { "mcl_dye:dark_green", mcl_colors_official.DARK_GREEN }, + { "mcl_dye:grey", mcl_colors_official.GRAY }, + { "mcl_dye:dark_grey", mcl_colors_official.DARK_GRAY }, + { "mcl_dye:lightblue", mcl_signs.mcl_wool_colors.unicolor_light_blue }, + { "mcl_dye:lime", mcl_signs.unicolor_green_or_lime }, + { "mcl_dye:magenta", mcl_colors_official.LIGHT_PURPLE }, + { "mcl_dye:orange", mcl_signs.mcl_wool_colors.unicolor_orange }, + { "mcl_dye:pink", mcl_signs.mcl_wool_colors.unicolor_light_red_pink }, + { "mcl_dye:purple", mcl_colors_official.LIGHT_PURPLE }, + { "mcl_dye:red", mcl_signs.mcl_wool_colors.unicolor_red }, + { "mcl_dye:silver", mcl_signs.mcl_wool_colors.unicolor_grey }, + { "mcl_dye:violet", mcl_colors_official.DARK_PURPLE }, + { "mcl_dye:white", mcl_colors_official.WHITE }, + { "mcl_dye:yellow", mcl_colors_official.YELLOW }, +} + +local function update_sign_registry(type, name) + if type == "wall" then + table.insert(mcl_signs.registered_signs.wall_signs, name) + end + if type == "standing" then + table.insert(mcl_signs.registered_signs.standing_signs, name) + end + if type == "hanging" then + table.insert(mcl_signs.registered_signs.hanging_signs, name) + end +end + function mcl_signs.make_lbm() local registered_sign_nodenames = {} @@ -468,49 +505,12 @@ function mcl_signs.make_lbm() end --- HELPER FUNCTIONS' VARIABLES -local sign_glow = 6 -local Dyes_table = { - { "mcl_dye:aqua", mcl_colors_official.AQUA }, - { "mcl_dye:black", mcl_colors_official.BLACK }, - { "mcl_dye:blue", mcl_colors_official.BLUE }, - { "mcl_dye:brown", mcl_colors_official.brown }, - { "mcl_dye:cyan", mcl_signs.mcl_wool_colors.unicolor_cyan }, - { "mcl_dye:green", mcl_colors_official.GREEN }, - { "mcl_dye:dark_green", mcl_colors_official.DARK_GREEN }, - { "mcl_dye:grey", mcl_colors_official.GRAY }, - { "mcl_dye:dark_grey", mcl_colors_official.DARK_GRAY }, - { "mcl_dye:lightblue", mcl_signs.mcl_wool_colors.unicolor_light_blue }, - { "mcl_dye:lime", mcl_signs.unicolor_green_or_lime }, - { "mcl_dye:magenta", mcl_colors_official.LIGHT_PURPLE }, - { "mcl_dye:orange", mcl_signs.mcl_wool_colors.unicolor_orange }, - { "mcl_dye:pink", mcl_signs.mcl_wool_colors.unicolor_light_red_pink }, - { "mcl_dye:purple", mcl_colors_official.LIGHT_PURPLE }, - { "mcl_dye:red", mcl_signs.mcl_wool_colors.unicolor_red }, - { "mcl_dye:silver", mcl_signs.mcl_wool_colors.unicolor_grey }, - { "mcl_dye:violet", mcl_colors_official.DARK_PURPLE }, - { "mcl_dye:white", mcl_colors_official.WHITE }, - { "mcl_dye:yellow", mcl_colors_official.YELLOW }, -} - function mcl_signs.register_dye (modname, item_name, color_code) if minetest.get_modpath(modname) then table.insert(Dyes_table, { item_name, color_code }) end end -local function update_sign_registry(type, name) - if type == "wall" then - table.insert(mcl_signs.registered_signs.wall_signs, name) - end - if type == "standing" then - table.insert(mcl_signs.registered_signs.standing_signs, name) - end - if type == "hanging" then - table.insert(mcl_signs.registered_signs.hanging_signs, name) - end -end - --- Register a new sign, tint the textures, and gives it an unique node name. Creates both wall and standing signs. --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). @@ -738,7 +738,6 @@ end --- --- modname: optional (pass "" or "false" to ignore), for use with other mods to --- allow the creation of a sign from the mod's wood (if installed). ---- type: "wall", "standing". --- --- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" --- @@ -948,6 +947,442 @@ function mcl_signs.register_sign_custom (modname, _name, tiles, color, inventory end +--- Override an existing sign, tint the textures, and gives it an unique node name. Creates both wall and standing signs. +--- modname: optional (pass "" or "false" to ignore), for use with other mods to +--- allow the creation of a sign from the mod's wood (if installed). +--- +--- color: the color code to color the base sign textures. must be a valid html color code. +--- +--- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" +--- +--- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. +--- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" +function mcl_signs.reregister_sign (modname, color, _name, ttsign) + local mod_name_pass = false + if modname ~= "" and modname ~= "false" then + if minetest.get_modpath(modname) then + mod_name_pass = true + end + if mod_name_pass == false then + return + end + end + local new_sign = {} + + if color == nil or color == "" then + color = "#FFFFFF" + end + + new_sign = table.copy(mcl_signs.wall_standard) + new_sign.description = S(ttsign) + + new_sign.wield_image = "(default_sign.png^[multiply:" .. color .. ")" + new_sign.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } + new_sign.inventory_image = "(default_sign.png^[multiply:" .. color .. ")" + + -- currently have to do this, because of how the base node placement works. + new_sign.on_place = function(itemstack, placer, pointed_thing) + local above = pointed_thing.above + local under = pointed_thing.under + + -- Use pointed node's on_rightclick function first, if present + local node_under = minetest.get_node(under) + if placer and not placer:get_player_control().sneak then + if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then + return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack + end + end + + local dir = vector.subtract(under, above) + + -- Only build when it's legal + local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] + if not abovenodedef or abovenodedef.buildable_to == false then + return itemstack + end + + local wdir = minetest.dir_to_wallmounted(dir) + local fdir = minetest.dir_to_facedir(dir) + + local sign_info + local nodeitem = ItemStack(itemstack) + -- Ceiling + if wdir == 0 then + --how would you add sign to ceiling? + return itemstack + -- Floor + elseif wdir == 1 then + -- Standing sign + + -- Determine the sign rotation based on player's yaw + local yaw = pi * 2 - placer:get_look_horizontal() + + -- Select one of 16 possible rotations (0-15) + local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) + + if rotation_level > 15 then + rotation_level = 0 + elseif rotation_level < 0 then + rotation_level = 15 + end + + -- The actual rotation is a combination of predefined mesh and facedir (see node definition) + if rotation_level % 4 == 0 then + nodeitem:set_name("mcl_signs:standing_sign" .. _name) + elseif rotation_level % 4 == 1 then + nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) + elseif rotation_level % 4 == 2 then + nodeitem:set_name("mcl_signs:standing_sign45" .. _name) + elseif rotation_level % 4 == 3 then + nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) + end + fdir = math.floor(rotation_level / 4) + + -- Place the node! + local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) + if not success then + return itemstack + end + if not minetest.is_creative_enabled(placer:get_player_name()) then + itemstack:take_item() + end + sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] + -- Side + else + -- Wall sign + local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) + if not success then + return itemstack + end + sign_info = mcl_signs.signtext_info_wall[fdir + 1] + end + + -- Determine spawn position of entity + local place_pos + if minetest.registered_nodes[node_under.name].buildable_to then + place_pos = under + else + place_pos = above + end + + if DEBUG then + minetest.log("action", "[mcl_signs] Register_Sign::Placed position:" .. dump(place_pos) .. "\nSign_info: " .. dump(sign_info)) + end + + local text_entity = minetest.add_entity({ + x = place_pos.x + sign_info.delta.x, + y = place_pos.y + sign_info.delta.y, + z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") + text_entity:set_yaw(sign_info.yaw) + text_entity:get_luaentity()._signnodename = nodeitem:get_name() + + minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) + + mcl_signs:show_formspec(placer, place_pos) + return itemstack + end + + minetest.override_item("mcl_signs:wall_sign" .. _name, new_sign) + update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) + + -- debug step + if DEBUG then + minetest.log("action", "[mcl_signs] Registered: mcl_signs:wall_sign" .. _name .. color .. "\n" .. dump(new_sign)) + minetest.log("action", "[mcl_signs] mcl_signs:wall_sign_standard\n" .. dump(mcl_signs.wall_standard)) + end + + -- standing sign base. + local new_sign_standing = {} + new_sign_standing = table.copy(mcl_signs.standing_standard) + new_sign_standing.drop = "mcl_signs:wall_sign" .. _name + new_sign_standing.wield_image = "(default_sign.png^[multiply:" .. color .. ")" + new_sign_standing.tiles = { "(mcl_signs_sign.png^[multiply:" .. color .. ")" } + new_sign_standing.inventory_image = "(default_sign.png^[multiply:" .. color .. ")" + minetest.override_item("mcl_signs:standing_sign" .. _name, new_sign_standing) + update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) + -- debug step + if DEBUG then + minetest.log("action", "[mcl_signs] Registered: mcl_signs:standing_sign" .. _name .. color .. "\n" .. dump(new_sign_standing)) + end + + -- 22.5° + local ssign22_5d = table.copy(new_sign_standing) + ssign22_5d.mesh = "mcl_signs_sign22.5.obj" + ssign22_5d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign45" .. _name + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign22_5" .. _name, ssign22_5d) + update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) + + -- 45° + local ssign45d = table.copy(new_sign_standing) + ssign45d.mesh = "mcl_signs_sign45.obj" + ssign45d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign67_5" .. _name + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign45" .. _name, ssign45d) + update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) + + -- 67.5° + local ssign67_5d = table.copy(new_sign_standing) + ssign67_5d.mesh = "mcl_signs_sign67.5.obj" + ssign67_5d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign" .. _name + node.param2 = (node.param2 + 1) % 4 + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign67_5" .. _name, ssign67_5d) + update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) + + -- register Doc entry + if minetest.get_modpath("doc") then + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) + end + + --register standing sign's rotation_levels + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign22_5" .. _name , 1}) + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign45" .. _name , 2}) + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign67_5" .. _name , 3}) +end + +--- The same as reregister_sign, except caller defines the textures. Note, there is a greyscale version of the sign, +--- called "default_sign_greyscale.png" and "mcl_signs_sign_greyscale.png" for optional use in the textures directory. +--- +--- modname: optional (pass "" or "false" to ignore), for use with other mods to +--- allow the creation of a sign from the mod's wood (if installed). +--- +--- _name: the sign's name suffix, such as "_dark" or "_red", etc., appended to "wall_sign" or "standing_sign" +--- +--- tiles: the texture file to use for the sign. +--- +--- color: color the texture file to use with this color. Use white (#FFFFFF) to negate the color, +--- and just use the texture as is +--- +--- inventory_image: the texture file to use for the sign's display in inventory. +--- +--- wield_image: the texture file to use for the sign's weilded (in hand) object. +--- +--- inventory_image: the image used for in-inventory and in hand. +--- +--- ttsign: the tool tip of the sign that gets translated. Shown when the mouse hovers the inventory sign. +--- For example: the basic, default oak (wood) sign is just "Sign"; and a spruce sign would be "Spruce Sign" +function mcl_signs.reregister_sign_custom (modname, _name, tiles, color, inventory_image, wield_image, ttsign) + local mod_name_pass = false + if modname ~= "" and modname ~= "false" then + if minetest.get_modpath(modname) then + mod_name_pass = true + end + if mod_name_pass == false then + return + end + end + local new_sign = {} + + new_sign = table.copy(mcl_signs.wall_standard) + + new_sign.wield_image ="("..wield_image.."^[multiply:" .. color .. ")" + new_sign.tiles = { "("..tiles.."^[multiply:" .. color .. ")" } + new_sign.inventory_image = "("..inventory_image.."^[multiply:" .. color .. ")" + new_sign.description = S(ttsign) + -- currently have to do this, because of how the base node placement works. + new_sign.on_place = function(itemstack, placer, pointed_thing) + local above = pointed_thing.above + local under = pointed_thing.under + + -- Use pointed node's on_rightclick function first, if present + local node_under = minetest.get_node(under) + if placer and not placer:get_player_control().sneak then + if minetest.registered_nodes[node_under.name] and minetest.registered_nodes[node_under.name].on_rightclick then + return minetest.registered_nodes[node_under.name].on_rightclick(under, node_under, placer, itemstack) or itemstack + end + end + + local dir = vector.subtract(under, above) + + -- Only build when it's legal + local abovenodedef = minetest.registered_nodes[minetest.get_node(above).name] + if not abovenodedef or abovenodedef.buildable_to == false then + return itemstack + end + + local wdir = minetest.dir_to_wallmounted(dir) + local fdir = minetest.dir_to_facedir(dir) + + local sign_info + local nodeitem = ItemStack(itemstack) + -- Ceiling + if wdir == 0 then + --how would you add sign to ceiling? + return itemstack + -- Floor + elseif wdir == 1 then + -- Standing sign + + -- Determine the sign rotation based on player's yaw + local yaw = pi * 2 - placer:get_look_horizontal() + + -- Select one of 16 possible rotations (0-15) + local rotation_level = mcl_signs:round((yaw / (pi * 2)) * 16) + + if rotation_level > 15 then + rotation_level = 0 + elseif rotation_level < 0 then + rotation_level = 15 + end + + -- The actual rotation is a combination of predefined mesh and facedir (see node definition) + if rotation_level % 4 == 0 then + nodeitem:set_name("mcl_signs:standing_sign" .. _name) + elseif rotation_level % 4 == 1 then + nodeitem:set_name("mcl_signs:standing_sign22_5" .. _name) + elseif rotation_level % 4 == 2 then + nodeitem:set_name("mcl_signs:standing_sign45" .. _name) + elseif rotation_level % 4 == 3 then + nodeitem:set_name("mcl_signs:standing_sign67_5" .. _name) + end + fdir = math.floor(rotation_level / 4) + + -- Place the node! + local _, success = minetest.item_place_node(nodeitem, placer, pointed_thing, fdir) + if not success then + return itemstack + end + if not minetest.is_creative_enabled(placer:get_player_name()) then + itemstack:take_item() + end + sign_info = mcl_signs.signtext_info_standing[rotation_level + 1] + -- Side + else + -- Wall sign + local _, success = minetest.item_place_node(itemstack, placer, pointed_thing, wdir) + if not success then + return itemstack + end + sign_info = mcl_signs.signtext_info_wall[fdir + 1] + end + + -- Determine spawn position of entity + local place_pos + if minetest.registered_nodes[node_under.name].buildable_to then + place_pos = under + else + place_pos = above + end + + local text_entity = minetest.add_entity({ + x = place_pos.x + sign_info.delta.x, + y = place_pos.y + sign_info.delta.y, + z = place_pos.z + sign_info.delta.z }, "mcl_signs:text") + text_entity:set_yaw(sign_info.yaw) + text_entity:get_luaentity()._signnodename = nodeitem:get_name() + + minetest.sound_play({ name = "default_place_node_hard", gain = 1.0 }, { pos = place_pos }, true) + + mcl_signs:show_formspec(placer, place_pos) + return itemstack + end + minetest.override_item("mcl_signs:wall_sign" .. _name, new_sign) + update_sign_registry("wall", "mcl_signs:wall_sign" .. _name) + + -- standing sign base. + local new_sign_standing = {} + new_sign_standing = table.copy(mcl_signs.standing_standard) + new_sign_standing.drop = "mcl_signs:wall_sign" .. _name + new_sign_standing.wield_image ="("..wield_image.."^[multiply:" .. color .. ")" + new_sign_standing.tiles = { "("..tiles.."^[multiply:" .. color .. ")" } + new_sign_standing.inventory_image = "("..inventory_image.."^[multiply:" .. color .. ")" + minetest.override_item("mcl_signs:standing_sign" .. _name, new_sign_standing) + update_sign_registry("standing", "mcl_signs:standing_sign" .. _name) + + -- 22.5° + local ssign22_5d = table.copy(new_sign_standing) + ssign22_5d.mesh = "mcl_signs_sign22.5.obj" + ssign22_5d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign45" .. _name + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign22_5" .. _name, ssign22_5d) + update_sign_registry("standing", "mcl_signs:standing_sign22_5" .. _name) + + -- 45° + local ssign45d = table.copy(new_sign_standing) + ssign45d.mesh = "mcl_signs_sign45.obj" + ssign45d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign67_5" .. _name + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign45" .. _name, ssign45d) + update_sign_registry("standing", "mcl_signs:standing_sign45" .. _name) + + -- 67.5° + local ssign67_5d = table.copy(new_sign_standing) + ssign67_5d.mesh = "mcl_signs_sign67.5.obj" + ssign67_5d.on_rotate = function(pos, node, user, mode) + if mode == screwdriver.ROTATE_FACE then + node.name = "mcl_signs:standing_sign" .. _name + node.param2 = (node.param2 + 1) % 4 + minetest.swap_node(pos, node) + elseif mode == screwdriver.ROTATE_AXIS then + return false + end + mcl_signs:update_sign(pos, nil, nil, true) + return true + end + minetest.override_item("mcl_signs:standing_sign67_5" .. _name, ssign67_5d) + update_sign_registry("standing", "mcl_signs:standing_sign67_5" .. _name) + + -- register Doc entry + if minetest.get_modpath("doc") then + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:wall_sign" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign22_5" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign45" .. _name) + doc.add_entry_alias("nodes", "mcl_signs:wall_sign", "nodes", "mcl_signs:standing_sign67_5" .. _name) + end + + --register standing sign's rotation_levels + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign22_5" .. _name , 1}) + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign45" .. _name , 2}) + table.insert(mcl_signs.standing_rotation_levels, {"mcl_signs:standing_sign67_5" .. _name , 3}) + +end + --- Usage: Call this with the mod's name, the wood's item string (for the planks), and with the sign's suffix. --- Registers the crafting recipe for that sign. for every registered sign, call this function to register the --- standard recipe for the sign. Otherwise, you have to do your own register craft call. @@ -1037,7 +1472,7 @@ local function get_rotation_level(facedir, nodename) end end rl = facedir * 4 + offset - if 1 == 1 then + if DEBUG then minetest.log("action", "[mcl_signs] GetRotationLevel: NodeName: " .. nodename .. " RL value: " .. rl) end return rl diff --git a/mods/ITEMS/mcl_signs/textures/default_sign.png b/mods/ITEMS/mcl_signs/textures/default_sign.png index 077983118274db82bad1d7abca17690112131857..8fcee7e9fb1a247f26a17bf4cc5eaa0c94c9d02e 100644 GIT binary patch literal 5305 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 ZmE-0ubBlZZT3evC44$rjF6*2UngG1rNMHZ} diff --git a/mods/ITEMS/mcl_signs/textures/default_sign_dark.png b/mods/ITEMS/mcl_signs/textures/default_sign_dark.png index aedab6f06e72414bebd70305b6a0a014289b1800..016098238767b45fac28853f80e92d5c8e6d063a 100644 GIT binary patch literal 5459 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 aaR>#w%mt2j7Y4!WeD%U@Rj delta 709 zcmV;$0y_QED(VH0BYy#IX+uL$X=7sm04R}lkvmHRK@^2Q;}ahUY9V5gLd7D%pdgkS z3!5Mk6?`?>&2A#>Cd=*y3ATcbgAJbdL320{@?fK zXi6KN4pj}p!@A@8!lS~872i?3A>5&7Q)%IS;fN~-6uwZpR^~^=nKHjBc4v~~5K=wE znIEkEU_I;F!u`TMwpGx-&!cYAY~*IArFO~e#v{oDal&X6SjNI9Dm5pW{q2i=`6kJW zN0+}t5my`;vVY=@h+2@YhE!8@Lq3b5%Kdkqo;fsF?%o`S+J_)`>4o|&C~XG8$3YO3 z4x#!U&TLkJ)o00009aFg^C5`O_ANklc8|q_!jV z*>~?H3a}wsI$V#gig1fHh*+p94?PCP+EuMohFB`x+&;F5Zpc|~i2J8EbFqHe4x4<> z%yakfQu0N~QGXrgd4`Wkg3FTwNKp>cJ&P!sSNYLyh$LMsFav^ZR!P;cazcIyl8XFtdLMc53=hRr#cz*rD#qnO#LjRPTq7RPG zNZ_y=7!}r9T|uuCG`L!Uyb+_{9hNZ)Hi rW$poFosD%0$fiG&bHFrF_;>sO#k+pA`kJR300000NkvXXu0mjfi7!!c diff --git a/mods/ITEMS/mcl_signs/textures/default_sign_greyscale.png b/mods/ITEMS/mcl_signs/textures/default_sign_greyscale.png index 2809447aa851e062d15eb42ccb2816fb22f49a46..570851a6a2a6a6003b01e81b437cdecf189c41c4 100644 GIT binary patch literal 5286 zcmeHKc{r478=px^)25PC(=n!#60z#R@=eh6Sec!+Pe(ql%nL!u4sZ7m&}MWj?rK7Gb$}U!FzYuv>_Hx$du#TO$V#yl=nMHnKe- zAig%CHrcx9{MNoW;y&MU)55hrqeHD*UI`uL3Nu~yv|Eq-r&WGTT@haLoJb2L>D5&i zWzO5v-g7jb$CdTA`29r<-&Q>!+99V}#5uKRiEaU$gtpVsTI3 z>$wl|Cs;W&-7l`$8#*)cdeXGc;>e|&kG!Bo4I+C>Ez09#EdG3Xem1&mvCF4irS+d3 zt!G=k?)8=C_b$2ll9~2F_suEg zCGxwT9sKjVC%un$9hqpXteW#WHV?aOhhM@b*}M!SJni+xd~D_GhpQ7zb?&Vv9run! zyj`AnIyJZVazoOiAZL^ZeL_pge_rq3?cUl&eZY5<&N`I8eL3Agk*!xPb`@e5{8@_m3*92?G^usKS!4Dq6Q zyJNQmW)khs!taiPIVsGrw0w3Ka`t?|C^cUp@Rjd%>BvaTi?EVo=m% z!9MsDR)k3rs}OGXM*Cg1<*}V5MXFg-j?G@enStDztQ)d{*DcCvexPj6*>#5bzNtUz;f(H{j}s{6*>H@mk)(i&{?^sFke7%k_4h%<0c3iKw$KSnIHET|Rvw%0PGEc8b!xm{e-S zNFFwAO&ppd88~@kKfEpDMq6OGb-`{y?&(62hYu9M-SSu_85{ zbqwa=?$psZYnzZ0ri8lI8ik*5>B-RfwkK2-L}kp+q&Gr;crXbumgJG38lYRBjdxTMz6`& zA_>d?8Y-Au&8Z(enp#m~!E)>JU&QPfjmulJfpgb?(P(q*o!Vr9SCw(r2PfMNx872% zGa4sStOzAYo7AOdG~b2_QbhFKIV&$&qC5}kq=g-~HPkYXNJ*bVF-&|Os!AT_F1uv^ zo|$Us)Za7NigfMoVc(JLVXMjHMvy{F4}`(sJ3t#7CytHH=RN~eae- z?1Colp@<{7tyhs2aYbZA)Zb2 z;H0Jyi;k`TVJ$)^_^L};%c@|HO15;PS{y+kn1Q}eLIv{u6H~$&++$DUfiX9`*`wKxhLzy|-|6ek}a-M1^^^1C(9oo}3j+wBfbJ;Dke?TF~D^fWam zY+j3~iF`lr`Uita6Dn60Jf*c?-@SeXe5B!W+T($YyvqYiU#6YVr%$+07M0L_;>0U> z#)_4n_8J{5G5r7{Dv-U~?AlY|VUnm0zpCMuxfeUnfgz5(1EZ3gc`p)*MT9Bim^PQln-E4Vi|NWz+e_uDj84U4=7Q5zz38t z(Qhg*p;4faiQYir;<+*#z!$U+lLPC+99;xq{sOuXZDonDP%$6?F`(q3RN?@Mf}vuf zHMk7uT|JFMqckE)ex8nA$^jG^OUB|cwkj}~h_*zaEaXBF!D)KIuU=O@k? zP)LL10>CyHkSG^_3n3JI(U%3u12o|X1vnr85JRF0$SUDGldCvfr!N|63VcAZOrr&n z{hg!|6n!P@JKxkRnsB~#1XBNk`plnOv0L-Wcf z6Da~RUxX3x_~sZgUqHanDHIWgLM4a@Bm$K{14Q3IaU=>QPa*)+P!Kp4gm6TBGLJwe z3ozznstAJMkuiLMh=38&g?K8#oFXJsfo~wz%0Z|qc>&*grG^qhP$UsuBqGqvF(kT3 z?F~T2&}cL|hAyP=1b8}?2Msh(LIJ~0Di`yhbb?}@4}gHP&x=tYgjRq78!$uD9lv25iR2slUt6f5=H8tgpvKUK>J*a>rLe&*NUi0gL zz_HQT76p4MG|`}zX{a>$-j@(x zK+O{#+S>#?hDdZF&>3VZ15d%=$qYOmjT;Xbr{2|{BeuZ(4<{BHfp6LXq&GGPwHK&c z;l8x1an95<{)?aST>Og`An2b)eu&?nbp533hZy)F;h)v@ldd0P;D>~NR@eWHF2vUh z4T%dC7h2u9Jp{=Pye`}D#Z=yc-1GC(@^KY5PiG*bqIaiz z-n) zz>D6ju+}-ATAka?NOiW{Che`T(eW+-kgFb+X&(`LHV0`R0T+}u`xcz)UJx0yiTMUY zI~AGXp9uFpU|eEWdH>;HR*Bj6-dBwt%i^O$52ZK{kxZ7XHc55PY&V^FcOz-qcAQc_ zQ|OQ3Ho}}-=RTwH3r36X4vs!Cc5GxH>a6b{0f5efZTi+3nWOOIU>Nv!>xiknNm6Hj zXzL#_A;LYsZkyBoByd%2;48!KCEA^rdix>|%T{=M=zm-!-J71YVs6z*F+>@RW9!I1 IW9=RNUjvmLng9R* delta 694 zcmV;n0!jU*Da{3tBYy#IX+uL$X=7sm04R}lk-bYoQ5eR5YGJ4mR6|68gGGZv6hvd$ z;36Srkkz8suR!f`uM*N4v@{3}QA=M#|3R%mYe5hcK}1u3KwnG9?L8V8q33e$`{Oz1 zc{%4fU=QcDg4r<+g<{EwhJxOu__Ejeii=*{I2lf8ral{qgnwx}zV5N9dKXZ=+V5*Q z+^Mvwfvrn;O4E&!@QiSHqoga|5$@M=iInh>u-}ja3STQd+29w&*#>_oHe%5^u&bWl z>>p14VJ&AAgvW$^g?w52J&(GHCtX}zkUA)H2$Luwf_O<%W{o^00#b{TS!>^T-8av= zcr^LzR4~MmC4VPgzo=#DnwFXoJuP3Jipu?eo@QopqS4(GgwAKndLIGjF4U@)^?htv zwG(hW!DX@OUzePwKSi%LHQyohY{B_eQ%ml_#WoB)>IoxJmmD(fnGC$0L3bSbZo#$E z$m(~U(+7xc$`jqd{sD~2{+`tzugGWReOc+(00009aDPZya{vGf5&!@T5&_cPe*6Fc z0R>4!K~y-)wNt&Sg)j_`QpBG@LGc9?boZ5fEZ@e-!NuLtO+i5sML3t_lG0xEoZ)ak zuqOT5Sh#}TqDlfiI~G0(HK!!U$x+w=gQ=SisumWxtpkq{6BftHyQ3AIiJO1+y` zZ7sks4CGAHL}hRZEFH6BiHN@MAxRRwgfvZo|F|iRV^YDTsS2Vf(r(FQ=kLk;zW*p+ zT}ypX6vb_mH(`r!`dr(XZ0!2I?xy$!Ig cEBrft01*d%>;`QcuK)l507*qoM6N<$f?dl^lmGw#