1
0
mirror of https://github.com/mt-mods/unifieddyes.git synced 2025-06-28 14:26:21 +02:00

Compare commits

..

6 Commits

Author SHA1 Message Date
fa71e3166c allow replacement nodes during airbrushing 2018-08-26 07:23:40 -04:00
414d72d2a6 new punch-to-colorize scheme
using a tool, the airbrush, for the job

point at air/nothing and punch while wielding the airbrush
to open the color selection form.
2018-08-26 07:10:00 -04:00
568168fe1f better handling of the register_on_placenode rotation fix 2018-08-26 07:09:20 -04:00
c005dc358a minor changes to colorwallmounted palette
got rid of the separate brown swatch in the colorwallmounted palette, as
it was being bypassed by the brown-> medium orange translation --
replaced it with light green.

fixed missing colorwallmounted light blue/azure check-and-return in
get_paletteidx()
2018-08-25 02:40:17 -04:00
c7fc48c8d0 fix some broken aliases,
add some corresponding ones (unifieddyes:* vs. dye:*)
2018-08-25 00:38:24 -04:00
de5f73e976 clarify usage of make_colored_itemstack() 2018-08-24 23:53:53 -04:00
7 changed files with 333 additions and 46 deletions

11
API.md
View File

@ -13,6 +13,7 @@ minetest.register_node("mymod:colored_node", {
palette = "unifieddyes_palette_extended.png", palette = "unifieddyes_palette_extended.png",
groups = {snappy = 1, cracky = 2, ud_param2_colorable = 1} groups = {snappy = 1, cracky = 2, ud_param2_colorable = 1}
on_construct = unifieddyes.on_construct, on_construct = unifieddyes.on_construct,
airbrush_replacement_node = "mymod:my_other_colored_node"
}) })
``` ```
@ -31,6 +32,8 @@ minetest.register_node("mymod:colored_node", {
`on_construct`: see below. `on_construct`: see below.
`airbrush_replacement_node`: The node to swap in when the airbrush is used on this node. For example, you could `minetest.override_item()` on some default node to add this field, pointing to a colorable node of your own, so that when the default node is painted, it's replaced with yours in the new color.
#### Function calls #### Function calls
**`unifieddyes.fix_rotation(pos, placer, itemstack, pointed_thing)` **`unifieddyes.fix_rotation(pos, placer, itemstack, pointed_thing)`
@ -42,10 +45,6 @@ These two are used to re-orient `wallmounted` nodes after placing. The former al
This serves the same purpose as the `fix_rotation_nsew`, but is used to restrict the node's rotation after it's been hit with the screwdriver. This serves the same purpose as the `fix_rotation_nsew`, but is used to restrict the node's rotation after it's been hit with the screwdriver.
**`unifieddyes.select_node(pointed_thing)`**
Just what it says on the tin. :-) This function returns a position and node definition of whatever is being pointed at.
**`unifieddyes.is_buildable_to(placer_name, ...)`** **`unifieddyes.is_buildable_to(placer_name, ...)`**
Again, another obvious one, returns whether or not the pointed node is `buildable_to` (can be overwritten by another node). Again, another obvious one, returns whether or not the pointed node is `buildable_to` (can be overwritten by another node).
@ -77,6 +76,10 @@ When given a `color` string (in the form of "dye:foo" or "unifieddyes:foo") and
This function, called in your node definition's on_construct, just sets the `palette = "ext"` metadata key for the node after it's been placed. This can then be read in an LBM to determine if this node needs to be converted from the old 89-color palette to the extended 256-color palette. Although it is good practice to call this for any node that uses the 256-color palette, it isn't actually necessary as long as the node has never used the 89-color palette, and won't be subjected to an LBM that changes its color. This function, called in your node definition's on_construct, just sets the `palette = "ext"` metadata key for the node after it's been placed. This can then be read in an LBM to determine if this node needs to be converted from the old 89-color palette to the extended 256-color palette. Although it is good practice to call this for any node that uses the 256-color palette, it isn't actually necessary as long as the node has never used the 89-color palette, and won't be subjected to an LBM that changes its color.
**`unifieddyes.make_colored_itemstack(itemstack, palette, color)`**
Makes a colored itemstack out of the given `itemstack` and `color` (as a dye, e.g. "dye:dark_red_s50", setting the correct index per the `palette` field, which works as described above for `unifieddyes.getpaletteidx()`. Said itemstack is returned as a string suitable for use as the output field of a craft recipe, equal in size to the itemstack passed into the function (e.g. if you give it "mymod:colored_node 7", it'll return a stack of 7 colored items).
#### Tables #### Tables
In addition to the above API calls, Unified Dyes provides several useful tables In addition to the above API calls, Unified Dyes provides several useful tables

368
init.lua
View File

@ -153,6 +153,9 @@ local default_dyes = {
"yellow" "yellow"
} }
unifieddyes.player_current_dye = {}
unifieddyes.player_selected_dye = {}
-- if a node with a palette is placed in the world, -- if a node with a palette is placed in the world,
-- but the itemstack used to place it has no palette_index (color byte), -- but the itemstack used to place it has no palette_index (color byte),
-- create something appropriate to make it officially white. -- create something appropriate to make it officially white.
@ -160,26 +163,29 @@ local default_dyes = {
minetest.register_on_placenode( minetest.register_on_placenode(
function(pos, newnode, placer, oldnode, itemstack, pointed_thing) function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
local def = minetest.registered_items[newnode.name] local def = minetest.registered_items[newnode.name]
if not def or not def.palette then return false end
if string.find(itemstack:to_string(), "palette_index") then if not def
minetest.swap_node(pos, {name = newnode.name, param2 = newnode.param2}) or not def.palette
return or def.after_place_node then
return false
end end
local param2 = 0 if not string.find(itemstack:to_string(), "palette_index") then
local color = 0 local param2 = 0
local color = 0
if def.palette == "unifieddyes_palette_extended.png" then if def.palette == "unifieddyes_palette_extended.png" then
param2 = 240 param2 = 240
color = 240 color = 240
elseif def.palette == "unifieddyes_palette_colorwallmounted.png" then elseif def.palette == "unifieddyes_palette_colorwallmounted.png" then
param2 = newnode.param2 % 8 param2 = newnode.param2 % 8
elseif def.palette ~= "unifieddyes_palette.png" then -- it's a split palette elseif def.palette ~= "unifieddyes_palette.png" then -- it's a split palette
param2 = newnode.param2 % 32 param2 = newnode.param2 % 32
end
minetest.swap_node(pos, {name = newnode.name, param2 = param2})
minetest.get_meta(pos):set_int("palette_index", color)
end end
minetest.swap_node(pos, {name = newnode.name, param2 = param2})
minetest.get_meta(pos):set_int("palette_index", color)
end end
) )
@ -198,7 +204,7 @@ function unifieddyes.make_colored_itemstack(item, palette, color)
local paletteidx = unifieddyes.getpaletteidx(color, palette) local paletteidx = unifieddyes.getpaletteidx(color, palette)
local stack = ItemStack(item) local stack = ItemStack(item)
stack:get_meta():set_int("palette_index", paletteidx) stack:get_meta():set_int("palette_index", paletteidx)
return stack:to_string() return stack:to_string(),paletteidx
end end
-- if your node was once 89-color and uses an LBM to convert to the 256-color palette, -- if your node was once 89-color and uses an LBM to convert to the 256-color palette,
@ -225,7 +231,6 @@ local function register_c(craft, hue, sat, val)
end end
local dye = "dye:"..color local dye = "dye:"..color
local recipe = minetest.serialize(craft.recipe) local recipe = minetest.serialize(craft.recipe)
recipe = string.gsub(recipe, "MAIN_DYE", dye) recipe = string.gsub(recipe, "MAIN_DYE", dye)
recipe = string.gsub(recipe, "NEUTRAL_NODE", craft.neutral_node) recipe = string.gsub(recipe, "NEUTRAL_NODE", craft.neutral_node)
@ -265,6 +270,8 @@ function unifieddyes.register_color_craft(craft)
local greys_table = unifieddyes.GREYS local greys_table = unifieddyes.GREYS
if craft.palette == "wallmounted" then if craft.palette == "wallmounted" then
register_c(craft, "green", "", "light_")
register_c(craft, "azure", "", "")
hues_table = unifieddyes.HUES_WALLMOUNTED hues_table = unifieddyes.HUES_WALLMOUNTED
sats_table = {""} sats_table = {""}
vals_table = unifieddyes.VALS vals_table = unifieddyes.VALS
@ -340,19 +347,6 @@ function unifieddyes.fix_after_screwdriver_nsew(pos, node, user, mode, new_param
end end
end end
function unifieddyes.select_node(pointed_thing)
local pos = pointed_thing.under
local node = minetest.get_node_or_nil(pos)
local def = node and minetest.registered_nodes[node.name]
if not def or not def.buildable_to then
pos = pointed_thing.above
node = minetest.get_node_or_nil(pos)
def = node and minetest.registered_nodes[node.name]
end
return def and pos, def
end
function unifieddyes.is_buildable_to(placer_name, ...) function unifieddyes.is_buildable_to(placer_name, ...)
for _, pos in ipairs({...}) do for _, pos in ipairs({...}) do
local node = minetest.get_node_or_nil(pos) local node = minetest.get_node_or_nil(pos)
@ -411,6 +405,7 @@ function unifieddyes.getpaletteidx(color, palette_type)
local aliases = { local aliases = {
["pink"] = "light_red", ["pink"] = "light_red",
["brown"] = "medium_orange", ["brown"] = "medium_orange",
["azure"] = "light_blue"
} }
local grayscale = { local grayscale = {
@ -585,9 +580,10 @@ function unifieddyes.getpaletteidx(color, palette_type)
end end
if palette_type == "wallmounted" then if palette_type == "wallmounted" then
if color == "brown" then return 48,1 if color == "green" and shade == "light" then return 48,3
elseif color == "brown" then return 17,1
elseif color == "pink" then return 56,7 elseif color == "pink" then return 56,7
elseif color == "blue" and shade == "light" then return 40,5 elseif color == "azure" then return 40,5
elseif hues_wallmounted[color] and shades_wallmounted[shade] then elseif hues_wallmounted[color] and shades_wallmounted[shade] then
return (shades_wallmounted[shade] * 64 + hues_wallmounted[color] * 8), hues_wallmounted[color] return (shades_wallmounted[shade] * 64 + hues_wallmounted[color] * 8), hues_wallmounted[color]
end end
@ -599,7 +595,20 @@ function unifieddyes.getpaletteidx(color, palette_type)
color = "red" color = "red"
shade = "light" shade = "light"
end end
if palette_type == true then -- it's colorfacedir if palette_type == true then -- it's colorfacedir, so "split" 89-color palette
-- If using this palette, translate new color names back to old.
if shade == "" then
if color == "spring" then
color = "aqua"
elseif color == "azure" then
color = "skyblue"
elseif color == "rose" then
color = "redviolet"
end
end
if hues[color] and shades[shade] then if hues[color] and shades[shade] then
return (shades[shade] * 32), hues[color] return (shades[shade] * 32), hues[color]
end end
@ -607,10 +616,7 @@ function unifieddyes.getpaletteidx(color, palette_type)
if hues_extended[color] and shades_extended[shade] then if hues_extended[color] and shades_extended[shade] then
return (hues_extended[color] + shades_extended[shade]*24), hues_extended[color] return (hues_extended[color] + shades_extended[shade]*24), hues_extended[color]
end end
else -- it's the 89-color palette else -- it's the regular 89-color palette, do the same translation if needed
-- If using this palette, translate new color names back to old.
if shade == "" then if shade == "" then
if color == "spring" then if color == "spring" then
color = "aqua" color = "aqua"
@ -627,6 +633,276 @@ function unifieddyes.getpaletteidx(color, palette_type)
end end
end end
-- punch-to-recolor using the airbrush
function unifieddyes.on_airbrush(itemstack, player, pointed_thing)
local player_name = player:get_player_name()
local painting_with = nil
if unifieddyes.player_current_dye[player_name] and minetest.registered_items[unifieddyes.player_current_dye[player_name]] then
painting_with = unifieddyes.player_current_dye[player_name]
end
local pos = minetest.get_pointed_thing_position(pointed_thing)
if not pos then unifieddyes.show_airbrush_form(player) return end
if not painting_with then return end
local node = minetest.get_node(pos)
local def = minetest.registered_items[node.name]
if not def then return end
if not def.palette then
minetest.chat_send_player(player_name, "That node can't be colored.")
return
end
local palette = nil
local fdir = 0
if def.palette == "unifieddyes_palette_extended.png" then
palette = "extended"
elseif def.palette == "unifieddyes_palette_colorwallmounted.png" then
palette = "wallmounted"
fdir = node.param2 % 8
elseif def.palette ~= "unifieddyes_palette.png" then
palette = true
fdir = node.param2 % 32
end
local idx, hue = unifieddyes.getpaletteidx(painting_with, palette)
local inv = player:get_inventory()
if (not creative or not creative.is_enabled_for(player_name)) and not inv:contains_item("main", painting_with) then
local suff = ""
if not idx then
suff = " Besides, "..string.sub(painting_with, 5).." can't be applied to that node."
end
minetest.chat_send_player(player_name, "You're in survival mode, and you're out of "..string.sub(painting_with, 5).."."..suff)
return
end
if not idx then
minetest.chat_send_player(player_name, string.sub(painting_with, 5).." can't be applied to that node.")
return
end
local oldidx = node.param2 - fdir
if idx == oldidx then
minetest.chat_send_player(player_name, "That node is already "..string.sub(painting_with, 5)..".")
return
end
local name = def.airbrush_replacement_node or node.name
minetest.swap_node(pos, {name = name, param2 = fdir + idx})
if not creative or not creative.is_enabled_for(player_name) then
inv:remove_item("main", painting_with)
return
end
end
function unifieddyes.show_airbrush_form(player)
if not player then return end
local player_name = player:get_player_name()
local creative = creative and creative.is_enabled_for(player_name)
local inv = player:get_inventory()
local base_form = "size[15,8.5]label[7,-0.25;Select a color:]"
local size="0.75,0.75;"
local hps=0.6
local vps=1.3
local vs=0.3
for v = 0, 6 do
local val = unifieddyes.VALS_EXTENDED[v+1]
local sat = ""
local v2=(v/2)
for hi, h in ipairs(unifieddyes.HUES_EXTENDED) do
local hue = h[1]
local hp=hi-0.5
local r = h[2]
local g = h[3]
local b = h[4]
local factor = 40
if v > 3 then
factor = 75
v2 = (v-2)
end
local r2 = math.max(math.min(r + (4-v)*factor, 255), 0)
local g2 = math.max(math.min(g + (4-v)*factor, 255), 0)
local b2 = math.max(math.min(b + (4-v)*factor, 255), 0)
local color = string.format("%02x", r2)..string.format("%02x", g2)..string.format("%02x", b2)
local dye = "dye:"..val..hue..sat
local overlay = ""
if not creative and inv:contains_item("main", dye) then
overlay = "^unifieddyes_available_overlay.png"
end
if dye == unifieddyes.player_selected_dye[player_name] then
overlay = "^unifieddyes_select_overlay.png"
end
local colorize = minetest.formspec_escape("^[colorize:#"..color..":255")
base_form = base_form.."image_button["..
(hp*hps)..","..(v2*vps+vs)..";"..
size..
"unifieddyes_white_square.png"..colorize..overlay..";"..
val..hue..sat..";]"..
"tooltip["..val..hue..sat..";"..val..hue..sat.."]"
end
if v > 3 then
sat = "_s50"
v2 = (v-1.5)
for hi, h in ipairs(unifieddyes.HUES_EXTENDED) do
local hue = h[1]
local hp=hi-0.5
local r = h[2]
local g = h[3]
local b = h[4]
local factor = 75
local pr = 0.299
local pg = 0.587
local pb = 0.114
local r2 = math.max(math.min(r + (4-v)*factor, 255), 0)
local g2 = math.max(math.min(g + (4-v)*factor, 255), 0)
local b2 = math.max(math.min(b + (4-v)*factor, 255), 0)
local p = math.sqrt(r2*r2*pr + g2*g2*pg + b2*b2*pb)
local r3 = math.floor(p+(r2-p)*0.5)
local g3 = math.floor(p+(g2-p)*0.5)
local b3 = math.floor(p+(b2-p)*0.5)
local color = string.format("%02x", r3)..string.format("%02x", g3)..string.format("%02x", b3)
local dye = "dye:"..val..hue..sat
local overlay = ""
if not creative and inv:contains_item("main", dye) then
overlay = "^unifieddyes_available_overlay.png"
end
if dye == unifieddyes.player_selected_dye[player_name] then
overlay = "^unifieddyes_select_overlay.png"
end
local colorize = minetest.formspec_escape("^[colorize:#"..color..":255")
base_form = base_form.."image_button["..
(hp*hps)..","..(v2*vps+vs)..";"..
size..
"unifieddyes_white_square.png"..colorize..overlay..";"..
val..hue..sat..";]"..
"tooltip["..val..hue..sat..";"..val..hue..sat.."]"
end
end
end
local v2=5
for y = 0, 15 do
local hp=(15-y)+0.5
local grey = string.format("%02x", y*17)..string.format("%02x", y*17)..string.format("%02x", y*17)
local grey2 = "grey_"..y
if y == 0 then grey2 = "black"
elseif y == 4 then grey2 = "dark_grey"
elseif y == 8 then grey2 = "grey"
elseif y == 11 then grey2 = "light_grey"
elseif y == 15 then grey2 = "white"
end
local dye = "dye:"..grey2
local overlay = ""
if not creative and inv:contains_item("main", dye) then
overlay = "^unifieddyes_available_overlay.png"
end
if dye == unifieddyes.player_selected_dye[player_name] then
overlay = "^unifieddyes_select_overlay.png"
end
local colorize = minetest.formspec_escape("^[colorize:#"..grey..":255")
base_form = base_form.."image_button["..
(hp*hps)..","..(v2*vps+vs)..";"..
size..
"unifieddyes_white_square.png"..colorize..overlay..";"..
grey2..";]tooltip["..grey2..";"..grey2.."]"
end
if not creative then
base_form = base_form..
"image[10.3,"..(vps*5+vs)..";"..size..
"unifieddyes_available_overlay.png]"..
"label[11.0,"..(vps*5.1+vs)..";Dyes on hand]"..
"image[12.5,"..(vps*5+vs)..";"..size..
"unifieddyes_select_overlay.png]"..
"label[13.2,"..(vps*5.1+vs)..";Your selection]"
end
base_form = base_form..
"button_exit[11,8;2,1;cancel;Cancel]"..
"button_exit[13,8;2,1;accept;Accept]"
if unifieddyes.player_selected_dye[player_name] then
base_form = base_form..
"label[1,"..(7.5+vs)..";Selected dye: "..
unifieddyes.player_selected_dye[player_name].."]"
end
minetest.show_formspec(player_name, "unifieddyes:dye_select_form", base_form)
end
minetest.register_tool("unifieddyes:airbrush", {
description = S("Dye Airbrush"),
inventory_image = "unifieddyes_airbrush.png",
use_texture_alpha = true,
tool_capabilities = {
full_punch_interval=0.1,
},
range = 12,
on_use = unifieddyes.on_airbrush
})
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname == "unifieddyes:dye_select_form" then
local player_name = player:get_player_name()
local s1 = string.sub(minetest.serialize(fields), 11)
local s3 = string.sub(s1,1, string.find(s1, '"')-1)
if s3 == "cancel" then
unifieddyes.player_selected_dye[player_name] = nil
return
elseif s3 == "accept" and unifieddyes.player_selected_dye[player_name] then
local dye = unifieddyes.player_selected_dye[player_name]
unifieddyes.player_current_dye[player_name] = dye
unifieddyes.player_selected_dye[player_name] = nil
minetest.chat_send_player(player_name, "Selected "..string.sub(dye, 5).." for the airbrush.")
return
else
local inv = player:get_inventory()
local creative = creative and creative.is_enabled_for(player_name)
local dye = "dye:"..s3
if minetest.registered_items[dye] and (creative or inv:contains_item("main", dye)) then
unifieddyes.player_selected_dye[player_name] = dye
unifieddyes.show_airbrush_form(player)
end
end
end
end)
-- build a table to convert from classic/89-color palette to extended palette -- build a table to convert from classic/89-color palette to extended palette
-- the first five entries are for the old greyscale - white, light, grey, dark, black -- the first five entries are for the old greyscale - white, light, grey, dark, black
@ -912,6 +1188,8 @@ minetest.register_craft( {
}, },
}) })
-- aliases
minetest.register_alias("dye:light_red", "dye:pink") minetest.register_alias("dye:light_red", "dye:pink")
minetest.register_alias("dye:medium_orange", "dye:brown") minetest.register_alias("dye:medium_orange", "dye:brown")
@ -938,10 +1216,16 @@ minetest.register_alias("unifieddyes:carbon_black", "dye:black")
-- note that technically, lime should be aliased, but can't be (there IS -- note that technically, lime should be aliased, but can't be (there IS
-- lime in the new color table, it's just shifted up a bit) -- lime in the new color table, it's just shifted up a bit)
minetest.register_alias("unifieddyes:aqua", "unifieddyes:spring") minetest.register_alias("unifieddyes:aqua", "dye:spring")
minetest.register_alias("unifieddyes:skyblue", "unifieddyes:azure") minetest.register_alias("dye:aqua", "dye:spring")
minetest.register_alias("unifieddyes:redviolet", "unifieddyes:rose")
minetest.register_alias("unifieddyes:brown", "dye:brown") minetest.register_alias("unifieddyes:skyblue", "dye:azure")
minetest.register_alias("dye:skyblue", "dye:azure")
minetest.register_alias("unifieddyes:redviolet", "dye:rose")
minetest.register_alias("dye:redviolet", "dye:rose")
minetest.register_alias("unifieddyes:brown", "dye:brown")
print(S("[UnifiedDyes] Loaded!")) print(S("[UnifiedDyes] Loaded!"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

After

Width:  |  Height:  |  Size: 136 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B