]> git.lizzy.rs Git - xdecor.git/blob - src/workbench.lua
remove unnecessary privilege checks
[xdecor.git] / src / workbench.lua
1 local function log(level, message, ...)
2         minetest.log(level, '[xdecor] ' .. message:format(...))
3 end
4
5 local workbench = {}
6 WB = {}
7 screwdriver = screwdriver or {}
8 local min, ceil = math.min, math.ceil
9 local registered_nodes = minetest.registered_nodes
10
11 -- Nodes allowed to be cut
12 -- Only the regular, solid blocks without metas or explosivity can be cut
13 local nodes = {}
14 for node, def in pairs(registered_nodes) do
15         if xdecor.stairs_valid_def(def) then
16                 nodes[#nodes + 1] = node
17         end
18 end
19
20 -- Optionally, you can register custom cuttable nodes in the workbench
21 WB.custom_nodes_register = {
22         -- "default:leaves",
23 }
24
25 setmetatable(nodes, {
26         __concat = function(t1, t2)
27                 for i = 1, #t2 do
28                         t1[#t1 + 1] = t2[i]
29                 end
30
31                 return t1
32         end
33 })
34
35 nodes = nodes .. WB.custom_nodes_register
36
37 -- Nodeboxes definitions
38 workbench.defs = {
39         -- Name YieldX  YZ  WH  L
40         {"nanoslab",    16, { 0, 0,  0, 8,  1, 8  }},
41         {"micropanel",  16, { 0, 0,  0, 16, 1, 8  }},
42         {"microslab",   8,  { 0, 0,  0, 16, 1, 16 }},
43         {"thinstair",   8,  { 0, 7,  0, 16, 1, 8  },
44                          { 0, 15, 8, 16, 1, 8  }},
45         {"cube",        4,  { 0, 0,  0, 8,  8, 8  }},
46         {"panel",       4,  { 0, 0,  0, 16, 8, 8  }},
47         {"slab",        2,  nil                   },
48         {"doublepanel", 2,  { 0, 0,  0, 16, 8, 8  },
49                          { 0, 8,  8, 16, 8, 8  }},
50         {"halfstair",   2,  { 0, 0,  0, 8,  8, 16 },
51                          { 0, 8,  8, 8,  8, 8  }},
52         {"stair_outer", 1,  nil                   },
53         {"stair",       1,  nil                   },
54         {"stair_inner", 1,  nil                   }
55 }
56
57 local repairable_tools = {"pick", "axe", "shovel", "sword", "hoe", "armor", "shield"}
58
59 -- Tools allowed to be repaired
60 function workbench:repairable(stack)
61         for _, t in ipairs(repairable_tools) do
62                 if stack:find(t) then
63                         return true
64                 end
65         end
66 end
67
68 function workbench:get_output(inv, input, name)
69         local output = {}
70         for i = 1, #self.defs do
71                 local nbox = self.defs[i]
72                 local count = min(nbox[2] * input:get_count(), input:get_stack_max())
73                 local item = name .. "_" .. nbox[1]
74
75                 item = nbox[3] and item or "stairs:" .. nbox[1] .. "_" .. name:match(":(.*)")
76                 output[i] = item .. " " .. count
77         end
78
79         inv:set_list("forms", output)
80 end
81
82 local main_fs = [[
83         label[0.9,1.23;Cut]
84         label[0.9,2.23;Repair]
85         box[-0.05,1;2.05,0.9;#555555]
86         box[-0.05,2;2.05,0.9;#555555]
87         button[0,0;2,1;craft;Crafting]
88         button[2,0;2,1;storage;Storage]
89         image[3,1;1,1;gui_furnace_arrow_bg.png^[transformR270]
90         image[0,1;1,1;worktable_saw.png]
91         image[0,2;1,1;worktable_anvil.png]
92         image[3,2;1,1;hammer_layout.png]
93         list[context;input;2,1;1,1;]
94         list[context;tool;2,2;1,1;]
95         list[context;hammer;3,2;1,1;]
96         list[context;forms;4,0;4,3;]
97         listring[current_player;main]
98         listring[context;tool]
99         listring[current_player;main]
100         listring[context;hammer]
101         listring[current_player;main]
102         listring[context;forms]
103         listring[current_player;main]
104         listring[context;input]
105 ]]
106
107 local crafting_fs = [[
108         image[5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]
109         button[0,0;1.5,1;back;< Back]
110         list[current_player;craft;2,0;3,3;]
111         list[current_player;craftpreview;6,1;1,1;]
112         listring[current_player;main]
113         listring[current_player;craft]
114 ]]
115
116 local storage_fs = [[
117         list[context;storage;0,1;8,2;]
118         button[0,0;1.5,1;back;< Back]
119         listring[context;storage]
120         listring[current_player;main]
121 ]]
122
123 local formspecs = {
124         -- Main formspec
125         main_fs,
126
127         -- Crafting formspec
128         crafting_fs,
129
130         -- Storage formspec
131         storage_fs,
132 }
133
134 function workbench:set_formspec(meta, id)
135         meta:set_string("formspec",
136                 "size[8,7;]list[current_player;main;0,3.25;8,4;]" ..
137                 formspecs[id] .. xbg .. default.get_hotbar_bg(0,3.25))
138 end
139
140 function workbench.construct(pos)
141         local meta = minetest.get_meta(pos)
142         local inv = meta:get_inventory()
143
144         inv:set_size("tool", 1)
145         inv:set_size("input", 1)
146         inv:set_size("hammer", 1)
147         inv:set_size("forms", 4*3)
148         inv:set_size("storage", 8*2)
149
150         meta:set_string("infotext", "Work Bench")
151         workbench:set_formspec(meta, 1)
152 end
153
154 function workbench.fields(pos, _, fields)
155         if fields.quit then return end
156
157         local meta = minetest.get_meta(pos)
158         local id = fields.back and 1 or fields.craft and 2 or fields.storage and 3
159         if not id then return end
160
161         workbench:set_formspec(meta, id)
162 end
163
164 function workbench.dig(pos)
165         local inv = minetest.get_meta(pos):get_inventory()
166         return inv:is_empty("input") and inv:is_empty("hammer") and
167                inv:is_empty("tool") and inv:is_empty("storage")
168 end
169
170 function workbench.timer(pos)
171         local timer = minetest.get_node_timer(pos)
172         local inv = minetest.get_meta(pos):get_inventory()
173         local tool = inv:get_stack("tool", 1)
174         local hammer = inv:get_stack("hammer", 1)
175
176         if tool:is_empty() or hammer:is_empty() or tool:get_wear() == 0 then
177                 timer:stop()
178                 return
179         end
180
181         -- Tool's wearing range: 0-65535; 0 = new condition
182         tool:add_wear(-500)
183         hammer:add_wear(700)
184
185         inv:set_stack("tool", 1, tool)
186         inv:set_stack("hammer", 1, hammer)
187
188         return true
189 end
190
191 function workbench.allow_put(pos, listname, index, stack, player)
192         local player_name = player:get_player_name()
193         if minetest.is_protected(pos, player_name) then
194                 minetest.record_protection_violation(pos, player_name)
195                 return 0
196         end
197
198         local stackname = stack:get_name()
199         if (listname == "tool" and stack:get_wear() > 0 and
200                 workbench:repairable(stackname)) or
201            (listname == "input" and registered_nodes[stackname .. "_cube"]) or
202            (listname == "hammer" and stackname == "xdecor:hammer") or
203             listname == "storage" then
204                 return stack:get_count()
205         end
206
207         return 0
208 end
209
210 function workbench.on_put(pos, listname, index, stack, player)
211         log('action',
212                 '%s put %s in workbench at %s',
213                 player:get_player_name(),
214                 stack:get_name(),
215                 minetest.pos_to_string(pos))
216
217         local inv = minetest.get_meta(pos):get_inventory()
218         if listname == "input" then
219                 local input = inv:get_stack("input", 1)
220                 workbench:get_output(inv, input, stack:get_name())
221         elseif listname == "tool" or listname == "hammer" then
222                 local timer = minetest.get_node_timer(pos)
223                 timer:start(3.0)
224         end
225 end
226
227 function workbench.allow_move(pos, from_list, from_index, to_list, to_index, count, player)
228         local player_name = player:get_player_name()
229         if minetest.is_protected(pos, player_name) then
230                 minetest.record_protection_violation(pos, player_name)
231                 return 0
232         end
233
234         return (to_list == "storage" and from_list ~= "forms") and count or 0
235 end
236
237 function workbench.on_move(pos, from_list, from_index, to_list, to_index, count, player)
238         local meta = minetest.get_meta(pos)
239         local inv = meta:get_inventory()
240         local from_stack = inv:get_stack(from_list, from_index)
241         local to_stack = inv:get_stack(to_list, to_index)
242
243         log('action',
244                 '%s moved %s in workbench at %s',
245                 player:get_player_name(),
246                 to_stack:get_name(),
247                 minetest.pos_to_string(pos))
248
249         workbench.on_take(pos, from_list, from_index, from_stack, player)
250         workbench.on_put(pos, to_list, to_index, to_stack, player)
251 end
252
253 function workbench.allow_take(pos, listname, index, stack, player)
254         local player_name = player:get_player_name()
255         if minetest.is_protected(pos, player_name) then
256                 minetest.record_protection_violation(pos, player_name)
257                 return 0
258         end
259
260         return stack:get_count()
261 end
262
263 function workbench.on_take(pos, listname, index, stack, player)
264         log('action',
265                 '%s took %s from workbench at %s',
266                 player:get_player_name(),
267                 stack:get_name(),
268                 minetest.pos_to_string(pos))
269
270         local inv = minetest.get_meta(pos):get_inventory()
271         local input = inv:get_stack("input", 1)
272         local inputname = input:get_name()
273         local stackname = stack:get_name()
274
275         if listname == "input" then
276                 if stackname == inputname and registered_nodes[inputname .. "_cube"] then
277                         workbench:get_output(inv, input, stackname)
278                 else
279                         inv:set_list("forms", {})
280                 end
281         elseif listname == "forms" then
282                 local fromstack = inv:get_stack(listname, index)
283                 if not fromstack:is_empty() and fromstack:get_name() ~= stackname then
284                         local player_inv = player:get_inventory()
285                         if player_inv:room_for_item("main", fromstack) then
286                                 player_inv:add_item("main", fromstack)
287                         end
288                 end
289
290                 input:take_item(ceil(stack:get_count() / workbench.defs[index][2]))
291                 inv:set_stack("input", 1, input)
292                 workbench:get_output(inv, input, inputname)
293         end
294 end
295
296 xdecor.register("workbench", {
297         description = "Work Bench",
298         groups = {cracky = 2, choppy = 2, oddly_breakable_by_hand = 1},
299         sounds = default.node_sound_wood_defaults(),
300         tiles = {
301                 "xdecor_workbench_top.png","xdecor_workbench_top.png",
302                 "xdecor_workbench_sides.png", "xdecor_workbench_sides.png",
303                 "xdecor_workbench_front.png", "xdecor_workbench_front.png"
304         },
305         on_rotate = screwdriver.rotate_simple,
306         can_dig = workbench.dig,
307         on_timer = workbench.timer,
308         on_construct = workbench.construct,
309         on_receive_fields = workbench.fields,
310         on_metadata_inventory_put = workbench.on_put,
311         on_metadata_inventory_take = workbench.on_take,
312         on_metadata_inventory_move = workbench.on_move,
313         allow_metadata_inventory_put = workbench.allow_put,
314         allow_metadata_inventory_take = workbench.allow_take,
315         allow_metadata_inventory_move = workbench.allow_move
316 })
317
318 for _, d in ipairs(workbench.defs) do
319 for i = 1, #nodes do
320         local node = nodes[i]
321         local mod_name, item_name = node:match("^(.-):(.*)")
322         local def = registered_nodes[node]
323
324         if item_name and d[3] then
325                 local groups = {}
326                 local tiles
327                 groups.not_in_creative_inventory = 1
328
329                 for k, v in pairs(def.groups) do
330                         if k ~= "wood" and k ~= "stone" and k ~= "level" then
331                                 groups[k] = v
332                         end
333                 end
334
335                 if def.tiles then
336                         if #def.tiles > 1 and (def.drawtype:sub(1,5) ~= "glass") then
337                                 tiles = def.tiles
338                         else
339                                 tiles = {def.tiles[1]}
340                         end
341                 else
342                         tiles = {def.tile_images[1]}
343                 end
344
345                 if not registered_nodes["stairs:slab_" .. item_name] then
346                         stairs.register_stair_and_slab(item_name, node,
347                                 groups, tiles, def.description .. " Stair",
348                                 def.description .. " Slab", def.sounds)
349                 end
350
351                 minetest.register_node(":" .. node .. "_" .. d[1], {
352                         description = def.description .. " " .. d[1]:gsub("^%l", string.upper),
353                         paramtype = "light",
354                         paramtype2 = "facedir",
355                         drawtype = "nodebox",
356                         sounds = def.sounds,
357                         tiles = tiles,
358                         groups = groups,
359                         -- `unpack` has been changed to `table.unpack` in newest Lua versions
360                         node_box = xdecor.pixelbox(16, {unpack(d, 3)}),
361                         sunlight_propagates = true,
362                         on_place = minetest.rotate_node
363                 })
364
365         elseif item_name and mod_name then
366                 minetest.register_alias_force(
367                         ("%s:%s_innerstair"):format(mod_name, item_name),
368                         ("stairs:stair_inner_%s"):format(item_name)
369                 )
370                 minetest.register_alias_force(
371                         ("%s:%s_outerstair"):format(mod_name, item_name),
372                         ("stairs:stair_outer_%s"):format(item_name)
373                 )
374         end
375 end
376 end
377
378 -- Craft items
379
380 minetest.register_tool("xdecor:hammer", {
381         description = "Hammer",
382         inventory_image = "xdecor_hammer.png",
383         wield_image = "xdecor_hammer.png",
384         on_use = function() do
385                 return end
386         end
387 })
388
389 -- Recipes
390
391 minetest.register_craft({
392         output = "xdecor:hammer",
393         recipe = {
394                 {"default:steel_ingot", "group:stick", "default:steel_ingot"},
395                 {"", "group:stick", ""}
396         }
397 })
398
399 minetest.register_craft({
400         output = "xdecor:workbench",
401         recipe = {
402                 {"group:wood", "group:wood"},
403                 {"group:wood", "group:wood"}
404         }
405 })