From da55b1950eb01f202c2024f085957a3aacfbe058 Mon Sep 17 00:00:00 2001 From: flux <25628292+fluxionary@users.noreply.github.com> Date: Thu, 7 Dec 2023 13:42:10 -0800 Subject: [PATCH] make chest color4dir and add UI to change the color --- init.lua | 285 ++++++++++-------- textures/chesttools_palette_4dir.a.png | Bin 0 -> 130 bytes textures/chesttools_palette_4dir.b.png | Bin 0 -> 193 bytes .../chesttools_white_chest_lock_overlay.png | Bin 0 -> 405 bytes .../chesttools_white_chest_side_overlay.png | Bin 0 -> 307 bytes .../chesttools_white_chest_top_overlay.png | Bin 0 -> 223 bytes textures/chesttools_wood_chest_lock.png | Bin 0 -> 446 bytes .../chesttools_wood_chest_lock_overlay.png | Bin 0 -> 242 bytes textures/chesttools_wood_chest_side.png | Bin 0 -> 282 bytes .../chesttools_wood_chest_side_overlay.png | Bin 0 -> 95 bytes textures/chesttools_wood_chest_top.png | Bin 0 -> 297 bytes .../chesttools_wood_chest_top_overlay.png | Bin 0 -> 95 bytes textures/palette_builder.py | 69 +++++ 13 files changed, 222 insertions(+), 132 deletions(-) create mode 100644 textures/chesttools_palette_4dir.a.png create mode 100644 textures/chesttools_palette_4dir.b.png create mode 100644 textures/chesttools_white_chest_lock_overlay.png create mode 100644 textures/chesttools_white_chest_side_overlay.png create mode 100644 textures/chesttools_white_chest_top_overlay.png create mode 100644 textures/chesttools_wood_chest_lock.png create mode 100644 textures/chesttools_wood_chest_lock_overlay.png create mode 100644 textures/chesttools_wood_chest_side.png create mode 100644 textures/chesttools_wood_chest_side_overlay.png create mode 100644 textures/chesttools_wood_chest_top.png create mode 100644 textures/chesttools_wood_chest_top_overlay.png create mode 100644 textures/palette_builder.py diff --git a/init.lua b/init.lua index d25be8c..563c031 100644 --- a/init.lua +++ b/init.lua @@ -4,6 +4,13 @@ -- 27.07.18 Added support for shared locked chests and moved to set_node -- with inventory copying for cleaner operation. -- 05.10.14 Fixed bug in protection/access +local f = string.format +local F = minetest.formspec_escape +local S = minetest.get_translator("chesttools") +local function FS(...) + return F(S(...)) +end + chesttools = {} @@ -36,8 +43,16 @@ chesttools.chest_add = {}; chesttools.chest_add.tiles = { -- "chesttools_blue_chest_top.png", "chesttools_blue_chest_top.png", "chesttools_blue_chest_side.png", -- "chesttools_blue_chest_side.png", "chesttools_blue_chest_side.png", "chesttools_blue_chest_lock.png"}; - "chesttools_white_chest_top.png", "chesttools_white_chest_top.png", "chesttools_white_chest_side.png", - "chesttools_white_chest_side.png", "chesttools_white_chest_side.png", "chesttools_white_chest_lock.png"}; + "chesttools_wood_chest_top.png", "chesttools_wood_chest_top.png", "chesttools_wood_chest_side.png", + "chesttools_wood_chest_side.png", "chesttools_wood_chest_side.png", "chesttools_wood_chest_lock.png"}; +chesttools.chest_add.overlay_tiles = { + { name = "chesttools_wood_chest_top_overlay.png", color = "white" }, + { name = "chesttools_wood_chest_top_overlay.png", color = "white" }, + { name = "chesttools_wood_chest_side_overlay.png", color = "white" }, + { name = "chesttools_wood_chest_side_overlay.png", color = "white" }, + { name = "chesttools_wood_chest_side_overlay.png", color = "white" }, + { name = "chesttools_wood_chest_lock_overlay.png", color = "white" }, +} chesttools.chest_add.groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2}; chesttools.chest_add.tube = {}; @@ -71,27 +86,101 @@ if( has_pipeworks ) then }; end -chesttools.formspec = "size[9,10]".. - "list[current_name;main;0.5,0.3;8,4;]".. - "label[0.5,9.7;Name:]".. - "field[1.8,10.0;6,0.5;chestname;;]".. - "button[7.5,9.7;1,0.5;set_chestname;Store\nName]".. --- "button[8.6,9.7;0.5,0.5;change_color;C]".. - "image_button[8.4,9.7;0.5,0.5;chesttools_palette.png;change_color;]".. - "label[0.0,4.4;Main]".. - "button[1.0,4.5;1,0.5;craft;Craft]".. - "button[7.0,4.5;0.5,0.5;drop_all;DA]".. - "button[7.5,4.5;0.5,0.5;take_all;TA]".. - "button[8.0,4.5;0.5,0.5;swap_all;SA]".. - "button[8.5,4.5;0.5,0.5;filter_all;FA]".. - "list[current_player;main;0.5,5.5;8,4;]"; +local colorstep_by_paramtype2 = { + color = 1, + colorwallmounted = 8, + colorfacedir = 32, + color4dir = 4, +} -if( minetest.get_modpath( 'unified_inventory')) then - chesttools.formspec = chesttools.formspec.. - "button[2.0,4.5;1,0.5;bag1;Bag 1]".. - "button[3.0,4.5;1,0.5;bag2;Bag 2]".. - "button[4.0,4.5;1,0.5;bag3;Bag 3]".. - "button[5.0,4.5;1,0.5;bag4;Bag 4]"; +-- to build the default (node metadata) formspec, only `pos` is needed. +-- when showing player inventories other than "main", both "player" and "selected_inventory" must be provided +function chesttools.build_chest_formspec(pos, player, selected_inventory) + local node = minetest.get_node(pos) + local item = ItemStack(node.name) + local paramtype2 = item:get_definition().paramtype2 + local colorstep = colorstep_by_paramtype2[paramtype2] + local param2 = node.param2 + local item_meta = item:get_meta() + item_meta:set_int("palette_index", param2) + local itemstring = item:to_string() + local node_meta = minetest.get_meta(pos) + local chestname = node_meta:get_string("chestname") + selected_inventory = selected_inventory or "main" + -- the parts that are common + local fs_parts = { + "size[9.5,10]", + "list[context;main;0.5,0.3;8,4;]", + "label[0.5,9.7;Name:]", + f("field[1.8,10.0;6,0.5;chestname;;%s]", F(chestname) or "unconfigured"), + f("button[7.5,9.7;1,0.5;set_chestname;%s]", FS("Store\nName")), + f("label[8.65,9;#%s]", F(tostring(math.floor(param2 / colorstep)))), + "button[7.0,4.5;0.5,0.5;drop_all;DA]", + "button[7.5,4.5;0.5,0.5;take_all;TA]", + "button[8.0,4.5;0.5,0.5;swap_all;SA]", + "button[8.5,4.5;0.5,0.5;filter_all;FA]", + "listring[context;main]", + f("field[20,20;0.1,0.1;pos2str;Pos;%s]", minetest.pos_to_string(pos)), + f("field[20,20;0.1,0.1;selected;selected;%s]", selected_inventory or "main"), + -- https://github.com/minetest/minetest/issues/13435 + f("item_image_button[8.5,8.2;1,1;%s;do_nothing;]", F(itemstring)), + "button[8.5,9.5;0.5,0.5;previous_color;<]", + "button[9.0,9.5;0.5,0.5;next_color;>]", + } + if selected_inventory == "main" then + table.insert_all(fs_parts, { + f("label[0.0,4.4;%s]", FS("Main")), + "list[current_player;main;0.5,5.5;8,4;]", + "listring[current_player;main]", + }) + else + table.insert(fs_parts, f("button[0.0,4.5;1,0.5;main;%s]", FS("Main"))) + end + if selected_inventory == "craft" then + table.insert_all(fs_parts, { + f("label[1.0,4.4;%s]", FS("Craft")), + f("label[0,5.5;%s]", FS("Crafting")), + "list[current_player;craftpreview;6.5,6.5;1,1;]", + "list[current_player;craft;2.5,6.5;3,3;]", + "listring[current_player;craft]", + "listring[context;main]", + "listring[current_player;craftpreview]", + }) + else + fs_parts[#fs_parts + 1] = f("button[1.0,4.5;1,0.5;craft;%s]", FS("Craft")) + end + + if minetest.get_modpath("unified_inventory") then + local function dobag(i, offset) + local bagi = f("bag%i", i) + local label = FS(f("Bag %i", i)) + + if player and selected_inventory == bagi then + fs_parts[#fs_parts + 1] = f("label[%f,4.4;%s]", offset, label) -- main label + local player_name = player:get_player_name() + local bags_inv_name = f("%s_bags", player_name) + local bags_inv = minetest.get_inventory({ type = "detached", name = bags_inv_name }) + fs_parts[#fs_parts + 1] = f("label[0.5,5.5;%s]", label) -- bag slot label + fs_parts[#fs_parts + 1] = f("list[detached:%s;%s;1.5,5.5;1,1;]", F(bags_inv_name), bagi) + local bag_item = bags_inv:get_stack(bagi, 1) + if bag_item:is_empty() then + fs_parts[#fs_parts + 1] = f("label[0.5,6.5;%s]", FS("You have no bag in this slot.")) + else + fs_parts[#fs_parts + 1] = f("list[current_player;%scontents;0.5,6.5;8,4;]", bagi) + fs_parts[#fs_parts + 1] = f("listring[current_player;%scontents]", bagi) + end + else + fs_parts[#fs_parts + 1] = f("button[%f,4.5;1,0.5;%s;%s]", offset, bagi, label) + end + end + + dobag(1, 2.0) + dobag(2, 3.0) + dobag(3, 4.0) + dobag(4, 5.0) + end + + return table.concat(fs_parts, "") end @@ -117,25 +206,30 @@ chesttools.may_use = function( pos, player ) return false; end +local function change_color(pos, direction) + local meta = minetest.get_meta(pos) + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + if def then + local add = (colorstep_by_paramtype2[def.paramtype2] or 0) * direction + minetest.swap_node(pos, {name=node.name, param2=(node.param2 + add) % 256}) + meta:set_string("formspec", chesttools.build_chest_formspec(pos)) + end +end chesttools.on_receive_fields = function(pos, formname, fields, player) if( fields.quit and fields.quit ~= "") then return; end - if( fields.change_color ) then - local node = minetest.get_node( pos ) - local add = 0 - if(node and node.name and minetest.registered_nodes[node.name]) then - local def = minetest.registered_nodes[node.name] - if(def and def.paramtype2 == "colorfacedir") then - add = 32 - elseif(def and def.paramtype2 == "colorwallmounted") then - add = 8 - end - minetest.swap_node(pos, {name=node.name, param2=(node.param2 + add) % 256}) - return - end + if fields.do_nothing then + return + end + + if fields.next_color then + change_color(pos, 1) + elseif fields.previous_color then + change_color(pos, -1) end local meta = minetest.get_meta( pos ); @@ -146,30 +240,9 @@ chesttools.on_receive_fields = function(pos, formname, fields, player) meta:set_string( 'chestname', chestname ); meta:set_string("infotext", "\""..chestname.."\" Chest (owned by "..meta:get_string("owner")..")") -- update the normal formspec - meta:set_string("formspec", chesttools.formspec.. - "listring[current_name;main]".. - "listring[current_player;main]".. - "field[1.8,10.0;6,0.5;chestname;;"..chestname.."]"); + meta:set_string("formspec", chesttools.build_chest_formspec(pos)); end - local formspec = "size[9,10]".. - "label[0.5,9.7;Name:]".. - "field[1.8,10.0;6,0.5;chestname;;"..tostring( chestname or "unconfigured").."]".. - "button[7.5,9.7;1,0.5;set_chestname;Store\nName]".. --- "button[8.6,9.7;0.5,0.5;change_color;C]".. - "image_button[8.4,9.7;0.5,0.5;chesttools_palette.png;change_color;]".. - "list[current_name;main;0.5,0.3;8,4;]".. - "button[7.0,4.5;0.5,0.5;drop_all;DA]".. - "button[7.5,4.5;0.5,0.5;take_all;TA]".. - "button[8.0,4.5;0.5,0.5;swap_all;SA]".. - "button[8.5,4.5;0.5,0.5;filter_all;FA]" - local bm = "button[0.0,4.5;1,0.5;main;Main]"; - local bc = "button[1.0,4.5;1,0.5;craft;Craft]"; - local b1 = "button[2.0,4.5;1,0.5;bag1;Bag 1]"; - local b2 = "button[3.0,4.5;1,0.5;bag2;Bag 2]"; - local b3 = "button[4.0,4.5;1,0.5;bag3;Bag 3]"; - local b4 = "button[5.0,4.5;1,0.5;bag4;Bag 4]"; - local selected = ''; if( fields.drop_all or fields.take_all or fields.swap_all or fields.filter_all ) then @@ -245,78 +318,30 @@ chesttools.on_receive_fields = function(pos, formname, fields, player) end end - local bag_nr = 0; if( fields[ 'main'] or selected=='main' or fields['set_chestname']) then - bag_nr = 0; - formspec = formspec.. - "list[current_player;main;0.5,5.5;8,4;]".. - "listring[nodemeta:" .. spos .. ";main]".. - "listring[current_player;main]" - bm = "label[0.0,4.4;Main]"; selected = 'main'; elseif( fields[ 'craft'] or selected=='craft') then - bag_nr = 0; - formspec = formspec.. - "label[0,5.5;Crafting]".. - "list[current_player;craftpreview;6.5,6.5;1,1;]".. - "list[current_player;craft;2.5,6.5;3,3;]".. - "listring[nodemeta:" .. spos .. ";main]".. - "listring[current_player;craft]" - bc = "label[1.0,4.4;Craft]"; selected = 'craft'; elseif( fields[ 'bag1' ] or selected=='bag1') then - bag_nr = 1; - b1 = "label[2.0,4.4;Bag 1]"; selected = 'bag1'; elseif( fields[ 'bag2' ] or selected=='bag2') then - bag_nr = 2; - b2 = "label[3.0,4.4;Bag 2]"; selected = 'bag2'; elseif( fields[ 'bag3' ] or selected=='bag3') then - bag_nr = 3; - b3 = "label[4.0,4.4;Bag 3]"; selected = 'bag3'; elseif( fields[ 'bag4' ] or selected=='bag4') then - bag_nr = 4; - b4 = "label[5.0,4.4;Bag 4]"; selected = 'bag4'; end - if( bag_nr >= 1 and bag_nr <= 4 ) then - formspec = formspec.. - "label[0.5,5.5;Bag "..bag_nr.."]"; - local stack = player:get_inventory():get_stack( "bag"..bag_nr, 1) - if( stack ) then - local pname_esc = minetest.formspec_escape(player:get_player_name()); - formspec = formspec.."list[detached:"..pname_esc.."_bags;bag".. - tostring(bag_nr)..";1.5,5.5;1,1;]"; - local bag = minetest.get_inventory({type="detached", name=pname_esc.."_bags"},"bag"..tostring(bag_nr)) - local slots = 4*8; - if( bag and not(bag:get_stack("bag"..tostring(bag_nr),1):is_empty())) then -- no bag present? - formspec = formspec.. - "list[current_player;bag"..tostring(bag_nr).."contents;0.5,6.5;8,"..tostring(slots/8)..";]".. - "listring[nodemeta:" .. spos .. ";main]".. - "listring[current_player;bag"..tostring(bag_nr).."contents]" - else - formspec = formspec.. - "label[0.5,6.5;You have no bag in this slot.]" - end - end + if not selected or selected == '' then + selected = fields.selected end - - formspec = formspec..bm..bc..b1..b2..b3..b4.. - -- provide the position of the chest - "field[20,20;0.1,0.1;pos2str;Pos;"..minetest.pos_to_string( pos ).."]".. - -- which inventory was selected? - "field[20,20;0.1,0.1;selected;selected;"..selected.."]"; - -- instead of updating the formspec of the chest - which would be slow - we display -- the new formspec directly to the player who asked for it; -- this is also necessary because players may have bags with diffrent sizes - minetest.show_formspec( player:get_player_name(), "chesttools:shared_chest", formspec ); + minetest.show_formspec( player:get_player_name(), "chesttools:shared_chest", chesttools.build_chest_formspec(pos, player, selected) ); end @@ -477,6 +502,10 @@ chesttools.register_chest = function(node_name, desc, name, paramtype2, palette, legacy_facedir_simple = true, is_ground_content = false, sounds = default.node_sound_wood_defaults(), + overlay_tiles = chesttools.chest_add.overlay_tiles, + use_texture_alpha = "clip", + color = "#4900ff", -- hoping this colors the inventory image... + drop = node_name, after_place_node = function(pos, placer) local meta = minetest.get_meta(pos) @@ -493,9 +522,7 @@ chesttools.register_chest = function(node_name, desc, name, paramtype2, palette, meta:set_string("owner", "") local inv = meta:get_inventory() inv:set_size("main", 8*4) - meta:set_string("formspec", chesttools.formspec.. - "listring[current_name;main]".. - "listring[current_player;main]") + meta:set_string("formspec", chesttools.build_chest_formspec(pos)) end, can_dig = function(pos, player) @@ -613,9 +640,10 @@ end chesttools.register_chest("chesttools:shared_chest", 'Shared chest which can be used by all who can build at that spot', 'shared chest', - 'colorfacedir', - 'chesttools_palette.png', - chesttools.chest_add.tiles) + "color4dir", + "chesttools_palette_4dir.b.png", + chesttools.chest_add.tiles, + chesttools.chest_add.overlay_tiles) minetest.register_craft({ output = 'chesttools:shared_chest', @@ -623,23 +651,16 @@ minetest.register_craft({ recipe = { 'default:steel_ingot', 'default:chest_locked' }, }) -chesttools.register_chest("chesttools:shared_chest_wall", - 'Shared chest which can be used by all who can build at that spot (wallmounted)', - 'shared chest (wallmounted)', - 'colorwallmounted', - 'chesttools_palette_wallmounted.png', - {chesttools.chest_add.tiles[6], - chesttools.chest_add.tiles[3].."^[transformR180", - chesttools.chest_add.tiles[3].."^[transformR270", - chesttools.chest_add.tiles[3].."^[transformR90", - chesttools.chest_add.tiles[1].."^[transformR90", - chesttools.chest_add.tiles[1].."^[transformR90", - chesttools.chest_add.tiles[1], - }) +minetest.register_alias("chesttools:shared_chest_4dir", "chesttools:shared_chest") +minetest.register_alias("chesttools:shared_chest_wall", "chesttools:shared_chest") -minetest.register_craft({ - output = 'chesttools:shared_chest_wall', - type = 'shapeless', - recipe = { 'default:steel_ingot', 'chesttools:shared_chest' }, +minetest.register_lbm({ + name = "chesttools:update_chest_formspec", + label = "update chest formspec", + nodenames = { "chesttools:shared_chest" }, + run_at_every_load = true, + action = function(pos, node, dtime_s) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", chesttools.build_chest_formspec(pos)) + end, }) - diff --git a/textures/chesttools_palette_4dir.a.png b/textures/chesttools_palette_4dir.a.png new file mode 100644 index 0000000000000000000000000000000000000000..98bedb749a99b8206b14e425ef561f98f552fd43 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^4nWMv!2~29^4o(ro}Mm_Ar*5@7UL{LoA9X4S+~;7i3egDA-@s*UV!yoo+6VE6&HuMw5IkWK dYPxwb`&SvI|0XkdihzbPc)I$ztaD0e0sylFD9Zo< literal 0 HcmV?d00001 diff --git a/textures/chesttools_palette_4dir.b.png b/textures/chesttools_palette_4dir.b.png new file mode 100644 index 0000000000000000000000000000000000000000..dec82a74812ca71b6f9ca83b64627bef08bd90e0 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^4nWMv!2~29^4o(r9iA?ZAr*624>Iz$7znsrT+hh6 zb%P_*N|q*;Anp{E7_CNy#9-cv6>KJF_PQTseLJz==0juM#9*`FEj_n?`3Pqp%j9iV zP}bSGaH`E==Xon8mjAeH(EcOUXZ0+lZ#~BkvFc8oeW%df^wXsHoFylw_?m|nE{zL5 sv*mdKI;Vst0M5ruR{#J2 literal 0 HcmV?d00001 diff --git a/textures/chesttools_white_chest_lock_overlay.png b/textures/chesttools_white_chest_lock_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..c83319cd33af5d4f9e3667e7b27bdfbddc23b4cc GIT binary patch literal 405 zcmV;G0c!qLMcU(Bml%1Da#UL4BmS}2oyzuwH9Lxq-iSDjMM2P zS}9exA7c#KIahl?RaIE6^+z#HQ(3Rq01SsiCX>lus4+&={eG9n@%$n%^|r^9BmVKf>cBD~*kTCEn&IqY`31;Bexj1lJ?^ZA@!uSd7rWxwCkY&Kb~ zR(S6ziUQ{xRaO1LIG@iSuP~iXf9tc^?4##;y^0PYeB435-~Y`AgTY6Sh(MNQU;kjS zSjcj@{Hk9r7vXq3)_$Zc%S3-WohLI?p7A;yS^;JxPuu0f-rp&PxB00000NkvXXu0mjfcv-L% literal 0 HcmV?d00001 diff --git a/textures/chesttools_white_chest_side_overlay.png b/textures/chesttools_white_chest_side_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..02990adbe86ae0c51fee4857d6e22fb24b15bfa7 GIT binary patch literal 307 zcmV-30nGl1P)~=fM3^M~jL>R{r z0C%U>O3s;ip6R{g?)2V?2#ULNJRXGwy4`M(L>74g=)IFvl{HE!rNw49Sh*;MHGb5E!){>%dpI00Gu$0jB_epeUJS#)e!s`e_ydC>iheu9F6gM)*Gg@uNOhKq}fjEszqj*gO&l9ZH` zmzS5Do131Vo}ZteprD|kp`oLrqo$^&sHmu`tE;T6tgf!Ev9YnYx3{^uxx2f&yu7@@ z!NJ19!q?Z=+}zyV-QDHo|1^xg3GI`+1`?Par=a$jvPgCFVJmk7w5MaE}z~6Bp@~k*WrDUvuvo9sYMFm~= zY_JAF25f#Oq?$vr91ljH&+9wflZjHlyh>rB?l>$i48;!3<$|ZSqfr`Ri#!{OVzgRR)g^x*dBl-EXz{gm~Lo@mz2`Y oI!R4ai$*hqLL5aQ<@kU64|T#5)fGkIN&o-=07*qoM6N<$f)fwS#sB~S literal 0 HcmV?d00001 diff --git a/textures/chesttools_wood_chest_lock_overlay.png b/textures/chesttools_wood_chest_lock_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f52baad7af0d4ab9e516ccb8b8b521503a702c GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`J3U<-Lo7~Tovg^$>>%KJ-z0QS z0w;%%ipml;Z(+U-qH|gcnEHbHSFT@i(9}_>icKZ$wSceth0wocYWDg6&Ul2X@X7y_ z2yuPHSK(#)VppE>>)&xpZL(T-t&6;Vm9Zspg;2+|gI~WfBt(k!7{;7apZnln&B^q{ zdFkS=f{!hPSPovFx5{IVm6OczC7D_bhYjAGPne~4Yg=jLw29Au{?m=fUaI5WV<>%6 qkEvl<=9A~vAMBR=Hx#&EUdOz?#c;{2YD5Cs+JGVtP2F9`}HN0m-t_L_l8X=k@Y%O4CXy(R;2@Pdz*>0rTfWz`6qLkpKVy07*qoM6N<$f^MR5F#rGn literal 0 HcmV?d00001 diff --git a/textures/chesttools_wood_chest_side_overlay.png b/textures/chesttools_wood_chest_side_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c7f4084f5d3503dbe9c1b352b45892777fe45a GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`YMw5RAr_~Tw_FeZao&M*!4Zb) s+SdO*JR(hv<_(1=0`9yLa+-n+0*kr63LKxk6R3m1)78&qol`;+08sK8YybcN literal 0 HcmV?d00001 diff --git a/textures/chesttools_wood_chest_top.png b/textures/chesttools_wood_chest_top.png new file mode 100644 index 0000000000000000000000000000000000000000..823c50079a6314009014e0a1cd394b28d00d3c65 GIT binary patch literal 297 zcmV+^0oMMBP)9efRDU?@Uj)#_sMH00000NkvXXu0mjfQGtB? literal 0 HcmV?d00001 diff --git a/textures/chesttools_wood_chest_top_overlay.png b/textures/chesttools_wood_chest_top_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..97029214b8d3c38e97c2bff6fd7fc0bb315c927b GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`YMw5RAr_~Tw_FeZao&M*!4Zb) s+SdO*JR(hj%x=6ArVLCHnrF{3_mdKI;Vst08FYHo&W#< literal 0 HcmV?d00001 diff --git a/textures/palette_builder.py b/textures/palette_builder.py new file mode 100644 index 0000000..9de4a55 --- /dev/null +++ b/textures/palette_builder.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +from PIL import Image, ImageColor + +target_initial_hue = 254 + + +def tween_closed(minimum, maximum, steps): + yield minimum + step_size = (maximum - minimum) / (steps - 1) + for i in range(1, steps): + yield minimum + step_size * i + + +def tween_half_open(minimum, maximum, steps): + yield minimum + step_size = (maximum - minimum) / steps + for i in range(1, steps): + yield minimum + step_size * i + + +img = Image.new(mode="RGB", size=(64, 1)) + +grays = tuple(tween_closed(0, 255, 8)) +hues = tuple(tween_half_open(0, 360, 56)) + +offset = 0 +for hue in hues: + if abs(hue - target_initial_hue) < abs(offset - target_initial_hue): + offset = hue + +i = 0 +for hue in hues: + offset_hue = (hue + offset) % 360 + img.putpixel((i, 0), ImageColor.getrgb(f'hsv({offset_hue},100%,100%)')) + i = i + 1 + +for gray in map(round, grays): + img.putpixel((i, 0), (gray, gray, gray)) + i = i + 1 + +img.save('chesttools_palette_4dir.a.png', 'PNG') + +img = Image.new(mode="RGB", size=(64, 1)) +hues = tuple(tween_half_open(0, 360, 14)) + +offset = 0 +for hue in hues: + if abs(hue - target_initial_hue) < abs(offset - target_initial_hue): + offset = hue + +i = 0 +for hue in hues: + offset_hue = (hue + offset) % 360 + img.putpixel((i, 0), ImageColor.getrgb(f'hsv({offset_hue},100%,100%)')) + i = i + 1 + img.putpixel((i, 0), ImageColor.getrgb(f'hsv({offset_hue},100%,50%)')) + i = i + 1 + img.putpixel((i, 0), ImageColor.getrgb(f'hsv({offset_hue},70.7%,70.7%)')) + i = i + 1 + img.putpixel((i, 0), ImageColor.getrgb(f'hsv({offset_hue},50%,100%)')) + i = i + 1 + +for gray in map(round, grays): + img.putpixel((i, 0), (gray, gray, gray)) + i = i + 1 + + +img.save('chesttools_palette_4dir.b.png', 'PNG')