New glass, glass stair/slab, and glass door textures
[oweals/minetest_game.git] / mods / default / furnace.lua
1
2 --
3 -- Formspecs
4 --
5
6 function default.get_furnace_active_formspec(fuel_percent, item_percent)
7         return "size[8,8.5]"..
8                 default.gui_bg..
9                 default.gui_bg_img..
10                 default.gui_slots..
11                 "list[context;src;2.75,0.5;1,1;]"..
12                 "list[context;fuel;2.75,2.5;1,1;]"..
13                 "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
14                 (100-fuel_percent)..":default_furnace_fire_fg.png]"..
15                 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
16                 (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
17                 "list[context;dst;4.75,0.96;2,2;]"..
18                 "list[current_player;main;0,4.25;8,1;]"..
19                 "list[current_player;main;0,5.5;8,3;8]"..
20                 "listring[context;dst]"..
21                 "listring[current_player;main]"..
22                 "listring[context;src]"..
23                 "listring[current_player;main]"..
24                 "listring[context;fuel]"..
25                 "listring[current_player;main]"..
26                 default.get_hotbar_bg(0, 4.25)
27 end
28
29 function default.get_furnace_inactive_formspec()
30         return "size[8,8.5]"..
31                 default.gui_bg..
32                 default.gui_bg_img..
33                 default.gui_slots..
34                 "list[context;src;2.75,0.5;1,1;]"..
35                 "list[context;fuel;2.75,2.5;1,1;]"..
36                 "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
37                 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
38                 "list[context;dst;4.75,0.96;2,2;]"..
39                 "list[current_player;main;0,4.25;8,1;]"..
40                 "list[current_player;main;0,5.5;8,3;8]"..
41                 "listring[context;dst]"..
42                 "listring[current_player;main]"..
43                 "listring[context;src]"..
44                 "listring[current_player;main]"..
45                 "listring[context;fuel]"..
46                 "listring[current_player;main]"..
47                 default.get_hotbar_bg(0, 4.25)
48 end
49
50 --
51 -- Node callback functions that are the same for active and inactive furnace
52 --
53
54 local function can_dig(pos, player)
55         local meta = minetest.get_meta(pos);
56         local inv = meta:get_inventory()
57         return inv:is_empty("fuel") and inv:is_empty("dst") and inv:is_empty("src")
58 end
59
60 local function allow_metadata_inventory_put(pos, listname, index, stack, player)
61         if minetest.is_protected(pos, player:get_player_name()) then
62                 return 0
63         end
64         local meta = minetest.get_meta(pos)
65         local inv = meta:get_inventory()
66         if listname == "fuel" then
67                 if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
68                         if inv:is_empty("src") then
69                                 meta:set_string("infotext", "Furnace is empty")
70                         end
71                         return stack:get_count()
72                 else
73                         return 0
74                 end
75         elseif listname == "src" then
76                 return stack:get_count()
77         elseif listname == "dst" then
78                 return 0
79         end
80 end
81
82 local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
83         local meta = minetest.get_meta(pos)
84         local inv = meta:get_inventory()
85         local stack = inv:get_stack(from_list, from_index)
86         return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
87 end
88
89 local function allow_metadata_inventory_take(pos, listname, index, stack, player)
90         if minetest.is_protected(pos, player:get_player_name()) then
91                 return 0
92         end
93         return stack:get_count()
94 end
95
96 local function swap_node(pos, name)
97         local node = minetest.get_node(pos)
98         if node.name == name then
99                 return
100         end
101         node.name = name
102         minetest.swap_node(pos, node)
103 end
104
105 local function furnace_node_timer(pos, elapsed)
106         --
107         -- Inizialize metadata
108         --
109         local meta = minetest.get_meta(pos)
110         local fuel_time = meta:get_float("fuel_time") or 0
111         local src_time = meta:get_float("src_time") or 0
112         local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
113
114         local inv = meta:get_inventory()
115         local srclist, fuellist
116
117         local cookable, cooked
118         local fuel
119
120         local update = true
121         while elapsed > 0 and update do
122                 update = false
123
124                 srclist = inv:get_list("src")
125                 fuellist = inv:get_list("fuel")
126
127                 --
128                 -- Cooking
129                 --
130
131                 -- Check if we have cookable content
132                 local aftercooked
133                 cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
134                 cookable = cooked.time ~= 0
135
136                 local el = math.min(elapsed, fuel_totaltime - fuel_time)
137                 if cookable then -- fuel lasts long enough, adjust el to cooking duration
138                         el = math.min(el, cooked.time - src_time)
139                 end
140
141                 -- Check if we have enough fuel to burn
142                 if fuel_time < fuel_totaltime then
143                         -- The furnace is currently active and has enough fuel
144                         fuel_time = fuel_time + el
145                         -- If there is a cookable item then check if it is ready yet
146                         if cookable then
147                                 src_time = src_time + el
148                                 if src_time >= cooked.time then
149                                         -- Place result in dst list if possible
150                                         if inv:room_for_item("dst", cooked.item) then
151                                                 inv:add_item("dst", cooked.item)
152                                                 inv:set_stack("src", 1, aftercooked.items[1])
153                                                 src_time = src_time - cooked.time
154                                                 update = true
155                                         end
156                                 else
157                                         -- Item could not be cooked: probably missing fuel
158                                         update = true
159                                 end
160                         end
161                 else
162                         -- Furnace ran out of fuel
163                         if cookable then
164                                 -- We need to get new fuel
165                                 local afterfuel
166                                 fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
167
168                                 if fuel.time == 0 then
169                                         -- No valid fuel in fuel list
170                                         fuel_totaltime = 0
171                                         src_time = 0
172                                 else
173                                         -- Take fuel from fuel list
174                                         inv:set_stack("fuel", 1, afterfuel.items[1])
175                                         update = true
176                                         fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
177                                 end
178                         else
179                                 -- We don't need to get new fuel since there is no cookable item
180                                 fuel_totaltime = 0
181                                 src_time = 0
182                         end
183                         fuel_time = 0
184                 end
185
186                 elapsed = elapsed - el
187         end
188
189         if fuel and fuel_totaltime > fuel.time then
190                 fuel_totaltime = fuel.time
191         end
192         if srclist[1]:is_empty() then
193                 src_time = 0
194         end
195
196         --
197         -- Update formspec, infotext and node
198         --
199         local formspec
200         local item_state
201         local item_percent = 0
202         if cookable then
203                 item_percent = math.floor(src_time / cooked.time * 100)
204                 if item_percent > 100 then
205                         item_state = "100% (output full)"
206                 else
207                         item_state = item_percent .. "%"
208                 end
209         else
210                 if srclist[1]:is_empty() then
211                         item_state = "Empty"
212                 else
213                         item_state = "Not cookable"
214                 end
215         end
216
217         local fuel_state = "Empty"
218         local active = "inactive"
219         local result = false
220
221         if fuel_totaltime ~= 0 then
222                 active = "active"
223                 local fuel_percent = math.floor(fuel_time / fuel_totaltime * 100)
224                 fuel_state = fuel_percent .. "%"
225                 formspec = default.get_furnace_active_formspec(fuel_percent, item_percent)
226                 swap_node(pos, "default:furnace_active")
227                 -- make sure timer restarts automatically
228                 result = true
229         else
230                 if not fuellist[1]:is_empty() then
231                         fuel_state = "0%"
232                 end
233                 formspec = default.get_furnace_inactive_formspec()
234                 swap_node(pos, "default:furnace")
235                 -- stop timer on the inactive furnace
236                 minetest.get_node_timer(pos):stop()
237         end
238
239         local infotext = "Furnace " .. active .. "\n(Item: " .. item_state ..
240                 "; Fuel: " .. fuel_state .. ")"
241
242         --
243         -- Set meta values
244         --
245         meta:set_float("fuel_totaltime", fuel_totaltime)
246         meta:set_float("fuel_time", fuel_time)
247         meta:set_float("src_time", src_time)
248         meta:set_string("formspec", formspec)
249         meta:set_string("infotext", infotext)
250
251         return result
252 end
253
254 --
255 -- Node definitions
256 --
257
258 minetest.register_node("default:furnace", {
259         description = "Furnace",
260         tiles = {
261                 "default_furnace_top.png", "default_furnace_bottom.png",
262                 "default_furnace_side.png", "default_furnace_side.png",
263                 "default_furnace_side.png", "default_furnace_front.png"
264         },
265         paramtype2 = "facedir",
266         groups = {cracky=2},
267         legacy_facedir_simple = true,
268         is_ground_content = false,
269         sounds = default.node_sound_stone_defaults(),
270
271         can_dig = can_dig,
272
273         on_timer = furnace_node_timer,
274
275         on_construct = function(pos)
276                 local meta = minetest.get_meta(pos)
277                 meta:set_string("formspec", default.get_furnace_inactive_formspec())
278                 local inv = meta:get_inventory()
279                 inv:set_size('src', 1)
280                 inv:set_size('fuel', 1)
281                 inv:set_size('dst', 4)
282         end,
283
284         on_metadata_inventory_move = function(pos)
285                 minetest.get_node_timer(pos):start(1.0)
286         end,
287         on_metadata_inventory_put = function(pos)
288                 -- start timer function, it will sort out whether furnace can burn or not.
289                 minetest.get_node_timer(pos):start(1.0)
290         end,
291         on_blast = function(pos)
292                 local drops = {}
293                 default.get_inventory_drops(pos, "src", drops)
294                 default.get_inventory_drops(pos, "fuel", drops)
295                 default.get_inventory_drops(pos, "dst", drops)
296                 drops[#drops+1] = "default:furnace"
297                 minetest.remove_node(pos)
298                 return drops
299         end,
300
301         allow_metadata_inventory_put = allow_metadata_inventory_put,
302         allow_metadata_inventory_move = allow_metadata_inventory_move,
303         allow_metadata_inventory_take = allow_metadata_inventory_take,
304 })
305
306 minetest.register_node("default:furnace_active", {
307         description = "Furnace",
308         tiles = {
309                 "default_furnace_top.png", "default_furnace_bottom.png",
310                 "default_furnace_side.png", "default_furnace_side.png",
311                 "default_furnace_side.png",
312                 {
313                         image = "default_furnace_front_active.png",
314                         backface_culling = false,
315                         animation = {
316                                 type = "vertical_frames",
317                                 aspect_w = 16,
318                                 aspect_h = 16,
319                                 length = 1.5
320                         },
321                 }
322         },
323         paramtype2 = "facedir",
324         light_source = 8,
325         drop = "default:furnace",
326         groups = {cracky=2, not_in_creative_inventory=1},
327         legacy_facedir_simple = true,
328         is_ground_content = false,
329         sounds = default.node_sound_stone_defaults(),
330         on_timer = furnace_node_timer,
331
332         can_dig = can_dig,
333
334         allow_metadata_inventory_put = allow_metadata_inventory_put,
335         allow_metadata_inventory_move = allow_metadata_inventory_move,
336         allow_metadata_inventory_take = allow_metadata_inventory_take,
337 })