SmallJoker
2022-10-20 4775d98fb7e12f7210cf778351767828e551011d
commit | author | age
41a10a 1 local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
179364 2
fcef0e 3 local pipeworks = rawget(_G, "pipeworks")
0f6bdb 4 local fs_helpers
8a987b 5 local tubelib_exists = minetest.global_exists("tubelib")
11f20d 6
VE 7 local allow_label = ""
b6d343 8 local tube_entry = ""
11f20d 9 local shift_edit_field = 0
VE 10
fcef0e 11 if not minetest.get_modpath("pipeworks") then
R 12     -- Pipeworks is not installed. Simulate using a dummy table...
13     pipeworks = {}
11f20d 14     fs_helpers = {}
fcef0e 15     local pipeworks_meta = {}
R 16     setmetatable(pipeworks, pipeworks_meta)
17     local dummy = function()
18         end
19     pipeworks_meta.__index = function(table, key)
20             print("[technic_chests] WARNING: variable or method '"..key.."' not present in dummy pipeworks table - assuming it is a method...")
21             pipeworks[key] = dummy
22             return dummy
23         end
24     pipeworks.after_place = dummy
25     pipeworks.after_dig = dummy
11f20d 26     fs_helpers.cycling_button = function() return "" end
VE 27 else
28     fs_helpers = pipeworks.fs_helpers
29     allow_label = "label[0.9,0.36;Allow splitting incoming stacks from tubes]"
30     shift_edit_field = 3
b6d343 31     tube_entry = "^pipeworks_tube_connection_metallic.png"
fcef0e 32 end
R 33
78cacd 34 local chest_mark_colors = {
179364 35     {"black", S("Black")},
S 36     {"blue", S("Blue")},
37     {"brown", S("Brown")},
39c41a 38     {"cyan", S("Cyan")},
179364 39     {"dark_green", S("Dark Green")},
S 40     {"dark_grey", S("Dark Grey")},
41     {"green", S("Green")},
42     {"grey", S("Grey")},
43     {"magenta", S("Magenta")},
44     {"orange", S("Orange")},
45     {"pink", S("Pink")},
46     {"red", S("Red")},
47     {"violet", S("Violet")},
48     {"white", S("White")},
49     {"yellow", S("Yellow")},
78cacd 50 }
S 51
52
53 local function colorid_to_postfix(id)
179364 54     return chest_mark_colors[id] and "_"..chest_mark_colors[id][1] or ""
78cacd 55 end
S 56
57
1bf52c 58 local function get_color_buttons(coleft, lotop)
78cacd 59     local buttons_string = ""
S 60     for y = 0, 3 do
61         for x = 0, 3 do
62             local file_name = "technic_colorbutton"..(y * 4 + x)..".png"
63             buttons_string = buttons_string.."image_button["
1bf52c 64                 ..(coleft + 0.1 + x * 0.7)..","..(lotop + 0.1 + y * 0.7)
78cacd 65                 ..";0.8,0.8;"..file_name..";color_button"
S 66                 ..(y * 4 + x + 1)..";]"
67         end
68     end
69     return buttons_string
70 end
71
72
73 local function check_color_buttons(pos, meta, chest_name, fields)
74     for i = 1, 16 do
75         if fields["color_button"..i] then
d60e3f 76             local node = minetest.get_node(pos)
Z 77             node.name = chest_name..colorid_to_postfix(i)
78             minetest.swap_node(pos, node)
179364 79             meta:set_string("color", i)
78cacd 80             return
S 81         end
82     end
83 end
84
5c689a 85 local function set_formspec(pos, data, page)
R 86     local meta = minetest.get_meta(pos)
1bf52c 87     local formspec = data.base_formspec
11f20d 88     formspec = formspec..fs_helpers.cycling_button(
VE 89                 meta,
90                 "image_button[0,0.35;1,0.6",
91                 "splitstacks",
92                 {
fab2c4 93                     pipeworks.button_off,
d2fb24 94                     pipeworks.button_on
11f20d 95                 }
VE 96             )..allow_label
97
5c689a 98     if data.autosort then
R 99         local status = meta:get_int("autosort")
0f6bdb 100         formspec = formspec.."button["..(data.hileft+2)..","..(data.height+1.1)..";3,0.8;autosort_to_"..(1-status)..";"..
S 101             S("Auto-sort is %s"):format(status == 1 and S("On") or S("Off")).."]"
78cacd 102     end
5c689a 103     if data.infotext then
78cacd 104         local formspec_infotext = minetest.formspec_escape(meta:get_string("infotext"))
5c689a 105         if page == "main" then
11f20d 106             formspec = formspec.."image_button["..(shift_edit_field+data.hileft+2.1)..",0.1;0.8,0.8;"
78cacd 107                     .."technic_pencil_icon.png;edit_infotext;]"
11f20d 108                     .."label["..(shift_edit_field+data.hileft+3)..",0;"..formspec_infotext.."]"
5c689a 109         elseif page == "edit_infotext" then
11f20d 110             formspec = formspec.."image_button["..(shift_edit_field+data.hileft+2.1)..",0.1;0.8,0.8;"
78cacd 111                     .."technic_checkmark_icon.png;save_infotext;]"
11f20d 112                     .."field["..(shift_edit_field+data.hileft+3.3)..",0.2;4.8,1;"
179364 113                     .."infotext_box;"..S("Edit chest description:")..";"
78cacd 114                     ..formspec_infotext.."]"
S 115         end
5c689a 116     end
R 117     if data.color then
118         local colorID = meta:get_int("color")
119         local colorName
120         if chest_mark_colors[colorID] then
121             colorName = chest_mark_colors[colorID][2]
122         else
123             colorName = S("None")
124         end
1bf52c 125         formspec = formspec.."label["..(data.coleft+0.2)..","..(data.lotop+3)..";"..S("Color Filter: %s"):format(colorName).."]"
5c689a 126     end
R 127     meta:set_string("formspec", formspec)
128 end
129
130 local function sort_inventory(inv)
131     local inlist = inv:get_list("main")
132     local typecnt = {}
133     local typekeys = {}
134     for _, st in ipairs(inlist) do
135         if not st:is_empty() then
136             local n = st:get_name()
137             local w = st:get_wear()
138             local m = st:get_metadata()
139             local k = string.format("%s %05d %s", n, w, m)
140             if not typecnt[k] then
930c51 141                 typecnt[k] = {st}
5c689a 142                 table.insert(typekeys, k)
930c51 143             else
D 144                 table.insert(typecnt[k], st)
5c689a 145             end
R 146         end
147     end
148     table.sort(typekeys)
930c51 149     inv:set_list("main", {})
5c689a 150     for _, k in ipairs(typekeys) do
930c51 151         for _, item in ipairs(typecnt[k]) do
D 152             inv:add_item("main", item)
5c689a 153         end
R 154     end
155 end
156
157 local function get_receive_fields(name, data)
158     local lname = name:lower()
159     return function(pos, formname, fields, sender)
160         local meta = minetest.get_meta(pos)
161         local page = "main"
4a9ad9 162
HL 163         local owner = meta:get_string("owner")
164         if owner ~= "" then
165             -- prevent modification of locked chests
166             if owner ~= sender:get_player_name() then return end
167         elseif not fields.quit then
168             -- prevent modification of protected chests
169             if minetest.is_protected(pos, sender:get_player_name()) then return end
170         end
171
5c689a 172         if fields.sort or (data.autosort and fields.quit and meta:get_int("autosort") == 1) then
R 173             sort_inventory(meta:get_inventory())
174         end
175         if fields.edit_infotext then
176             page = "edit_infotext"
177         end
178         if fields.autosort_to_1 then meta:set_int("autosort", 1) end
179         if fields.autosort_to_0 then meta:set_int("autosort", 0) end
180         if fields.infotext_box then
181             meta:set_string("infotext", fields.infotext_box)
182         end
78cacd 183         if data.color then
S 184             -- This sets the node
185             local nn = "technic:"..lname..(data.locked and "_locked" or "").."_chest"
186             check_color_buttons(pos, meta, nn, fields)
187         end
11f20d 188         if fields["fs_helpers_cycling:0:splitstacks"]
VE 189           or fields["fs_helpers_cycling:1:splitstacks"] then
190             if not pipeworks.may_configure(pos, sender) then return end
191             fs_helpers.on_receive_fields(pos, fields)
192         end
193
96ad67 194         meta:get_inventory():set_size("main", data.width * data.height)
5c689a 195         set_formspec(pos, data, page)
78cacd 196     end
S 197 end
198
1d7cb7 199 function technic.chests:definition(name, data)
78cacd 200     local lname = name:lower()
179364 201     name = S(name)
1bf52c 202     local d = {}
Z 203     for k, v in pairs(data) do d[k] = v end
204     data = d
78cacd 205
1bf52c 206     data.lowidth = 8
Z 207     data.ovwidth = math.max(data.lowidth, data.width)
208     data.hileft = (data.ovwidth - data.width) / 2
209     data.loleft = (data.ovwidth - data.lowidth) / 2
210     if data.color then
211         if data.lowidth + 3 <= data.ovwidth then
212             data.coleft = data.ovwidth - 3
213             if data.loleft + data.lowidth > data.coleft then
214                 data.loleft = data.coleft - data.lowidth
215             end
216         else
217             data.loleft = 0
218             data.coleft = data.lowidth
219             data.ovwidth = data.lowidth + 3
220         end
221     end
222     data.lotop = data.height + 2
223     data.ovheight = data.lotop + 4
78cacd 224
S 225     local front = {"technic_"..lname.."_chest_front.png"}
473505 226     data.base_formspec = "size["..data.ovwidth..","..data.ovheight.."]"..
39c41a 227             "label[0,0;"..S("%s Chest"):format(name).."]"..
473505 228             "list[context;main;"..data.hileft..",1;"..data.width..","..data.height..";]"..
1bf52c 229             "list[current_player;main;"..data.loleft..","..data.lotop..";8,4;]"..
24eca0 230             "background[-0.19,-0.25;"..(data.ovwidth+0.4)..","..(data.ovheight+0.75)..";technic_chest_form_bg.png]"..
1bf52c 231             "background["..data.hileft..",1;"..data.width..","..data.height..";technic_"..lname.."_chest_inventory.png]"..
d732c8 232             "background["..data.loleft..","..data.lotop..";8,4;technic_main_inventory.png]"..
E 233             "listring[]"
11f20d 234
5c689a 235     if data.sort then
1bf52c 236         data.base_formspec = data.base_formspec.."button["..data.hileft..","..(data.height+1.1)..";1,0.8;sort;"..S("Sort").."]"
5c689a 237     end
78cacd 238     if data.color then
1bf52c 239         data.base_formspec = data.base_formspec..get_color_buttons(data.coleft, data.lotop)
78cacd 240     end
S 241
0f6bdb 242     local locked_after_place
78cacd 243     if data.locked then
S 244         locked_after_place = function(pos, placer)
245             local meta = minetest.get_meta(pos)
246             meta:set_string("owner", placer:get_player_name() or "")
179364 247             meta:set_string("infotext",
S 248                     S("%s Locked Chest (owned by %s)")
249                     :format(name, meta:get_string("owner")))
cbfeb0 250             pipeworks.after_place(pos)
78cacd 251         end
S 252         table.insert(front, "technic_"..lname.."_chest_lock_overlay.png")
cbfeb0 253     else
VE 254         locked_after_place = pipeworks.after_place
78cacd 255     end
S 256
179364 257     local desc
S 258     if data.locked then
259         desc = S("%s Locked Chest"):format(name)
260     else
261         desc = S("%s Chest"):format(name)
262     end
263
b6d343 264     local tentry = tube_entry
VE 265     if tube_entry ~= "" then
266         if lname == "wooden" then
267             tentry = "^pipeworks_tube_connection_wooden.png"
268         elseif lname == "mithril" then
269             tentry = "^pipeworks_tube_connection_stony.png"
270         end
271     end
78cacd 272     local def = {
179364 273         description = desc,
b6d343 274         tiles = {
VE 275             "technic_"..lname.."_chest_top.png"..tentry,
276             "technic_"..lname.."_chest_top.png"..tentry,
277             "technic_"..lname.."_chest_side.png"..tentry,
278             "technic_"..lname.."_chest_side.png"..tentry,
279             "technic_"..lname.."_chest_side.png"..tentry,
280             table.concat(front, "^")
281         },
78cacd 282         paramtype2 = "facedir",
S 283         groups = self.groups,
284         tube = self.tube,
285         legacy_facedir_simple = true,
286         sounds = default.node_sound_wood_defaults(),
cbfeb0 287         after_place_node = locked_after_place,
d5db18 288         after_dig_node = pipeworks.after_dig,
VE 289
78cacd 290         on_construct = function(pos)
S 291             local meta = minetest.get_meta(pos)
179364 292             meta:set_string("infotext", S("%s Chest"):format(name))
5c689a 293             set_formspec(pos, data, "main")
78cacd 294             local inv = meta:get_inventory()
96ad67 295             inv:set_size("main", data.width * data.height)
78cacd 296         end,
S 297         can_dig = self.can_dig,
298         on_receive_fields = get_receive_fields(name, data),
299         on_metadata_inventory_move = self.on_inv_move,
300         on_metadata_inventory_put = self.on_inv_put,
930c51 301         on_metadata_inventory_take = self.on_inv_take,
6b52c7 302         on_blast = function(pos)
T 303             local drops = {}
304             default.get_inventory_drops(pos, "main", drops)
ec6354 305             drops[#drops+1] = "technic:"..name:lower()..(data.locked and "_locked" or "").."_chest"
6b52c7 306             minetest.remove_node(pos)
T 307             return drops
308         end,
78cacd 309     }
S 310     if data.locked then
311         def.allow_metadata_inventory_move = self.inv_move
312         def.allow_metadata_inventory_put = self.inv_put
313         def.allow_metadata_inventory_take = self.inv_take
35da22 314         def.on_blast = function() end
ec6354 315         def.can_dig = function(pos,player)
T 316             local meta = minetest.get_meta(pos);
317             local inv = meta:get_inventory()
318             return inv:is_empty("main") and default.can_interact_with_node(player, pos)
35da22 319         end
6b52c7 320         def.on_skeleton_key_use = function(pos, player, newsecret)
T 321             local meta = minetest.get_meta(pos)
322             local owner = meta:get_string("owner")
323             local name = player:get_player_name()
324
325             -- verify placer is owner of lockable chest
326             if owner ~= name then
327                 minetest.record_protection_violation(pos, name)
328                 minetest.chat_send_player(name, "You do not own this chest.")
329                 return nil
330             end
331
332             local secret = meta:get_string("key_lock_secret")
333             if secret == "" then
334                 secret = newsecret
335                 meta:set_string("key_lock_secret", secret)
336             end
337
338             return secret, "a locked chest", owner
35da22 339         end
78cacd 340     end
1d7cb7 341     return def
Z 342 end
78cacd 343
8a987b 344 local _TUBELIB_CALLBACKS = {
O 345     on_pull_item = function(pos, side, player_name)
346         if not minetest.is_protected(pos, player_name) then
347             local inv = minetest.get_meta(pos):get_inventory()
348             for _, stack in pairs(inv:get_list("main")) do
349                 if not stack:is_empty() then
350                     return inv:remove_item("main", stack:get_name())
351                 end
352             end
353         end
354         return nil
355     end,
356     on_push_item = function(pos, side, item, player_name)
357         local inv = minetest.get_meta(pos):get_inventory()
358         if inv:room_for_item("main", item) then
359             inv:add_item("main", item)
360             return true
361         end
362         return false
363     end,
364     on_unpull_item = function(pos, side, item, player_name)
365         local inv = minetest.get_meta(pos):get_inventory()
366         if inv:room_for_item("main", item) then
367             inv:add_item("main", item)
368             return true
369         end
370         return false
371     end,
372 }
373
1d7cb7 374 function technic.chests:register(name, data)
Z 375     local def = technic.chests:definition(name, data)
78cacd 376
1d7cb7 377     local nn = "technic:"..name:lower()..(data.locked and "_locked" or "").."_chest"
78cacd 378     minetest.register_node(":"..nn, def)
8a987b 379
O 380     if tubelib_exists then
381         tubelib.register_node(nn, {}, _TUBELIB_CALLBACKS)
382     end
78cacd 383
S 384     if data.color then
1d7cb7 385         local mk_front
Z 386         if string.find(def.tiles[6], "%^") then
387             mk_front = function (overlay) return def.tiles[6]:gsub("%^", "^"..overlay.."^") end
388         else
389             mk_front = function (overlay) return def.tiles[6].."^"..overlay end
390         end
78cacd 391         for i = 1, 15 do
S 392             local postfix = colorid_to_postfix(i)
393             local colordef = {}
394             for k, v in pairs(def) do
395                 colordef[k] = v
396             end
397             colordef.drop = nn
398             colordef.groups = self.groups_noinv
1d7cb7 399             colordef.tiles = { def.tiles[1], def.tiles[2], def.tiles[3], def.tiles[4], def.tiles[5], mk_front("technic_chest_overlay"..postfix..".png") }
78cacd 400             minetest.register_node(":"..nn..postfix, colordef)
8a987b 401             if tubelib_exists then
O 402                 tubelib.register_node(nn..postfix, {}, _TUBELIB_CALLBACKS)
403             end
78cacd 404         end
S 405     end
406 end
407