Unified Dyes expands the standard dye set from 15 to up to 256 colors (depending on the object to be colored) https://content.minetest.net/packages/VanessaE/unifieddyes/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1570 lines
47KB

  1. --[[
  2. Unified Dyes
  3. This mod provides an extension to the Minetest 0.4.x dye system
  4. ==============================================================================
  5. Copyright (C) 2012-2013, Vanessa Ezekowitz
  6. Email: vanessaezekowitz@gmail.com
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License along
  16. with this program; if not, write to the Free Software Foundation, Inc.,
  17. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. ==============================================================================
  19. --]]
  20. --=====================================================================
  21. unifieddyes = {}
  22. local creative_mode = minetest.settings:get_bool("creative_mode")
  23. local S = minetest.get_translator("unifieddyes")
  24. -- the names of the various colors here came from http://www.procato.com/rgb+index/
  25. unifieddyes.HUES_EXTENDED = {
  26. { "red", 0xff, 0x00, 0x00 },
  27. { "vermilion", 0xff, 0x40, 0x00 },
  28. { "orange", 0xff, 0x80, 0x00 },
  29. { "amber", 0xff, 0xbf, 0x00 },
  30. { "yellow", 0xff, 0xff, 0x00 },
  31. { "lime", 0xbf, 0xff, 0x00 },
  32. { "chartreuse", 0x80, 0xff, 0x00 },
  33. { "harlequin", 0x40, 0xff, 0x00 },
  34. { "green", 0x00, 0xff, 0x00 },
  35. { "malachite", 0x00, 0xff, 0x40 },
  36. { "spring", 0x00, 0xff, 0x80 },
  37. { "turquoise", 0x00, 0xff, 0xbf },
  38. { "cyan", 0x00, 0xff, 0xff },
  39. { "cerulean", 0x00, 0xbf, 0xff },
  40. { "azure", 0x00, 0x80, 0xff },
  41. { "sapphire", 0x00, 0x40, 0xff },
  42. { "blue", 0x00, 0x00, 0xff },
  43. { "indigo", 0x40, 0x00, 0xff },
  44. { "violet", 0x80, 0x00, 0xff },
  45. { "mulberry", 0xbf, 0x00, 0xff },
  46. { "magenta", 0xff, 0x00, 0xff },
  47. { "fuchsia", 0xff, 0x00, 0xbf },
  48. { "rose", 0xff, 0x00, 0x80 },
  49. { "crimson", 0xff, 0x00, 0x40 }
  50. }
  51. unifieddyes.HUES_WITH_GREY = {}
  52. for _,i in ipairs(unifieddyes.HUES_EXTENDED) do
  53. table.insert(unifieddyes.HUES_WITH_GREY, i[1])
  54. end
  55. table.insert(unifieddyes.HUES_WITH_GREY, "grey")
  56. unifieddyes.HUES_WALLMOUNTED = {
  57. "red",
  58. "orange",
  59. "yellow",
  60. "green",
  61. "cyan",
  62. "blue",
  63. "violet",
  64. "magenta"
  65. }
  66. unifieddyes.SATS = {
  67. "",
  68. "_s50"
  69. }
  70. unifieddyes.VALS = {
  71. "",
  72. "medium_",
  73. "dark_"
  74. }
  75. unifieddyes.VALS_SPLIT = {
  76. "faint_",
  77. "light_",
  78. "",
  79. "medium_",
  80. "dark_"
  81. }
  82. unifieddyes.VALS_EXTENDED = {
  83. "faint_",
  84. "pastel_",
  85. "light_",
  86. "bright_",
  87. "",
  88. "medium_",
  89. "dark_"
  90. }
  91. unifieddyes.GREYS = {
  92. "white",
  93. "light_grey",
  94. "grey",
  95. "dark_grey",
  96. "black"
  97. }
  98. unifieddyes.GREYS_EXTENDED = table.copy(unifieddyes.GREYS)
  99. for i = 1, 14 do
  100. if i ~= 0 and i ~= 4 and i ~= 8 and i ~= 11 and i ~= 15 then
  101. table.insert(unifieddyes.GREYS_EXTENDED, "grey_"..i)
  102. end
  103. end
  104. local default_dyes = {
  105. "black",
  106. "blue",
  107. "brown",
  108. "cyan",
  109. "dark_green",
  110. "dark_grey",
  111. "green",
  112. "grey",
  113. "magenta",
  114. "orange",
  115. "pink",
  116. "red",
  117. "violet",
  118. "white",
  119. "yellow"
  120. }
  121. unifieddyes.player_current_dye = {}
  122. unifieddyes.player_selected_dye = {}
  123. unifieddyes.player_last_right_clicked = {}
  124. unifieddyes.palette_has_color = {}
  125. unifieddyes.player_showall = {}
  126. -- if a node with a palette is placed in the world,
  127. -- but the itemstack used to place it has no palette_index (color byte),
  128. -- create something appropriate to make it officially white.
  129. minetest.register_on_placenode(
  130. function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
  131. local def = minetest.registered_items[newnode.name]
  132. if not def
  133. or not def.palette
  134. or def.after_place_node then
  135. return false
  136. end
  137. if not string.find(itemstack:to_string(), "palette_index") then
  138. local param2
  139. local color = 0
  140. if def.palette == "unifieddyes_palette_extended.png"
  141. and def.paramtype2 == "color" then
  142. param2 = 240
  143. color = 240
  144. elseif def.palette == "unifieddyes_palette_colorwallmounted.png"
  145. and def.paramtype2 == "colorwallmounted" then
  146. param2 = newnode.param2 % 8
  147. elseif string.find(def.palette, "unifieddyes_palette_")
  148. and def.paramtype2 == "colorfacedir" then -- it's a split palette
  149. param2 = newnode.param2 % 32
  150. end
  151. if param2 then
  152. minetest.swap_node(pos, {name = newnode.name, param2 = param2})
  153. minetest.get_meta(pos):set_int("palette_index", color)
  154. end
  155. end
  156. end
  157. )
  158. -- The complementary function: strip-off the color if the node being dug is still white/neutral
  159. local function move_item(item, pos, inv, digger)
  160. local creative = creative_mode or minetest.check_player_privs(digger, "creative")
  161. if inv:room_for_item("main", item)
  162. and (not creative or not inv:contains_item("main", item, true)) then
  163. inv:add_item("main", item)
  164. elseif not creative then
  165. minetest.item_drop(ItemStack(item), digger, pos)
  166. end
  167. minetest.remove_node(pos)
  168. end
  169. function unifieddyes.on_dig(pos, node, digger)
  170. local playername = digger:get_player_name()
  171. if minetest.is_protected(pos, playername) then
  172. minetest.record_protection_violation(pos, playername)
  173. return
  174. end
  175. local oldparam2 = minetest.get_node(pos).param2
  176. local def = minetest.registered_items[node.name]
  177. local del_color
  178. if def.paramtype2 == "color" and oldparam2 == 240 and def.palette == "unifieddyes_palette_extended.png" then
  179. del_color = true
  180. elseif def.paramtype2 == "colorwallmounted" and math.floor(oldparam2 / 8) == 0 and def.palette == "unifieddyes_palette_colorwallmounted.png" then
  181. del_color = true
  182. elseif def.paramtype2 == "colorfacedir" and math.floor(oldparam2 / 32) == 0 and string.find(def.palette, "unifieddyes_palette_") then
  183. del_color = true
  184. end
  185. local inv = digger:get_inventory()
  186. if del_color then
  187. move_item(node.name, pos, inv, digger)
  188. else
  189. return minetest.node_dig(pos, node, digger)
  190. end
  191. end
  192. -- just stubs to keep old mods from crashing when expecting auto-coloring
  193. -- or getting back the dye on dig.
  194. function unifieddyes.recolor_on_place(foo)
  195. end
  196. function unifieddyes.after_dig_node(foo)
  197. end
  198. -- This helper function creates multiple copies of the passed node,
  199. -- for the split palette - one per hue, plus grey - and assigns
  200. -- proper palettes and other attributes
  201. function unifieddyes.generate_split_palette_nodes(name, def, drop)
  202. for _, color in ipairs(unifieddyes.HUES_WITH_GREY) do
  203. local def2 = table.copy(def)
  204. local desc_color = string.gsub(string.upper(string.sub(color, 1, 1))..string.sub(color, 2), "_", " ")
  205. if string.sub(def2.description, -1) == ")" then
  206. def2.description = string.sub(def2.description, 1, -2)..", "..desc_color.." shades)"
  207. else
  208. def2.description = def2.description.."("..desc_color.." shades)"
  209. end
  210. def2.palette = "unifieddyes_palette_"..color.."s.png"
  211. def2.paramtype2 = "colorfacedir"
  212. def2.groups.ud_param2_colorable = 1
  213. if drop then
  214. def2.drop = {
  215. items = {
  216. {items = {drop.."_"..color}, inherit_color = true },
  217. }
  218. }
  219. end
  220. minetest.register_node(":"..name.."_"..color, def2)
  221. end
  222. end
  223. -- This helper function creates a colored itemstack
  224. function unifieddyes.make_colored_itemstack(item, palette, color)
  225. local paletteidx = unifieddyes.getpaletteidx(color, palette)
  226. local stack = ItemStack(item)
  227. stack:get_meta():set_int("palette_index", paletteidx)
  228. return stack:to_string(),paletteidx
  229. end
  230. -- these helper functions register all of the recipes needed to create colored
  231. -- nodes with any of the dyes supported by that node's palette.
  232. local function register_c(craft, h, sat, val)
  233. local hue = (type(h) == "table") and h[1] or h
  234. local color = ""
  235. if val then
  236. if craft.palette == "wallmounted" then
  237. color = val..hue..sat
  238. else
  239. color = val..hue..sat
  240. end
  241. else
  242. color = hue -- if val is nil, then it's grey.
  243. end
  244. local dye = "dye:"..color
  245. local recipe = minetest.serialize(craft.recipe)
  246. recipe = string.gsub(recipe, "MAIN_DYE", dye)
  247. recipe = string.gsub(recipe, "NEUTRAL_NODE", craft.neutral_node)
  248. local newrecipe = minetest.deserialize(recipe)
  249. local coutput = craft.output or ""
  250. local output = coutput
  251. if craft.output_prefix then
  252. if craft.palette ~= "split" then
  253. output = craft.output_prefix..color..craft.output_suffix..coutput
  254. else
  255. if hue == "white" or hue == "black" or string.find(hue, "grey") then
  256. output = craft.output_prefix.."grey"..craft.output_suffix..coutput
  257. elseif hue == "pink" then
  258. dye = "dye:light_red"
  259. output = craft.output_prefix.."red"..craft.output_suffix..coutput
  260. else
  261. output = craft.output_prefix..hue..craft.output_suffix..coutput
  262. end
  263. end
  264. end
  265. local colored_itemstack =
  266. unifieddyes.make_colored_itemstack(output, craft.palette, dye)
  267. minetest.register_craft({
  268. output = colored_itemstack,
  269. type = craft.type,
  270. recipe = newrecipe
  271. })
  272. end
  273. function unifieddyes.register_color_craft(craft)
  274. local hues_table = unifieddyes.HUES_EXTENDED
  275. local sats_table = unifieddyes.SATS
  276. local vals_table = unifieddyes.VALS_SPLIT
  277. local greys_table = unifieddyes.GREYS
  278. if craft.palette == "wallmounted" then
  279. register_c(craft, "green", "", "light_")
  280. register_c(craft, "blue", "", "light_")
  281. hues_table = unifieddyes.HUES_WALLMOUNTED
  282. sats_table = {""}
  283. vals_table = unifieddyes.VALS
  284. elseif craft.palette == "extended" then
  285. vals_table = unifieddyes.VALS_EXTENDED
  286. greys_table = unifieddyes.GREYS_EXTENDED
  287. end
  288. for _, hue in ipairs(hues_table) do
  289. for _, val in ipairs(vals_table) do
  290. for _, sat in ipairs(sats_table) do
  291. if sat == "_s50" and val ~= "" and val ~= "medium_" and val ~= "dark_" then break end
  292. register_c(craft, hue, sat, val)
  293. end
  294. end
  295. end
  296. for _, grey in ipairs(greys_table) do
  297. register_c(craft, grey)
  298. end
  299. register_c(craft, "pink")
  300. end
  301. -- code borrowed from homedecor
  302. -- call this function to reset the rotation of a "wallmounted" object on place
  303. function unifieddyes.fix_rotation(pos, placer, itemstack, pointed_thing)
  304. local node = minetest.get_node(pos)
  305. local colorbits = node.param2 - (node.param2 % 8)
  306. local yaw = placer:get_look_horizontal()
  307. local dir = minetest.yaw_to_dir(yaw) -- -1.5)
  308. local pitch = placer:get_look_vertical()
  309. local fdir = minetest.dir_to_wallmounted(dir)
  310. if pitch < -(math.pi/8) then
  311. fdir = 0
  312. elseif pitch > math.pi/8 then
  313. fdir = 1
  314. end
  315. minetest.swap_node(pos, { name = node.name, param2 = fdir+colorbits })
  316. end
  317. -- use this when you have a "wallmounted" node that should never be oriented
  318. -- to floor or ceiling...
  319. function unifieddyes.fix_rotation_nsew(pos, placer, itemstack, pointed_thing)
  320. local node = minetest.get_node(pos)
  321. local colorbits = node.param2 - (node.param2 % 8)
  322. local yaw = placer:get_look_horizontal()
  323. local dir = minetest.yaw_to_dir(yaw+1.5)
  324. local fdir = minetest.dir_to_wallmounted(dir)
  325. minetest.swap_node(pos, { name = node.name, param2 = fdir+colorbits })
  326. end
  327. -- ... and use this one to force that kind of node off of floor/ceiling
  328. -- orientation after the screwdriver rotates it.
  329. function unifieddyes.fix_after_screwdriver_nsew(pos, node, user, mode, new_param2)
  330. local new_fdir = new_param2 % 8
  331. local color = new_param2 - new_fdir
  332. if new_fdir < 2 then
  333. new_fdir = 2
  334. minetest.swap_node(pos, { name = node.name, param2 = new_fdir + color })
  335. return true
  336. end
  337. end
  338. function unifieddyes.is_buildable_to(placer_name, ...)
  339. for _, pos in ipairs({...}) do
  340. local node = minetest.get_node_or_nil(pos)
  341. local def = node and minetest.registered_nodes[node.name]
  342. if not (def and def.buildable_to) or minetest.is_protected(pos, placer_name) then
  343. return false
  344. end
  345. end
  346. return true
  347. end
  348. function unifieddyes.get_hsv(name) -- expects a node/item name
  349. local hue = ""
  350. local a,b
  351. for _, i in ipairs(unifieddyes.HUES_EXTENDED) do
  352. a,b = string.find(name, "_"..i[1])
  353. if a then
  354. hue = i[1]
  355. break
  356. end
  357. end
  358. if string.find(name, "_light_grey") then hue = "light_grey"
  359. elseif string.find(name, "_lightgrey") then hue = "light_grey"
  360. elseif string.find(name, "_dark_grey") then hue = "dark_grey"
  361. elseif string.find(name, "_darkgrey") then hue = "dark_grey"
  362. elseif string.find(name, "_grey") then hue = "grey"
  363. elseif string.find(name, "_white") then hue = "white"
  364. elseif string.find(name, "_black") then hue = "black"
  365. end
  366. local sat = ""
  367. if string.find(name, "_s50") then sat = "_s50" end
  368. local val = ""
  369. if string.find(name, "dark_") then val = "dark_" end
  370. if string.find(name, "medium_") then val = "medium_" end
  371. if string.find(name, "light_") then val = "light_" end
  372. return hue, sat, val
  373. end
  374. -- code partially borrowed from cheapie's plasticbox mod
  375. -- in the function below, color is just a color string, while
  376. -- palette_type can be:
  377. --
  378. -- "extended" = 256 color palette
  379. -- "split" = 200 color palette split into pieces for colorfacedir
  380. -- "wallmounted" = 32-color abridged palette
  381. function unifieddyes.getpaletteidx(color, palette_type)
  382. local origcolor = color
  383. local aliases = {
  384. ["pink"] = "light_red",
  385. ["brown"] = "medium_orange",
  386. ["azure"] = "light_blue"
  387. }
  388. local grayscale = {
  389. ["white"] = 1,
  390. ["light_grey"] = 2,
  391. ["grey"] = 3,
  392. ["dark_grey"] = 4,
  393. ["black"] = 5,
  394. }
  395. local grayscale_extended = {
  396. ["white"] = 0,
  397. ["grey_14"] = 1,
  398. ["grey_13"] = 2,
  399. ["grey_12"] = 3,
  400. ["light_grey"] = 4,
  401. ["grey_11"] = 4,
  402. ["grey_10"] = 5,
  403. ["grey_9"] = 6,
  404. ["grey_8"] = 7,
  405. ["grey"] = 7,
  406. ["grey_7"] = 8,
  407. ["grey_6"] = 9,
  408. ["grey_5"] = 10,
  409. ["grey_4"] = 11,
  410. ["dark_grey"] = 11,
  411. ["grey_3"] = 12,
  412. ["grey_2"] = 13,
  413. ["grey_1"] = 14,
  414. ["black"] = 15,
  415. }
  416. local grayscale_wallmounted = {
  417. ["white"] = 0,
  418. ["light_grey"] = 1,
  419. ["grey"] = 2,
  420. ["dark_grey"] = 3,
  421. ["black"] = 4,
  422. }
  423. local hues_extended = {
  424. ["red"] = 0,
  425. ["vermilion"] = 1,
  426. ["orange"] = 2,
  427. ["amber"] = 3,
  428. ["yellow"] = 4,
  429. ["lime"] = 5,
  430. ["chartreuse"] = 6,
  431. ["harlequin"] = 7,
  432. ["green"] = 8,
  433. ["malachite"] = 9,
  434. ["spring"] = 10,
  435. ["aqua"] = 10,
  436. ["turquoise"] = 11,
  437. ["cyan"] = 12,
  438. ["cerulean"] = 13,
  439. ["azure"] = 14,
  440. ["skyblue"] = 14,
  441. ["sapphire"] = 15,
  442. ["blue"] = 16,
  443. ["indigo"] = 17,
  444. ["violet"] = 18,
  445. ["mulberry"] = 19,
  446. ["magenta"] = 20,
  447. ["fuchsia"] = 21,
  448. ["rose"] = 22,
  449. ["redviolet"] = 22,
  450. ["crimson"] = 23,
  451. }
  452. local hues_wallmounted = {
  453. ["red"] = 0,
  454. ["orange"] = 1,
  455. ["yellow"] = 2,
  456. ["green"] = 3,
  457. ["cyan"] = 4,
  458. ["blue"] = 5,
  459. ["violet"] = 6,
  460. ["magenta"] = 7
  461. }
  462. local shades = {
  463. [""] = 1,
  464. ["s50"] = 2,
  465. ["light"] = 3,
  466. ["medium"] = 4,
  467. ["mediums50"] = 5,
  468. ["dark"] = 6,
  469. ["darks50"] = 7,
  470. }
  471. local shades_split = {
  472. ["faint"] = 0,
  473. [""] = 1,
  474. ["s50"] = 2,
  475. ["light"] = 3,
  476. ["medium"] = 4,
  477. ["mediums50"] = 5,
  478. ["dark"] = 6,
  479. ["darks50"] = 7,
  480. }
  481. local shades_extended = {
  482. ["faint"] = 0,
  483. ["pastel"] = 1,
  484. ["light"] = 2,
  485. ["bright"] = 3,
  486. [""] = 4,
  487. ["s50"] = 5,
  488. ["medium"] = 6,
  489. ["mediums50"] = 7,
  490. ["dark"] = 8,
  491. ["darks50"] = 9
  492. }
  493. local shades_wallmounted = {
  494. [""] = 1,
  495. ["medium"] = 2,
  496. ["dark"] = 3
  497. }
  498. if string.sub(color,1,4) == "dye:" then
  499. color = string.sub(color,5,-1)
  500. elseif string.sub(color,1,12) == "unifieddyes:" then
  501. color = string.sub(color,13,-1)
  502. else
  503. return
  504. end
  505. if palette_type == "wallmounted" then
  506. if grayscale_wallmounted[color] then
  507. return (grayscale_wallmounted[color] * 8), 0
  508. end
  509. elseif palette_type == "split" then
  510. if grayscale[color] then
  511. return (grayscale[color] * 32), 0
  512. end
  513. elseif palette_type == "extended" then
  514. if grayscale_extended[color] then
  515. return grayscale_extended[color]+240, 0
  516. end
  517. end
  518. local shade = "" -- assume full
  519. if string.sub(color,1,6) == "faint_" then
  520. shade = "faint"
  521. color = string.sub(color,7,-1)
  522. elseif string.sub(color,1,7) == "pastel_" then
  523. shade = "pastel"
  524. color = string.sub(color,8,-1)
  525. elseif string.sub(color,1,6) == "light_" then
  526. shade = "light"
  527. color = string.sub(color,7,-1)
  528. elseif string.sub(color,1,7) == "bright_" then
  529. shade = "bright"
  530. color = string.sub(color,8,-1)
  531. elseif string.sub(color,1,7) == "medium_" then
  532. shade = "medium"
  533. color = string.sub(color,8,-1)
  534. elseif string.sub(color,1,5) == "dark_" then
  535. shade = "dark"
  536. color = string.sub(color,6,-1)
  537. end
  538. if string.sub(color,-4,-1) == "_s50" then
  539. shade = shade.."s50"
  540. color = string.sub(color,1,-5)
  541. end
  542. if palette_type == "wallmounted" then
  543. if color == "green" and shade == "light" then return 48,3
  544. elseif color == "brown" then return 17,1
  545. elseif color == "pink" then return 56,7
  546. elseif color == "blue" and shade == "light" then return 40,5
  547. elseif hues_wallmounted[color] and shades_wallmounted[shade] then
  548. return (shades_wallmounted[shade] * 64 + hues_wallmounted[color] * 8), hues_wallmounted[color]
  549. end
  550. else
  551. if color == "brown" then
  552. color = "orange"
  553. shade = "medium"
  554. elseif color == "pink" then
  555. color = "red"
  556. shade = "light"
  557. end
  558. if palette_type == "split" then -- it's colorfacedir
  559. if hues_extended[color] and shades_split[shade] then
  560. return (shades_split[shade] * 32), hues_extended[color]+1
  561. end
  562. elseif palette_type == "extended" then
  563. if hues_extended[color] and shades_extended[shade] then
  564. return (hues_extended[color] + shades_extended[shade]*24), hues_extended[color]
  565. end
  566. end
  567. end
  568. end
  569. function unifieddyes.get_color_from_dye_name(name)
  570. if name == "dye:black" then
  571. return "000000"
  572. elseif name == "dye:white" then
  573. return "ffffff"
  574. end
  575. local item = minetest.registered_items[name]
  576. if not item then return end
  577. local inv_image = item.inventory_image
  578. if not inv_image then return end
  579. return string.match(inv_image,"colorize:#(......):200")
  580. end
  581. -- punch-to-recolor using the airbrush
  582. function unifieddyes.on_airbrush(itemstack, player, pointed_thing)
  583. local player_name = player:get_player_name()
  584. local painting_with = nil
  585. if unifieddyes.player_current_dye[player_name] then
  586. painting_with = unifieddyes.player_current_dye[player_name]
  587. end
  588. if not painting_with then
  589. minetest.chat_send_player(player_name, "*** You need to set a color first.")
  590. minetest.chat_send_player(player_name, "*** Right-click any random node to open the color selector,")
  591. minetest.chat_send_player(player_name, "*** or shift+right-click a colorized node to use its color.")
  592. minetest.chat_send_player(player_name, "*** Be sure to click \"Accept\", or the color you select will be ignored.")
  593. return
  594. end
  595. local pos = minetest.get_pointed_thing_position(pointed_thing)
  596. if not pos then
  597. local look_angle = player:get_look_vertical()
  598. if look_angle > -1.55 then
  599. minetest.chat_send_player(player_name, "*** No node selected")
  600. else
  601. local hexcolor = unifieddyes.get_color_from_dye_name(painting_with)
  602. if hexcolor then
  603. local r = tonumber(string.sub(hexcolor,1,2),16)
  604. local g = tonumber(string.sub(hexcolor,3,4),16)
  605. local b = tonumber(string.sub(hexcolor,5,6),16)
  606. player:set_sky({r=r,g=g,b=b,a=255},"plain")
  607. end
  608. end
  609. return
  610. end
  611. local node = minetest.get_node(pos)
  612. local def = minetest.registered_items[node.name]
  613. if not def then return end
  614. if minetest.is_protected(pos, player_name) then
  615. minetest.chat_send_player(player_name, "*** Sorry, someone else owns that node.")
  616. return
  617. end
  618. if not (def.groups and def.groups.ud_param2_colorable and def.groups.ud_param2_colorable > 0) then
  619. minetest.chat_send_player(player_name, "*** That node can't be colored.")
  620. return
  621. end
  622. local palette = nil
  623. local fdir = 0
  624. if not def or not def.palette then
  625. minetest.chat_send_player(player_name, "*** That node can't be colored -- it's either undefined or has no palette.")
  626. return
  627. elseif def.palette == "unifieddyes_palette_extended.png" then
  628. palette = "extended"
  629. elseif def.palette == "unifieddyes_palette_colorwallmounted.png" then
  630. palette = "wallmounted"
  631. fdir = node.param2 % 8
  632. elseif def.palette ~= "unifieddyes_palette_extended.png"
  633. and def.palette ~= "unifieddyes_palette_colorwallmounted.png"
  634. and string.find(def.palette, "unifieddyes_palette_") then
  635. palette = "split"
  636. fdir = node.param2 % 32
  637. else
  638. minetest.chat_send_player(player_name, "*** That node can't be colored -- it has an invalid color mode.")
  639. return
  640. end
  641. local idx, hue = unifieddyes.getpaletteidx(painting_with, palette)
  642. local inv = player:get_inventory()
  643. if (not creative or not creative.is_enabled_for(player_name)) and not inv:contains_item("main", painting_with) then
  644. local suff = ""
  645. if not idx then
  646. suff = " Besides, "..string.sub(painting_with, 5).." can't be applied to that node."
  647. end
  648. minetest.chat_send_player(player_name, "*** You're in survival mode, and you're out of "..string.sub(painting_with, 5).."."..suff)
  649. return
  650. end
  651. if not idx then
  652. minetest.chat_send_player(player_name, "*** "..string.sub(painting_with, 5).." can't be applied to that node.")
  653. return
  654. end
  655. local oldidx = node.param2 - fdir
  656. local name = def.airbrush_replacement_node or node.name
  657. if palette == "split" then
  658. local modname = string.sub(name, 1, string.find(name, ":")-1)
  659. local nodename2 = string.sub(name, string.find(name, ":")+1)
  660. local oldcolor = "snozzberry"
  661. local newcolor = "razzberry" -- intentionally misspelled ;-)
  662. if def.ud_color_start and def.ud_color_end then
  663. oldcolor = string.sub(node.name, def.ud_color_start, def.ud_color_end)
  664. newcolor = string.sub(painting_with, 5)
  665. else
  666. if hue ~= 0 then
  667. newcolor = unifieddyes.HUES_EXTENDED[hue][1]
  668. else
  669. newcolor = "grey"
  670. end
  671. if def.airbrush_replacement_node then
  672. oldcolor = "grey"
  673. else
  674. local s = string.sub(def.palette, 21)
  675. oldcolor = string.sub(s, 1, string.find(s, "s.png")-1)
  676. end
  677. end
  678. name = modname..":"..string.gsub(nodename2, oldcolor, newcolor)
  679. if not minetest.registered_items[name] then
  680. minetest.chat_send_player(player_name, "*** "..string.sub(painting_with, 5).." can't be applied to that node.")
  681. return
  682. end
  683. elseif idx == oldidx then
  684. return
  685. end
  686. minetest.swap_node(pos, {name = name, param2 = fdir + idx})
  687. if not creative or not creative.is_enabled_for(player_name) then
  688. inv:remove_item("main", painting_with)
  689. return
  690. end
  691. end
  692. -- get a node's dye color based on its palette and param2
  693. function unifieddyes.color_to_name(param2, def)
  694. if not param2 or not def or not def.palette then return end
  695. if def.palette == "unifieddyes_palette_extended.png" then
  696. local color = param2
  697. local v = 0
  698. local s = 1
  699. if color < 24 then v = 1
  700. elseif color > 23 and color < 48 then v = 2
  701. elseif color > 47 and color < 72 then v = 3
  702. elseif color > 71 and color < 96 then v = 4
  703. elseif color > 95 and color < 120 then v = 5
  704. elseif color > 119 and color < 144 then v = 5 s = 2
  705. elseif color > 143 and color < 168 then v = 6
  706. elseif color > 167 and color < 192 then v = 6 s = 2
  707. elseif color > 191 and color < 216 then v = 7
  708. elseif color > 215 and color < 240 then v = 7 s = 2
  709. end
  710. if color > 239 then
  711. if color == 240 then return "white"
  712. elseif color == 244 then return "light_grey"
  713. elseif color == 247 then return "grey"
  714. elseif color == 251 then return "dark_grey"
  715. elseif color == 255 then return "black"
  716. else return "grey_"..15-(color-240)
  717. end
  718. else
  719. local h = color - math.floor(color/24)*24
  720. return unifieddyes.VALS_EXTENDED[v]..unifieddyes.HUES_EXTENDED[h+1][1]..unifieddyes.SATS[s]
  721. end
  722. elseif def.palette == "unifieddyes_palette_colorwallmounted.png" then
  723. local color = math.floor(param2 / 8)
  724. if color == 0 then return "white"
  725. elseif color == 1 then return "light_grey"
  726. elseif color == 2 then return "grey"
  727. elseif color == 3 then return "dark_grey"
  728. elseif color == 4 then return "black"
  729. elseif color == 5 then return "light_blue"
  730. elseif color == 6 then return "light_green"
  731. elseif color == 7 then return "pink"
  732. end
  733. local v = math.floor(color/8)
  734. local h = color - v * 8
  735. return unifieddyes.VALS[v]..unifieddyes.HUES_WALLMOUNTED[h+1]
  736. elseif string.find(def.palette, "unifieddyes_palette") then -- it's the split palette
  737. -- palette names in this mode are always "unifieddyes_palette_COLORs.png"
  738. local s = string.sub(def.palette, 21)
  739. local color = string.sub(s, 1, string.find(s, "s.png")-1)
  740. local v = math.floor(param2/32)
  741. if color ~= "grey" then
  742. if v == 0 then return "faint_"..color
  743. elseif v == 1 then return color
  744. elseif v == 2 then return color.."_s50"
  745. elseif v == 3 then return "light_"..color
  746. elseif v == 4 then return "medium_"..color
  747. elseif v == 5 then return "medium_"..color.."_s50"
  748. elseif v == 6 then return "dark_"..color
  749. elseif v == 7 then return "dark_"..color.."_s50"
  750. end
  751. else
  752. if v > 0 and v < 6 then return unifieddyes.GREYS[v]
  753. else return "white"
  754. end
  755. end
  756. end
  757. end
  758. local hps = 0.6 -- horizontal position scale
  759. local vps = 1.3 -- vertical position scale
  760. local vs = 0.1 -- vertical shift/offset
  761. local color_button_size = ";0.75,0.75;"
  762. local color_square_size = ";0.69,0.69;"
  763. function unifieddyes.make_readable_color(color)
  764. local s = string.gsub(color, "_", " ")
  765. s = string.gsub(s, "s50", "(low saturation)")
  766. return s
  767. end
  768. function unifieddyes.make_colored_square(hexcolor, colorname, showall, creative, painting_with, nodepalette, hp, v2, selindic, inv, explist)
  769. local dye = "dye:"..colorname
  770. local overlay = ""
  771. local colorize = minetest.formspec_escape("^[colorize:#"..hexcolor..":255")
  772. if not creative and inv:contains_item("main", dye) then
  773. overlay = "^unifieddyes_onhand_overlay.png"
  774. end
  775. local unavail_overlay = ""
  776. if not showall and not unifieddyes.palette_has_color[nodepalette.."_"..colorname]
  777. or (explist and not explist[colorname]) then
  778. if overlay == "" then
  779. unavail_overlay = "^unifieddyes_unavailable_overlay.png"
  780. else
  781. unavail_overlay = "^unifieddyes_onhand_unavailable_overlay.png"
  782. end
  783. end
  784. local tooltip = "tooltip["..colorname..";"..
  785. unifieddyes.make_readable_color(colorname)..
  786. "\n(dye:"..colorname..")]"
  787. if dye == painting_with then
  788. overlay = "^unifieddyes_select_overlay.png"
  789. selindic = "unifieddyes_white_square.png"..colorize..overlay..unavail_overlay.."]"..tooltip
  790. end
  791. local form
  792. if unavail_overlay == "" then
  793. form = "image_button["..
  794. (hp*hps)..","..(v2*vps+vs)..
  795. color_button_size..
  796. "unifieddyes_white_square.png"..colorize..overlay..unavail_overlay..";"..
  797. colorname..";]"..
  798. tooltip
  799. else
  800. form = "image["..
  801. (hp*hps)..","..(v2*vps+vs)..
  802. color_square_size..
  803. "unifieddyes_white_square.png"..colorize..overlay..unavail_overlay.."]"..
  804. tooltip
  805. end
  806. return form, selindic
  807. end
  808. function unifieddyes.show_airbrush_form(player)
  809. if not player then return end
  810. local t = {}
  811. local player_name = player:get_player_name()
  812. local painting_with = unifieddyes.player_selected_dye[player_name] or unifieddyes.player_current_dye[player_name]
  813. local creative = creative and creative.is_enabled_for(player_name)
  814. local inv = player:get_inventory()
  815. local nodepalette = "extended"
  816. local showall = unifieddyes.player_showall[player_name]
  817. t[1] = "size[14.5,8.5]label[7,-0.3;"..S("Select a color:").."]"
  818. local selindic = "unifieddyes_select_overlay.png^unifieddyes_question.png]"
  819. local last_right_click = unifieddyes.player_last_right_clicked[player_name]
  820. if last_right_click then
  821. if last_right_click.def and last_right_click.def.palette then
  822. if last_right_click.def.palette == "unifieddyes_palette_colorwallmounted.png" then
  823. nodepalette = "wallmounted"
  824. elseif last_right_click.def.palette == "unifieddyes_palette_extended.png" then
  825. t[#t+1] = "label[0.5,8.25;"..S("(Right-clicked a node that supports all 256 colors, showing them all)").."]"
  826. showall = true
  827. elseif last_right_click.def.palette ~= "unifieddyes_palette_extended.png"
  828. and last_right_click.def.palette ~= "unifieddyes_palette_colorwallmounted.png"
  829. and string.find(last_right_click.def.palette, "unifieddyes_palette_") then
  830. nodepalette = "split"
  831. end
  832. end
  833. end
  834. if not last_right_click.def.groups
  835. or not last_right_click.def.groups.ud_param2_colorable
  836. or not last_right_click.def.palette
  837. or not string.find(last_right_click.def.palette, "unifieddyes_palette_") then
  838. t[#t+1] = "label[0.5,8.25;"..S("(Right-clicked a node not supported by the Airbrush, showing all colors)").."]"
  839. end
  840. local explist = last_right_click.def.explist
  841. for v = 0, 6 do
  842. local val = unifieddyes.VALS_EXTENDED[v+1]
  843. local sat = ""
  844. local v2=(v/2)
  845. for hi, h in ipairs(unifieddyes.HUES_EXTENDED) do
  846. local hue = h[1]
  847. local hp=hi-1
  848. local r = h[2]
  849. local g = h[3]
  850. local b = h[4]
  851. local factor = 40
  852. if v > 3 then
  853. factor = 75
  854. v2 = (v-2)
  855. end
  856. local r2 = math.max(math.min(r + (4-v)*factor, 255), 0)
  857. local g2 = math.max(math.min(g + (4-v)*factor, 255), 0)
  858. local b2 = math.max(math.min(b + (4-v)*factor, 255), 0)
  859. local hexcolor = string.format("%02x", r2)..string.format("%02x", g2)..string.format("%02x", b2)
  860. local f
  861. f, selindic = unifieddyes.make_colored_square(hexcolor, val..hue..sat, showall, creative, painting_with, nodepalette, hp, v2, selindic, inv, explist)
  862. t[#t+1] = f
  863. end
  864. if v > 3 then
  865. sat = "_s50"
  866. v2 = (v-1.5)
  867. for hi, h in ipairs(unifieddyes.HUES_EXTENDED) do
  868. local hue = h[1]
  869. local hp=hi-1
  870. local r = h[2]
  871. local g = h[3]
  872. local b = h[4]
  873. local factor = 75
  874. local pr = 0.299
  875. local pg = 0.587
  876. local pb = 0.114
  877. local r2 = math.max(math.min(r + (4-v)*factor, 255), 0)
  878. local g2 = math.max(math.min(g + (4-v)*factor, 255), 0)
  879. local b2 = math.max(math.min(b + (4-v)*factor, 255), 0)
  880. local p = math.sqrt(r2*r2*pr + g2*g2*pg + b2*b2*pb)
  881. local r3 = math.floor(p+(r2-p)*0.5)
  882. local g3 = math.floor(p+(g2-p)*0.5)
  883. local b3 = math.floor(p+(b2-p)*0.5)
  884. local hexcolor = string.format("%02x", r3)..string.format("%02x", g3)..string.format("%02x", b3)
  885. local f
  886. f, selindic = unifieddyes.make_colored_square(hexcolor, val..hue..sat, showall, creative, painting_with, nodepalette, hp, v2, selindic, inv, explist)
  887. t[#t+1] = f
  888. end
  889. end
  890. end
  891. local v2=5
  892. for y = 0, 15 do
  893. local hp=15-y
  894. local hexgrey = string.format("%02x", y*17)..string.format("%02x", y*17)..string.format("%02x", y*17)
  895. local grey = "grey_"..y
  896. if y == 0 then grey = "black"
  897. elseif y == 4 then grey = "dark_grey"
  898. elseif y == 8 then grey = "grey"
  899. elseif y == 11 then grey = "light_grey"
  900. elseif y == 15 then grey = "white"
  901. end
  902. local f
  903. f, selindic = unifieddyes.make_colored_square(hexgrey, grey, showall, creative, painting_with, nodepalette, hp, v2, selindic, inv, explist)
  904. t[#t+1] = f
  905. end
  906. if not creative then
  907. t[#t+1] = "image[10,"
  908. t[#t+1] = (vps*5.55+vs)
  909. t[#t+1] = color_button_size
  910. t[#t+1] = "unifieddyes_onhand_overlay.png]label[10.7,"
  911. t[#t+1] = (vps*5.51+vs)
  912. t[#t+1] = ";"..S("Dyes").."]"
  913. t[#t+1] = "label[10.7,"
  914. t[#t+1] = (vps*5.67+vs)
  915. t[#t+1] = ";on hand]"
  916. end
  917. t[#t+1] = "image[10,"
  918. t[#t+1] = (vps*5+vs)
  919. t[#t+1] = color_button_size
  920. t[#t+1] = selindic
  921. if painting_with then
  922. t[#t+1] = "label[10.7,"
  923. t[#t+1] = (vps*4.90+vs)
  924. t[#t+1] = ";"..S("Your selection:").."]"
  925. t[#t+1] = "label[10.7,"
  926. t[#t+1] = (vps*5.07+vs)
  927. t[#t+1] = ";"
  928. t[#t+1] = unifieddyes.make_readable_color(string.sub(painting_with, 5))
  929. t[#t+1] = "]label[10.7,"
  930. t[#t+1] = (vps*5.24+vs)
  931. t[#t+1] = ";("
  932. t[#t+1] = painting_with
  933. t[#t+1] = ")]"
  934. else
  935. t[#t+1] = "label[10.7,"
  936. t[#t+1] = (vps*5.07+vs)
  937. t[#t+1] = ";"..S("Your selection").."]"
  938. end
  939. t[#t+1] = "button_exit[10.5,8;2,1;cancel;"..S("Cancel").."]button_exit[12.5,8;2,1;accept;"..S("Accept").."]"
  940. if last_right_click and last_right_click.def and nodepalette ~= "extended" then
  941. if showall then
  942. t[#t+1] = "button[0,8;2,1;show_avail;"..S("Show Available").."]"
  943. t[#t+1] = "label[2,8.25;"..S("(Currently showing all 256 colors)").."]"
  944. else
  945. t[#t+1] = "button[0,8;2,1;show_all;"..S("Show All Colors").."]"
  946. t[#t+1] = "label[2,8.25;"..S("(Currently only showing what the right-clicked node can use)").."]"
  947. end
  948. end
  949. minetest.show_formspec(player_name, "unifieddyes:dye_select_form", table.concat(t))
  950. end
  951. minetest.register_tool("unifieddyes:airbrush", {
  952. description = S("Dye Airbrush"),
  953. inventory_image = "unifieddyes_airbrush.png",
  954. use_texture_alpha = true,
  955. tool_capabilities = {
  956. full_punch_interval=0.1,
  957. },
  958. range = 12,
  959. on_use = unifieddyes.on_airbrush,
  960. on_place = function(itemstack, placer, pointed_thing)
  961. local keys = placer:get_player_control()
  962. local player_name = placer:get_player_name()
  963. local pos = minetest.get_pointed_thing_position(pointed_thing)
  964. local node
  965. local def
  966. if pos then node = minetest.get_node(pos) end
  967. if node then def = minetest.registered_items[node.name] end
  968. unifieddyes.player_last_right_clicked[player_name] = {pos = pos, node = node, def = def}
  969. if not keys.sneak then
  970. unifieddyes.show_airbrush_form(placer)
  971. elseif keys.sneak then
  972. if not pos or not def then return end
  973. local newcolor = unifieddyes.color_to_name(node.param2, def)
  974. if not newcolor then
  975. minetest.chat_send_player(player_name, "*** That node is uncolored.")
  976. return
  977. end
  978. minetest.chat_send_player(player_name, "*** Switching to "..newcolor.." for the airbrush, to match that node.")
  979. unifieddyes.player_current_dye[player_name] = "dye:"..newcolor
  980. end
  981. end
  982. })
  983. minetest.register_craft( {
  984. output = "unifieddyes:airbrush",
  985. recipe = {
  986. { "basic_materials:brass_ingot", "", "basic_materials:plastic_sheet" },
  987. { "", "default:steel_ingot", "" },
  988. { "", "", "default:steel_ingot" }
  989. },
  990. })
  991. minetest.register_on_player_receive_fields(function(player, formname, fields)
  992. if formname == "unifieddyes:dye_select_form" then
  993. local player_name = player:get_player_name()
  994. local nodepalette = "extended"
  995. local showall = unifieddyes.player_showall[player_name]
  996. local last_right_click = unifieddyes.player_last_right_clicked[player_name]
  997. if last_right_click and last_right_click.def then
  998. if last_right_click.def.palette then
  999. if last_right_click.def.palette == "unifieddyes_palette_colorwallmounted.png" then
  1000. nodepalette = "wallmounted"
  1001. elseif last_right_click.def.palette ~= "unifieddyes_palette_extended.png" then
  1002. nodepalette = "split"
  1003. end
  1004. end
  1005. end
  1006. if fields.show_all then
  1007. unifieddyes.player_showall[player_name] = true
  1008. unifieddyes.show_airbrush_form(player)
  1009. return
  1010. elseif fields.show_avail then
  1011. unifieddyes.player_showall[player_name] = false
  1012. unifieddyes.show_airbrush_form(player)
  1013. return
  1014. elseif fields.quit then
  1015. if fields.accept then
  1016. local dye = unifieddyes.player_selected_dye[player_name]
  1017. if not dye then
  1018. minetest.chat_send_player(player_name, "*** Clicked \"Accept\", but no color was selected!")
  1019. return
  1020. elseif not showall
  1021. and not unifieddyes.palette_has_color[nodepalette.."_"..string.sub(dye, 5)] then
  1022. minetest.chat_send_player(player_name, "*** Clicked \"Accept\", but the selected color can't be used on the")
  1023. minetest.chat_send_player(player_name, "*** node that was right-clicked (and \"Show All\" wasn't in effect).")
  1024. if unifieddyes.player_current_dye[player_name] then
  1025. minetest.chat_send_player(player_name, "*** Ignoring it and sticking with "..string.sub(unifieddyes.player_current_dye[player_name], 5)..".")
  1026. else
  1027. minetest.chat_send_player(player_name, "*** Ignoring it.")
  1028. end
  1029. return
  1030. else
  1031. unifieddyes.player_current_dye[player_name] = dye
  1032. unifieddyes.player_selected_dye[player_name] = nil
  1033. minetest.chat_send_player(player_name, "*** Selected "..string.sub(dye, 5).." for the airbrush.")
  1034. return
  1035. end
  1036. else -- assume "Cancel" or Esc.
  1037. unifieddyes.player_selected_dye[player_name] = nil
  1038. return
  1039. end
  1040. else
  1041. local s1 = string.sub(minetest.serialize(fields), 11)
  1042. local s3 = string.sub(s1,1, string.find(s1, '"')-1)
  1043. local inv = player:get_inventory()
  1044. local creative = creative and creative.is_enabled_for(player_name)
  1045. local dye = "dye:"..s3
  1046. if (showall or unifieddyes.palette_has_color[nodepalette.."_"..s3]) and
  1047. (minetest.registered_items[dye] and (creative or inv:contains_item("main", dye))) then
  1048. unifieddyes.player_selected_dye[player_name] = dye
  1049. unifieddyes.show_airbrush_form(player)
  1050. end
  1051. end
  1052. end
  1053. end)
  1054. -- Generate all dyes that are not part of the default minetest_game dyes mod
  1055. for _, h in ipairs(unifieddyes.HUES_EXTENDED) do
  1056. local hue = h[1]
  1057. local r = h[2]
  1058. local g = h[3]
  1059. local b = h[4]
  1060. for v = 0, 6 do
  1061. local val = unifieddyes.VALS_EXTENDED[v+1]
  1062. local factor = 40
  1063. if v > 3 then factor = 75 end
  1064. local r2 = math.max(math.min(r + (4-v)*factor, 255), 0)
  1065. local g2 = math.max(math.min(g + (4-v)*factor, 255), 0)
  1066. local b2 = math.max(math.min(b + (4-v)*factor, 255), 0)
  1067. -- full-sat color
  1068. local desc = hue:gsub("%a", string.upper, 1).." Dye"
  1069. if val ~= "" then
  1070. desc = val:sub(1, -2):gsub("%a", string.upper, 1) .." "..desc
  1071. end
  1072. local color = string.format("%02x", r2)..string.format("%02x", g2)..string.format("%02x", b2)
  1073. if minetest.registered_items["dye:"..val..hue] then
  1074. minetest.override_item("dye:"..val..hue, {
  1075. inventory_image = "unifieddyes_dye.png^[colorize:#"..color..":200",
  1076. })
  1077. else
  1078. if (val..hue) ~= "medium_orange"
  1079. and (val..hue) ~= "light_red" then
  1080. minetest.register_craftitem(":dye:"..val..hue, {
  1081. description = S(desc),
  1082. inventory_image = "unifieddyes_dye.png^[colorize:#"..color..":200",
  1083. groups = { dye=1, not_in_creative_inventory=1 },
  1084. })
  1085. end
  1086. end
  1087. minetest.register_alias("unifieddyes:"..val..hue, "dye:"..val..hue)
  1088. if v > 3 then -- also register the low-sat version
  1089. local pr = 0.299
  1090. local pg = 0.587
  1091. local pb = 0.114
  1092. local p = math.sqrt(r2*r2*pr + g2*g2*pg + b2*b2*pb)
  1093. local r3 = math.floor(p+(r2-p)*0.5)
  1094. local g3 = math.floor(p+(g2-p)*0.5)
  1095. local b3 = math.floor(p+(b2-p)*0.5)
  1096. local color = string.format("%02x", r3)..string.format("%02x", g3)..string.format("%02x", b3)
  1097. minetest.register_craftitem(":dye:"..val..hue.."_s50", {
  1098. description = S(desc.." (low saturation)"),
  1099. inventory_image = "unifieddyes_dye.png^[colorize:#"..color..":200",
  1100. groups = { dye=1, not_in_creative_inventory=1 },
  1101. })
  1102. minetest.register_alias("unifieddyes:"..val..hue.."_s50", "dye:"..val..hue.."_s50")
  1103. end
  1104. end
  1105. end
  1106. -- register the greyscales too :P
  1107. for y = 1, 14 do -- colors 0 and 15 are black and white, default dyes
  1108. if y ~= 4 and y ~= 8 and y~= 11 then -- don't register the three greys, they're done separately.
  1109. local rgb = string.format("%02x", y*17)..string.format("%02x", y*17)..string.format("%02x", y*17)
  1110. local name = "grey_"..y
  1111. local desc = "Grey Dye #"..y
  1112. minetest.register_craftitem(":dye:"..name, {
  1113. description = S(desc),
  1114. inventory_image = "unifieddyes_dye.png^[colorize:#"..rgb..":200",
  1115. groups = { dye=1, not_in_creative_inventory=1 },
  1116. })
  1117. minetest.register_alias("unifieddyes:"..name, "dye:"..name)
  1118. end
  1119. end
  1120. minetest.override_item("dye:grey", {
  1121. inventory_image = "unifieddyes_dye.png^[colorize:#888888:200",
  1122. })
  1123. minetest.override_item("dye:dark_grey", {
  1124. inventory_image = "unifieddyes_dye.png^[colorize:#444444:200",
  1125. })
  1126. minetest.register_craftitem(":dye:light_grey", {
  1127. description = S("Light grey Dye"),
  1128. inventory_image = "unifieddyes_dye.png^[colorize:#cccccc:200",
  1129. groups = { dye=1, not_in_creative_inventory=1 },
  1130. })
  1131. -- build a table of color <-> palette associations to reduce the need for
  1132. -- realtime lookups with getpaletteidx()
  1133. for _, palette in ipairs({"extended", "split", "wallmounted"}) do
  1134. local palette2 = palette
  1135. for i in ipairs(unifieddyes.SATS) do
  1136. local sat = (palette == "wallmounted") and "" or unifieddyes.SATS[i]
  1137. for _, hue in ipairs(unifieddyes.HUES_EXTENDED) do
  1138. for _, val in ipairs(unifieddyes.VALS_EXTENDED) do
  1139. local color = val..hue[1]..sat
  1140. if unifieddyes.getpaletteidx("dye:"..color, palette2) then
  1141. unifieddyes.palette_has_color[palette.."_"..color] = true
  1142. end
  1143. end
  1144. end
  1145. end
  1146. for y = 0, 15 do
  1147. local grey = "grey_"..y
  1148. if y == 0 then grey = "black"
  1149. elseif y == 4 then grey = "dark_grey"
  1150. elseif y == 8 then grey = "grey"
  1151. elseif y == 11 then grey = "light_grey"
  1152. elseif y == 15 then grey = "white"
  1153. end
  1154. if unifieddyes.getpaletteidx("dye:"..grey, palette2) then
  1155. unifieddyes.palette_has_color[palette.."_"..grey] = true
  1156. end
  1157. end
  1158. end
  1159. unifieddyes.palette_has_color["wallmounted_light_red"] = true
  1160. -- crafting!
  1161. unifieddyes.base_color_crafts = {
  1162. { "red", "flowers:rose", nil, nil, nil, nil, 4 },
  1163. { "vermilion", "dye:red", "dye:orange", nil, nil, nil, 3 },
  1164. { "orange", "flowers:tulip", nil, nil, nil, nil, 4 },
  1165. { "orange", "dye:red", "dye:yellow", nil, nil, nil, 2 },
  1166. { "amber", "dye:orange", "dye:yellow", nil, nil, nil, 2 },
  1167. { "yellow", "flowers:dandelion_yellow", nil, nil, nil, nil, 4 },
  1168. { "lime", "dye:yellow", "dye:chartreuse", nil, nil, nil, 2 },
  1169. { "lime", "dye:yellow", "dye:yellow", "dye:green", nil, nil, 3 },
  1170. { "chartreuse", "dye:yellow", "dye:green", nil, nil, nil, 2 },
  1171. { "harlequin", "dye:chartreuse", "dye:green", nil, nil, nil, 2 },
  1172. { "harlequin", "dye:yellow", "dye:green", "dye:green", nil, nil, 3 },
  1173. { "green", "default:cactus", nil, nil, nil, nil, 4 },
  1174. { "green", "dye:yellow", "dye:blue", nil, nil, nil, 2 },
  1175. { "malachite", "dye:green", "dye:spring", nil, nil, nil, 2 },
  1176. { "malachite", "dye:green", "dye:green", "dye:cyan", nil, nil, 3 },
  1177. { "malachite", "dye:green", "dye:green", "dye:green", "dye:blue", nil, 4 },
  1178. { "spring", "dye:green", "dye:cyan", nil, nil, nil, 2 },
  1179. { "spring", "dye:green", "dye:green", "dye:blue", nil, nil, 3 },
  1180. { "turquoise", "dye:spring", "dye:cyan", nil, nil, nil, 2 },
  1181. { "turquoise", "dye:green", "dye:cyan", "dye:cyan", nil, nil, 3 },
  1182. { "turquoise", "dye:green", "dye:green", "dye:green", "dye:blue", "dye:blue", 5 },
  1183. { "cyan", "dye:green", "dye:blue", nil, nil, nil, 2 },
  1184. { "cerulean", "dye:cyan", "dye:azure", nil, nil, nil, 2 },
  1185. { "cerulean", "dye:cyan", "dye:cyan", "dye:blue", nil, nil, 3 },
  1186. { "cerulean", "dye:green", "dye:green", "dye:blue", "dye:blue", "dye:blue", 5 },
  1187. { "azure", "dye:cyan", "dye:blue", nil, nil, nil, 2 },
  1188. { "azure", "dye:green", "dye:blue", "dye:blue", nil, nil, 3 },
  1189. { "sapphire", "dye:azure", "dye:blue", nil, nil, nil, 2 },
  1190. { "sapphire", "dye:cyan", "dye:blue", "dye:blue", nil, nil, 3 },
  1191. { "sapphire", "dye:green", "dye:blue", "dye:blue", "dye:blue", nil, 4 },
  1192. { "blue", "flowers:geranium", nil, nil, nil, nil, 4 },
  1193. { "indigo", "dye:blue", "dye:violet", nil, nil, nil, 2 },
  1194. { "violet", "flowers:viola", nil, nil, nil, nil, 4 },
  1195. { "violet", "dye:blue", "dye:magenta", nil, nil, nil, 2 },
  1196. { "mulberry", "dye:violet", "dye:magenta", nil, nil, nil, 2 },
  1197. { "mulberry", "dye:violet", "dye:blue", "dye:red", nil, nil, 3 },
  1198. { "magenta", "dye:blue", "dye:red", nil, nil, nil, 2 },
  1199. { "fuchsia", "dye:magenta", "dye:rose", nil, nil, nil, 2 },
  1200. { "fuchsia", "dye:blue", "dye:red", "dye:rose", nil, nil, 3 },
  1201. { "fuchsia", "dye:red", "dye:violet", nil, nil, nil, 2 },
  1202. { "rose", "dye:magenta", "dye:red", nil, nil, nil, 2 },
  1203. { "rose", "dye:red", "dye:red", "dye:blue", nil, nil, 3 },
  1204. { "crimson", "dye:rose", "dye:red", nil, nil, nil, 2 },
  1205. { "crimson", "dye:magenta", "dye:red", "dye:red", nil, nil, 3 },
  1206. { "crimson", "dye:red", "dye:red", "dye:red", "dye:blue", nil, 4 },
  1207. { "black", "default:coal_lump", nil, nil, nil, nil, 4 },
  1208. { "white", "flowers:dandelion_white", nil, nil, nil, nil, 4 },
  1209. }
  1210. unifieddyes.shade_crafts = {
  1211. { "faint_", "", "dye:white", "dye:white", "dye:white", 4 },
  1212. { "pastel_", "", "dye:white", "dye:white", nil, 3 },
  1213. { "light_", "", "dye:white", nil, nil, 2 },
  1214. { "bright_", "", "color", "dye:white", nil, 3 },
  1215. { "", "_s50", "dye:light_grey", nil, nil, 2 },
  1216. { "", "_s50", "dye:black", "dye:white", "dye:white", 3 },
  1217. { "medium_", "", "dye:black", nil, nil, 2 },
  1218. { "medium_", "_s50", "dye:grey", nil, nil, 2 },
  1219. { "medium_", "_s50", "dye:black", "dye:white", nil, 3 },
  1220. { "dark_", "", "dye:black", "dye:black", nil, 3 },
  1221. { "dark_", "_s50", "dye:dark_grey", nil, nil, 2 },
  1222. { "dark_", "_s50", "dye:black", "dye:black", "dye:white", 4 },
  1223. }
  1224. for _,i in ipairs(unifieddyes.base_color_crafts) do
  1225. local color = i[1]
  1226. local yield = i[7]
  1227. minetest.register_craft( {
  1228. type = "shapeless",
  1229. output = "dye:"..color.." "..yield,
  1230. recipe = {
  1231. i[2],
  1232. i[3],
  1233. i[4],
  1234. i[5],
  1235. i[6],
  1236. },
  1237. })
  1238. for _,j in ipairs(unifieddyes.shade_crafts) do
  1239. local firstdye = j[3]
  1240. if firstdye == "color" then firstdye = "dye:"..color end
  1241. -- ignore black, white, anything containing the word "grey"
  1242. if color ~= "black" and color ~= "white" and not string.find(color, "grey") then
  1243. minetest.register_craft( {
  1244. type = "shapeless",
  1245. output = "dye:"..j[1]..color..j[2].." "..j[6],
  1246. recipe = {
  1247. "dye:"..color,
  1248. firstdye,
  1249. j[4],
  1250. j[5]
  1251. },
  1252. })
  1253. end
  1254. end
  1255. end
  1256. -- greys
  1257. unifieddyes.greymixes = {
  1258. { 1, "dye:black", "dye:black", "dye:black", "dye:dark_grey", 4 },
  1259. { 2, "dye:black", "dye:black", "dye:dark_grey", nil, 3 },
  1260. { 3, "dye:black", "dye:dark_grey", nil, nil, 2 },
  1261. { 4, "dye:white", "dye:black", "dye:black", nil, 3 },
  1262. { 5, "dye:dark_grey", "dye:dark_grey", "dye:grey", nil, 3 },
  1263. { 6, "dye:dark_grey", "dye:grey", nil, nil, 2 },
  1264. { 7, "dye:dark_grey", "dye:grey", "dye:grey", nil, 3 },
  1265. { 8, "dye:white", "dye:black", nil, nil, 2 },
  1266. { 9, "dye:grey", "dye:grey", "dye:light_grey", nil, 3 },
  1267. { 10, "dye:grey", "dye:light_grey", "dye:light_grey", nil, 3 },
  1268. { 11, "dye:white", "dye:white", "dye:black", nil, 3 },
  1269. { 12, "dye:light_grey", "dye:light_grey", "dye:white", nil, 3 },
  1270. { 13, "dye:light_grey", "dye:white", nil, nil, 2 },
  1271. { 14, "dye:white", "dye:white", "dye:light_grey", nil, 3 },
  1272. }
  1273. for _, i in ipairs(unifieddyes.greymixes) do
  1274. local shade = i[1]
  1275. local dye1 = i[2]
  1276. local dye2 = i[3]
  1277. local dye3 = i[4]
  1278. local dye4 = i[5]
  1279. local yield = i[6]
  1280. local color = "grey_"..shade
  1281. if shade == 4 then
  1282. color = "dark_grey"
  1283. elseif shade == 8 then
  1284. color = "grey"
  1285. elseif shade == 11 then
  1286. color = "light_grey"
  1287. end
  1288. minetest.register_craft( {
  1289. type = "shapeless",
  1290. output = "dye:"..color.." "..yield,
  1291. recipe = {
  1292. dye1,
  1293. dye2,
  1294. dye3,
  1295. dye4,
  1296. },
  1297. })
  1298. end
  1299. -- we can't make dark orange anymore because brown/medium orange conflicts
  1300. minetest.register_craft( {
  1301. type = "shapeless",
  1302. output = "dye:dark_orange",
  1303. recipe = {
  1304. "dye:brown",
  1305. "dye:brown"
  1306. },
  1307. })
  1308. -- aliases
  1309. minetest.register_alias("dye:light_red", "dye:pink")
  1310. minetest.register_alias("dye:medium_orange", "dye:brown")
  1311. minetest.register_alias("unifieddyes:black", "dye:black")
  1312. minetest.register_alias("unifieddyes:dark_grey", "dye:dark_grey")
  1313. minetest.register_alias("unifieddyes:grey", "dye:grey")
  1314. minetest.register_alias("unifieddyes:light_grey", "dye:light_grey")
  1315. minetest.register_alias("unifieddyes:white", "dye:white")
  1316. minetest.register_alias("unifieddyes:grey_0", "dye:black")
  1317. minetest.register_alias("unifieddyes:grey_4", "dye:dark_grey")
  1318. minetest.register_alias("unifieddyes:grey_8", "dye:grey")
  1319. minetest.register_alias("unifieddyes:grey_11", "dye:light_grey")
  1320. minetest.register_alias("unifieddyes:grey_15", "dye:white")
  1321. minetest.register_alias("unifieddyes:white_paint", "dye:white")
  1322. minetest.register_alias("unifieddyes:titanium_dioxide", "dye:white")
  1323. minetest.register_alias("unifieddyes:lightgrey_paint", "dye:light_grey")
  1324. minetest.register_alias("unifieddyes:grey_paint", "dye:grey")
  1325. minetest.register_alias("unifieddyes:darkgrey_paint", "dye:dark_grey")
  1326. minetest.register_alias("unifieddyes:carbon_black", "dye:black")
  1327. minetest.register_alias("unifieddyes:brown", "dye:brown")
  1328. print(S("[UnifiedDyes] Loaded!"))