Update deprecated function calls
[minetest_easyvend.git] / easyvend.lua
blob9172a3e1b284200bfc155d6f074725e1be12736b
1 -- TODO: Improve mod compability
2 local slots_max = 31
4 local S = minetest.get_translator("easyvend")
5 local F = minetest.formspec_escape
7 local traversable_node_types = {
8 ["easyvend:vendor"] = true,
9 ["easyvend:depositor"] = true,
10 ["easyvend:vendor_on"] = true,
11 ["easyvend:depositor_on"] = true,
13 local registered_chests = {}
14 local cost_stack_max = minetest.registered_items[easyvend.currency].stack_max
15 local maxcost = cost_stack_max * slots_max
17 local joketimer_start = 3
19 local active_item_selection = {}
21 -- Allow for other mods to register custom chests
22 easyvend.register_chest = function(node_name, inv_list, meta_owner)
23 registered_chests[node_name] = { inv_list = inv_list, meta_owner = meta_owner }
24 traversable_node_types[node_name] = true
25 end
27 if minetest.get_modpath("select_item") then
28 -- When player selects item via "select item" dialog, switch the
29 -- machine's selected item and update the formspec.
30 select_item.register_on_select_item(function(playername, dialogname, itemstring)
31 if dialogname == "easyvend:trade_item" then
32 local player = minetest.get_player_by_name(playername)
33 if not player then
34 return
35 end
36 local pos = active_item_selection[playername]
37 if pos then
38 local node = minetest.get_node(pos)
39 if not easyvend.is_machine(node.name) then
40 return
41 end
42 local meta = minetest.get_meta(pos)
43 local owner = meta:get_string("owner")
44 if playername == owner then
45 local inv = meta:get_inventory()
46 local stack = ItemStack(itemstring)
47 if stack == nil then
48 inv:set_stack( "item", 1, nil )
49 else
50 inv:set_stack( "item", 1, stack)
51 meta:set_string("itemname", itemstring)
52 easyvend.set_formspec(pos, player)
53 end
54 end
55 end
56 active_item_selection[playername] = nil
57 end
58 end)
59 end
61 -- Partly a wrapper around contains_item, but does special treatment if the item
62 -- is a tool. Basically checks whether the items exist in the supplied inventory
63 -- list. If check_wear is true, only counts items without wear.
64 easyvend.check_and_get_items = function(inventory, listname, itemtable, check_wear)
65 local itemstring = itemtable.name
66 local minimum = itemtable.count
67 if check_wear == nil then check_wear = false end
68 local get_items = {}
69 -- Tool workaround
70 if minetest.registered_tools[itemstring] ~= nil then
71 local count = 0
72 for i=1,inventory:get_size(listname) do
73 local stack = inventory:get_stack(listname, i)
74 if stack:get_name() == itemstring then
75 if not check_wear or stack:get_wear() == 0 then
76 count = count + 1
77 table.insert(get_items, {id=i, item=stack})
78 if count >= minimum then
79 return true, get_items
80 end
81 end
82 end
83 end
84 return false
85 else
86 -- Normal Minetest check
87 return inventory:contains_item(listname, ItemStack(itemtable))
88 end
89 end
92 if minetest.get_modpath("default") ~= nil then
93 easyvend.register_chest("default:chest_locked", "main", "owner")
94 end
96 easyvend.free_slots= function(inv, listname)
97 local size = inv:get_size(listname)
98 local free = 0
99 for i=1,size do
100 local stack = inv:get_stack(listname, i)
101 if stack:is_empty() then
102 free = free + 1
105 return free
108 easyvend.buysell = function(nodename)
109 local buysell = nil
110 if ( nodename == "easyvend:depositor" or nodename == "easyvend:depositor_on" ) then
111 buysell = "buy"
112 elseif ( nodename == "easyvend:vendor" or nodename == "easyvend:vendor_on" ) then
113 buysell = "sell"
115 return buysell
118 easyvend.is_machine = function(nodename)
119 return ( nodename == "easyvend:depositor_on" or nodename == "easyvend:vendor_on" or nodename == "easyvend:depositor" or nodename == "easyvend:vendor" )
122 easyvend.is_active = function(nodename)
123 if ( nodename == "easyvend:depositor_on" or nodename == "easyvend:vendor_on" ) then
124 return true
125 elseif ( nodename == "easyvend:depositor" or nodename == "easyvend:vendor" ) then
126 return false
127 else
128 return nil
132 easyvend.set_formspec = function(pos, player)
133 local meta = minetest.get_meta(pos)
134 local node = minetest.get_node(pos)
136 local description = minetest.registered_nodes[node.name].description;
137 local number = meta:get_int("number")
138 local cost = meta:get_int("cost")
139 local itemname = meta:get_string("itemname")
140 local bg = ""
141 local configmode = meta:get_int("configmode") == 1
142 -- Support legacy background from default mod (MT<=0.4.17)
143 if minetest.get_modpath("default") and default.gui_bg then
144 bg = default.gui_bg .. default.gui_bg_img .. default.gui_slots
147 local numbertext, costtext, buysellbuttontext
148 local itemcounttooltip = S("Item count (append ā€œsā€ to multiply with maximum stack size)")
149 local buysell = easyvend.buysell(node.name)
150 if buysell == "sell" then
151 numbertext = S("Offered item")
152 costtext = S("Price")
153 buysellbuttontext = S("Buy")
154 elseif buysell == "buy" then
155 numbertext = S("Requested item")
156 costtext = S("Payment")
157 buysellbuttontext = S("Sell")
158 else
159 return
161 local status = meta:get_string("status")
162 if status == "" then status = S("Unknown.") end
163 local message = meta:get_string("message")
164 if message == "" then message = S("No message.") end
165 local status_image
166 if node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on" then
167 status_image = "easyvend_status_on.png"
168 else
169 status_image = "easyvend_status_off.png"
172 -- TODO: Expose number of items in stock
174 local formspec = "size[8,7.3;]"
175 .. bg
176 .."label[3,-0.2;" .. F(description) .. "]"
178 .."image[7.5,0.2;0.5,1;" .. status_image .. "]"
179 .."textarea[2.8,0.2;5.1,2;;"..F(S("Status: @1", status)) .. ";]"
180 .."textarea[2.8,1.3;5.6,2;;"..F(S("Message: @1", message)) .. ";]"
182 .."label[0,-0.15;"..F(numbertext).."]"
183 .."label[0,1.2;"..F(costtext).."]"
184 .."list[current_player;main;0,3.5;8,4;]"
186 if configmode then
187 local wear = "false"
188 if meta:get_int("wear") == 1 then wear = "true" end
189 formspec = formspec
190 .."item_image_button[0,1.65;1,1;"..easyvend.currency..";easyvend.currency_image;]"
191 .."list[current_name;item;0,0.35;1,1;]"
192 .."listring[current_player;main]"
193 .."listring[current_name;item]"
194 .."field[1.3,0.65;1.5,1;number;;" .. number .. "]"
195 .."tooltip[number;"..F(itemcounttooltip).."]"
196 .."field[1.3,1.95;1.5,1;cost;;" .. F(cost) .. "]"
197 .."tooltip[cost;"..F(itemcounttooltip).."]"
198 .."button[6,2.8;2,0.5;save;"..F(S("Confirm")).."]"
199 .."tooltip[save;"..F(S("Confirm configuration and activate machine (only for owner)")).."]"
200 if minetest.get_modpath("select_item") then
201 formspec = formspec .. "button[0,2.8;2,0.5;select_item;"..F(S("Select item")).."]"
203 local weartext, weartooltip
204 if buysell == "buy" then
205 weartext = S("Buy worn tools")
206 weartooltip = S("If disabled, only tools in perfect condition will be bought from sellers (only settable by owner)")
207 else
208 weartext = S("Sell worn tools")
209 weartooltip = S("If disabled, only tools in perfect condition will be sold (only settable by owner)")
211 if minetest.registered_tools[itemname] ~= nil then
212 formspec = formspec .."checkbox[2,2.4;wear;"..F(weartext)..";"..wear.."]"
213 .."tooltip[wear;"..F(weartooltip).."]"
215 else
216 formspec = formspec
217 .."item_image_button[0,1.65;1,1;"..easyvend.currency..";easyvend.currency_image;]"
218 .."item_image_button[0,0.35;1,1;"..itemname..";item_image;]"
219 .."label[1,1.85;Ɨ" .. cost .. "]"
220 .."label[1,0.55;Ɨ" .. number .. "]"
221 .."button[6,2.8;2,0.5;config;"..F(S("Configure")).."]"
222 if buysell == "sell" then
223 formspec = formspec .. "tooltip[config;"..F(S("Configure offered items and price (only for owner)")).."]"
224 else
225 formspec = formspec .. "tooltip[config;"..F(S("Configure requested items and payment (only for owner)")).."]"
227 formspec = formspec .."button[0,2.8;2,0.5;buysell;"..F(buysellbuttontext).."]"
228 if minetest.registered_tools[itemname] ~= nil then
229 local weartext
230 if meta:get_int("wear") == 0 then
231 if buysell == "buy" then
232 weartext = S("Only intact tools are bought.")
233 else
234 weartext = S("Only intact tools are sold.")
236 else
237 if buysell == "sell" then
238 weartext = S("Note: Might sell worn tools.")
239 else
240 weartext = S("Accepts worn tools.")
243 if weartext ~= nil then
244 formspec = formspec .."textarea[2.3,2.6;3,1;;"..F(weartext)..";]"
249 meta:set_string("formspec", formspec)
252 easyvend.machine_disable = function(pos, node, playername)
253 if node.name == "easyvend:vendor_on" then
254 easyvend.sound_disable(pos)
255 minetest.swap_node(pos, {name="easyvend:vendor", param2 = node.param2})
256 return true
257 elseif node.name == "easyvend:depositor_on" then
258 easyvend.sound_disable(pos)
259 minetest.swap_node(pos, {name="easyvend:depositor", param2 = node.param2})
260 return true
261 else
262 if playername ~= nil then
263 easyvend.sound_error(playername)
265 return false
269 easyvend.machine_enable = function(pos, node)
270 if node.name == "easyvend:vendor" then
271 easyvend.sound_setup(pos)
272 minetest.swap_node(pos, {name="easyvend:vendor_on", param2 = node.param2})
273 return true
274 elseif node.name == "easyvend:depositor" then
275 easyvend.sound_setup(pos)
276 minetest.swap_node(pos, {name="easyvend:depositor_on", param2 = node.param2})
277 return true
278 else
279 return false
283 easyvend.machine_check = function(pos, node)
284 local active = true
285 local status = S("Ready.")
287 local meta = minetest.get_meta(pos)
289 local machine_owner = meta:get_string("owner")
290 local number = meta:get_int("number")
291 local cost = meta:get_int("cost")
292 local itemname = meta:get_string("itemname")
293 local check_wear = meta:get_int("wear") == 0
294 local inv = meta:get_inventory()
295 local itemstack = inv:get_stack("item",1)
296 local buysell = easyvend.buysell(node.name)
298 local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
299 if buysell == "sell" then
300 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
301 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, false)
302 else
303 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, true)
304 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
306 if chest_pos_remove and chest_pos_add then
307 local rchest, rchestdef, rchest_meta, rchest_inv
308 rchest = minetest.get_node(chest_pos_remove)
309 rchestdef = registered_chests[rchest.name]
310 rchest_meta = minetest.get_meta(chest_pos_remove)
311 rchest_inv = rchest_meta:get_inventory()
313 local checkstack, checkitem
314 if buysell == "buy" then
315 checkitem = easyvend.currency
316 else
317 checkitem = itemname
319 local stock = 0
320 -- Count stock
321 -- FIXME: Ignore tools with bad wear level
322 for i=1,rchest_inv:get_size(rchestdef.inv_list) do
323 checkstack = rchest_inv:get_stack(rchestdef.inv_list, i)
324 if checkstack:get_name() == checkitem then
325 stock = stock + checkstack:get_count()
328 meta:set_int("stock", stock)
330 if not itemstack:is_empty() then
331 local number_stack_max = itemstack:get_stack_max()
332 local maxnumber = number_stack_max * slots_max
333 if not(number >= 1 and number <= maxnumber and cost >= 1 and cost <= maxcost) then
334 active = false
335 if buysell == "sell" then
336 status = S("Invalid item count or price.")
337 else
338 status = S("Invalid item count or payment.")
341 else
342 active = false
343 status = S("Awaiting configuration by owner.")
345 else
346 active = false
347 meta:set_int("stock", 0)
348 if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
349 status = S("No storage; machine needs to be connected with a locked chest.")
350 elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
351 status = S("Storage canā€™t be accessed because it is owned by a different person!")
352 elseif chest_error_remove == "no_stock" then
353 if buysell == "sell" then
354 status = S("The vending machine has insufficient materials!")
355 else
356 status = S("The depositing machine is out of money!")
358 elseif chest_error_add == "no_space" then
359 status = S("No room in the machineā€™s storage!")
360 else
361 status = S("Unknown error!")
364 if meta:get_int("configmode") == 1 then
365 active = false
366 status = S("Awaiting configuration by owner.")
369 if itemname == easyvend.currency and number == cost and active then
370 local jt = meta:get_int("joketimer")
371 if jt > 0 then
372 jt = jt - 1
374 if jt == 0 then
375 if buysell == "sell" then
376 meta:set_string("message", S("Item bought."))
377 else
378 meta:set_string("message", S("Item sold."))
380 jt = -1
382 meta:set_int("joketimer", jt)
384 meta:set_string("status", status)
386 meta:set_string("infotext", easyvend.make_infotext(node.name, machine_owner, cost, number, itemname))
387 itemname=itemstack:get_name()
388 meta:set_string("itemname", itemname)
390 if minetest.get_modpath("awards") and buysell == "sell" then
391 if minetest.get_player_by_name(machine_owner) then
392 local earnings = meta:get_int("earnings")
393 if earnings >= 1 then
394 awards.unlock(machine_owner, "easyvend_seller")
396 if earnings >= easyvend.powerseller then
397 awards.unlock(machine_owner, "easyvend_powerseller")
402 local change
403 if node.name == "easyvend:vendor" or node.name == "easyvend:depositor" then
404 if active then change = easyvend.machine_enable(pos, node) end
405 elseif node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on" then
406 if not active then change = easyvend.machine_disable(pos, node) end
408 easyvend.set_formspec(pos)
409 return change
412 easyvend.on_receive_fields_config = function(pos, formname, fields, sender)
413 local node = minetest.get_node(pos)
414 local meta = minetest.get_meta(pos)
415 local inv_self = meta:get_inventory()
416 local itemstack = inv_self:get_stack("item",1)
417 local buysell = easyvend.buysell(node.name)
419 if fields.config then
420 meta:set_int("configmode", 1)
421 local was_active = easyvend.is_active(node.name)
422 if was_active then
423 meta:set_string("message", S("Configuration mode activated; machine disabled."))
424 else
425 meta:set_string("message", S("Configuration mode activated."))
427 easyvend.machine_check(pos, node)
428 return
431 if not fields.save then
432 return
435 local number = fields.number
436 local cost = fields.cost
438 --[[ Convenience function:
439 When appending ā€œsā€ or ā€œSā€ to the number, it is multiplied
440 by the maximum stack size. ]]
441 local number_stack_max = itemstack:get_stack_max()
442 local ss = string.sub(number, #number, #number)
443 if ss == "s" or ss == "S" then
444 local n = tonumber(string.sub(number, 1, #number-1))
445 if string.len(number) == 1 then n = 1 end
446 if n ~= nil then
447 number = n * number_stack_max
450 ss = string.sub(cost, #cost, #cost)
451 if ss == "s" or ss == "S" then
452 local n = tonumber(string.sub(cost, 1, #cost-1))
453 if string.len(cost) == 1 then n = 1 end
454 if n ~= nil then
455 cost = n * cost_stack_max
458 number = tonumber(number)
459 cost = tonumber(cost)
461 local itemname=""
463 local oldnumber = meta:get_int("number")
464 local oldcost = meta:get_int("cost")
465 local maxnumber = number_stack_max * slots_max
467 if ( itemstack == nil or itemstack:is_empty() ) then
468 meta:set_string("status", S("Awaiting configuration by owner."))
469 meta:set_string("message", S("No item specified."))
470 easyvend.sound_error(sender:get_player_name())
471 easyvend.set_formspec(pos, sender)
472 return
473 elseif ( not itemstack:is_known() ) then
474 meta:set_string("status", S("Awaiting configuration by owner."))
475 meta:set_string("message", S("Unknown item specified."))
476 easyvend.sound_error(sender:get_player_name())
477 easyvend.set_formspec(pos, sender)
478 return
479 elseif ( number == nil or number < 1 or number > maxnumber ) then
480 if maxnumber > 1 then
481 meta:set_string("message", S("Invalid item count; must be between 1 and @1!", maxnumber))
482 else
483 meta:set_string("message", S("Invalid item count; must be exactly 1!"))
485 meta:set_int("number", oldnumber)
486 easyvend.sound_error(sender:get_player_name())
487 easyvend.set_formspec(pos, sender)
488 return
489 elseif ( cost == nil or cost < 1 or cost > maxcost ) then
490 if maxcost > 1 then
491 meta:set_string("message", S("Invalid cost; must be between 1 and @1!", maxcost))
492 else
493 meta:set_string("message", S("Invalid cost; must be exactly 1!"))
495 meta:set_int("cost", oldcost)
496 easyvend.sound_error(sender:get_player_name())
497 easyvend.set_formspec(pos, sender)
498 return
500 meta:set_int("number", number)
501 meta:set_int("cost", cost)
502 itemname=itemstack:get_name()
503 meta:set_string("itemname", itemname)
504 meta:set_int("configmode", 0)
506 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
507 meta:set_string("message", S("Configuration successful. I am feeling funny."))
508 meta:set_int("joketimer", joketimer_start)
509 meta:set_int("joke_id", easyvend.assign_joke(buysell))
510 else
511 meta:set_string("message", S("Configuration successful."))
514 local change = easyvend.machine_check(pos, node)
516 if not change then
517 if (node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on") then
518 easyvend.sound_setup(pos)
519 else
520 easyvend.sound_disable(pos)
525 easyvend.make_infotext = function(nodename, owner, cost, number, itemstring)
526 local d = ""
527 if itemstring == nil or itemstring == "" or number == 0 or cost == 0 then
528 if easyvend.buysell(nodename) == "sell" then
529 d = S("Inactive vending machine (owned by @1)", owner)
530 else
531 d = S("Inactive depositing machine (owned by @1)", owner)
533 return d
535 local iname
536 if minetest.registered_items[itemstring] then
537 iname = minetest.registered_items[itemstring].description
538 else
539 iname = S("Unknown Item (@1)", itemstring)
541 if iname == nil then iname = itemstring end
542 local printitem, printcost
543 if number == 1 then
544 printitem = iname
545 else
546 printitem = S("@1Ɨ@2", number, iname)
548 if cost == 1 then
549 printcost = easyvend.currency_desc
550 else
551 printcost = S("@1Ɨ@2", cost, easyvend.currency_desc)
553 if nodename == "easyvend:vendor_on" then
554 d = S("Vending machine (owned by @1)", owner).."\n"..S("Selling: @1", printitem).."\n"..S("Price: @1", printcost)
555 elseif nodename == "easyvend:vendor" then
556 d = S("Inactive vending machine (owned by @1)", owner).."\n"..S("Selling: @1", printitem).."\n"..S("Price: @1", printcost)
557 elseif nodename == "easyvend:depositor_on" then
558 d = S("Depositing machine (owned by @1)", owner).."\n"..S("Buying: @1", printitem).."\n"..S("Payment: @1", printcost)
559 elseif nodename == "easyvend:depositor" then
560 d = S("Inactive depositing machine (owned by @1)", owner).."\n"..S("Buying: @1", printitem).."\n"..S("Payment: @1", printcost)
562 return d
565 if minetest.get_modpath("awards") then
566 awards.register_achievement("easyvend_seller",{
567 title = S("First Sale"),
568 description = S("Sell something with a vending machine."),
569 icon = "easyvend_vendor_front_on.png^awards_level1.png",
571 local desc_powerseller
572 if easyvend.currency == "default:gold_ingot" then
573 desc_powerseller = S("Earn @1 gold ingots by selling goods with a single vending machine.", easyvend.powerseller)
574 else
575 desc_powerseller = S("Earn @1 currency items by selling goods with a single vending machine.", easyvend.powerseller)
577 awards.register_achievement("easyvend_powerseller",{
578 title = S("Power Seller"),
579 description = desc_powerseller,
580 icon = "easyvend_vendor_front_on.png^awards_level2.png",
584 easyvend.check_earnings = function(buyername, nodemeta)
585 local owner = nodemeta:get_string("owner")
586 if buyername ~= owner then
587 local cost = nodemeta:get_int("cost")
588 local itemname = nodemeta:get_string("itemname")
589 -- First sell
590 if minetest.get_modpath("awards") and minetest.get_player_by_name(owner) ~= nil then
591 awards.unlock(owner, "easyvend_seller")
593 if itemname ~= easyvend.currency then
594 local newearnings = nodemeta:get_int("earnings") + cost
595 if newearnings >= easyvend.powerseller and minetest.get_modpath("awards") then
596 if minetest.get_player_by_name(owner) ~= nil then
597 awards.unlock(owner, "easyvend_powerseller")
600 nodemeta:set_int("earnings", newearnings)
605 easyvend.on_receive_fields_buysell = function(pos, formname, fields, sender)
606 local sendername = sender:get_player_name()
607 local meta = minetest.get_meta(pos)
609 if not fields.buysell then
610 return
613 local node = minetest.get_node(pos)
614 local number = meta:get_int("number")
615 local cost = meta:get_int("cost")
616 local itemname=meta:get_string("itemname")
617 local item=meta:get_inventory():get_stack("item", 1)
618 local check_wear = meta:get_int("wear") == 0 and minetest.registered_tools[itemname] ~= nil
619 local machine_owner = meta:get_string("owner")
621 local buysell = easyvend.buysell(node.name)
623 local number_stack_max = item:get_stack_max()
624 local maxnumber = number_stack_max * slots_max
626 if ( number == nil or number < 1 or number > maxnumber ) or
627 ( cost == nil or cost < 1 or cost > maxcost ) or
628 ( itemname == nil or itemname=="") then
629 meta:set_string("status", S("Invalid item count or price!"))
630 easyvend.machine_disable(pos, node, sendername)
631 return
634 local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
635 if buysell == "sell" then
636 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
637 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, false)
638 else
639 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, true)
640 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
643 if chest_pos_remove ~= nil and chest_pos_add ~= nil and sender and sender:is_player() then
644 local rchest = minetest.get_node(chest_pos_remove)
645 local rchestdef = registered_chests[rchest.name]
646 local rchest_meta = minetest.get_meta(chest_pos_remove)
647 local rchest_inv = rchest_meta:get_inventory()
648 local achest = minetest.get_node(chest_pos_add)
649 local achestdef = registered_chests[achest.name]
650 local achest_meta = minetest.get_meta(chest_pos_add)
651 local achest_inv = achest_meta:get_inventory()
653 local player_inv = sender:get_inventory()
655 local stack = {name=itemname, count=number, wear=0, metadata=""}
656 local price = {name=easyvend.currency, count=cost, wear=0, metadata=""}
657 local chest_has, player_has, chest_free, player_free, chest_out, player_out
658 local msg = ""
659 if buysell == "sell" then
660 chest_has, chest_out = easyvend.check_and_get_items(rchest_inv, rchestdef.inv_list, stack, check_wear)
661 player_has, player_out = easyvend.check_and_get_items(player_inv, "main", price, check_wear)
662 chest_free = achest_inv:room_for_item(achestdef.inv_list, price)
663 player_free = player_inv:room_for_item("main", stack)
664 if chest_has and player_has and chest_free and player_free then
665 if cost <= cost_stack_max and number <= number_stack_max then
666 easyvend.machine_enable(pos, node)
667 player_inv:remove_item("main", price)
668 if check_wear then
669 rchest_inv:set_stack(rchestdef.inv_list, chest_out[1].id, "")
670 player_inv:add_item("main", chest_out[1].item)
671 else
672 stack = rchest_inv:remove_item(rchestdef.inv_list, stack)
673 player_inv:add_item("main", stack)
675 achest_inv:add_item(achestdef.inv_list, price)
676 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
677 meta:set_string("message", easyvend.get_joke(buysell, meta:get_int("joke_id")))
678 meta:set_int("joketimer", joketimer_start)
679 else
680 meta:set_string("message", S("Item bought."))
682 easyvend.check_earnings(sendername, meta)
683 easyvend.sound_vend(pos)
684 easyvend.machine_check(pos, node)
685 else
686 -- Large item counts (multiple stacks)
687 local coststacks = math.modf(cost / cost_stack_max)
688 local costremainder = math.fmod(cost, cost_stack_max)
689 local numberstacks = math.modf(number / number_stack_max)
690 local numberremainder = math.fmod(number, number_stack_max)
691 local numberfree = numberstacks
692 local costfree = coststacks
693 if numberremainder > 0 then numberfree = numberfree + 1 end
694 if costremainder > 0 then costfree = costfree + 1 end
695 if not player_free and easyvend.free_slots(player_inv, "main") < numberfree then
696 if numberfree > 1 then
697 msg = S("No room in your inventory (@1 empty slots required)!", numberfree)
698 else
699 msg = S("No room in your inventory!")
701 meta:set_string("message", msg)
702 elseif not chest_free and easyvend.free_slots(achest_inv, achestdef.inv_list) < costfree then
703 meta:set_string("status", S("No room in the machineā€™s storage!"))
704 easyvend.machine_disable(pos, node, sendername)
705 else
706 -- Remember items for transfer
707 local cheststacks = {}
708 easyvend.machine_enable(pos, node)
709 for i=1, coststacks do
710 price.count = cost_stack_max
711 player_inv:remove_item("main", price)
713 if costremainder > 0 then
714 price.count = costremainder
715 player_inv:remove_item("main", price)
717 if check_wear then
718 for o=1,#chest_out do
719 rchest_inv:set_stack(rchestdef.inv_list, chest_out[o].id, "")
721 else
722 for i=1, numberstacks do
723 stack.count = number_stack_max
724 table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
727 if numberremainder > 0 then
728 stack.count = numberremainder
729 table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
731 for i=1, coststacks do
732 price.count = cost_stack_max
733 achest_inv:add_item(achestdef.inv_list, price)
735 if costremainder > 0 then
736 price.count = costremainder
737 achest_inv:add_item(achestdef.inv_list, price)
739 if check_wear then
740 for o=1,#chest_out do
741 player_inv:add_item("main", chest_out[o].item)
743 else
744 for i=1,#cheststacks do
745 player_inv:add_item("main", cheststacks[i])
748 meta:set_string("message", S("Item bought."))
749 easyvend.check_earnings(sendername, meta)
750 easyvend.sound_vend(pos)
751 easyvend.machine_check(pos, node)
754 elseif chest_has and player_has then
755 if not player_free then
756 msg = S("No room in your inventory!")
757 meta:set_string("message", msg)
758 easyvend.sound_error(sendername)
759 elseif not chest_free then
760 msg = S("No room in the machineā€™s storage!")
761 meta:set_string("status", msg)
762 easyvend.machine_disable(pos, node, sendername)
764 else
765 if not chest_has then
766 msg = S("The vending machine has insufficient materials!")
767 meta:set_string("status", msg)
768 easyvend.machine_disable(pos, node, sendername)
769 elseif not player_has then
770 msg = S("You canā€™t afford this item!")
771 meta:set_string("message", msg)
772 easyvend.sound_error(sendername)
775 else
776 chest_has, chest_out = easyvend.check_and_get_items(rchest_inv, rchestdef.inv_list, price, check_wear)
777 player_has, player_out = easyvend.check_and_get_items(player_inv, "main", stack, check_wear)
778 chest_free = achest_inv:room_for_item(achestdef.inv_list, stack)
779 player_free = player_inv:room_for_item("main", price)
780 if chest_has and player_has and chest_free and player_free then
781 if cost <= cost_stack_max and number <= number_stack_max then
782 easyvend.machine_enable(pos, node)
783 if check_wear then
784 player_inv:set_stack("main", player_out[1].id, "")
785 achest_inv:add_item(achestdef.inv_list, player_out[1].item)
786 else
787 stack = player_inv:remove_item("main", stack)
788 achest_inv:add_item(achestdef.inv_list, stack)
790 rchest_inv:remove_item(rchestdef.inv_list, price)
791 player_inv:add_item("main", price)
792 meta:set_string("status", S("Ready."))
793 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
794 meta:set_string("message", easyvend.get_joke(buysell, meta:get_int("joke_id")))
795 meta:set_int("joketimer", joketimer_start)
796 else
797 meta:set_string("message", S("Item sold."))
799 easyvend.sound_deposit(pos)
800 easyvend.machine_check(pos, node)
801 else
802 -- Large item counts (multiple stacks)
803 local coststacks = math.modf(cost / cost_stack_max)
804 local costremainder = math.fmod(cost, cost_stack_max)
805 local numberstacks = math.modf(number / number_stack_max)
806 local numberremainder = math.fmod(number, number_stack_max)
807 local numberfree = numberstacks
808 local costfree = coststacks
809 if numberremainder > 0 then numberfree = numberfree + 1 end
810 if costremainder > 0 then costfree = costfree + 1 end
811 if not player_free and easyvend.free_slots(player_inv, "main") < costfree then
812 if costfree > 1 then
813 msg = S("No room in your inventory (@1 empty slots required)!", costfree)
814 else
815 msg = S("No room in your inventory!")
817 meta:set_string("message", msg)
818 easyvend.sound_error(sendername)
819 elseif not chest_free and easyvend.free_slots(achest_inv, achestdef.inv_list) < numberfree then
820 meta:set_string("status", S("No room in the machineā€™s storage!"))
821 easyvend.machine_disable(pos, node, sendername)
822 else
823 easyvend.machine_enable(pos, node)
824 -- Remember removed items for transfer
825 local playerstacks = {}
826 for i=1, coststacks do
827 price.count = cost_stack_max
828 rchest_inv:remove_item(rchestdef.inv_list, price)
830 if costremainder > 0 then
831 price.count = costremainder
832 rchest_inv:remove_item(rchestdef.inv_list, price)
834 if check_wear then
835 for o=1,#player_out do
836 player_inv:set_stack("main", player_out[o].id, "")
838 else
839 for i=1, numberstacks do
840 stack.count = number_stack_max
841 table.insert(playerstacks, player_inv:remove_item("main", stack))
844 if numberremainder > 0 then
845 stack.count = numberremainder
846 table.insert(playerstacks, player_inv:remove_item("main", stack))
848 for i=1, coststacks do
849 price.count = cost_stack_max
850 player_inv:add_item("main", price)
852 if costremainder > 0 then
853 price.count = costremainder
854 player_inv:add_item("main", price)
856 if check_wear then
857 for o=1,#player_out do
858 achest_inv:add_item(achestdef.inv_list, player_out[o].item)
860 else
861 for i=1,#playerstacks do
862 achest_inv:add_item(achestdef.inv_list, playerstacks[i])
865 meta:set_string("message", S("Item sold."))
866 easyvend.sound_deposit(pos)
867 easyvend.machine_check(pos, node)
870 elseif chest_has and player_has then
871 if not player_free then
872 msg = S("No room in your inventory!")
873 meta:set_string("message", msg)
874 easyvend.sound_error(sendername)
875 elseif not chest_free then
876 msg = S("No room in the machineā€™s storage!")
877 meta:set_string("status", msg)
878 easyvend.machine_disable(pos, node, sendername)
880 else
881 if not player_has then
882 msg = S("You have insufficient materials!")
883 meta:set_string("message", msg)
884 easyvend.sound_error(sendername)
885 elseif not chest_has then
886 msg = S("The depositing machine is out of money!")
887 meta:set_string("status", msg)
888 easyvend.machine_disable(pos, node, sendername)
892 else
893 local status
894 meta:set_int("stock", 0)
895 if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
896 status = S("No storage; machine needs to be connected with a locked chest.")
897 elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
898 status = S("Storage canā€™t be accessed because it is owned by a different person!")
899 elseif chest_error_remove == "no_stock" then
900 if buysell == "sell" then
901 status = S("The vending machine has insufficient materials!")
902 else
903 status = S("The depositing machine is out of money!")
905 elseif chest_error_add == "no_space" then
906 status = S("No room in the machineā€™s storage!")
907 else
908 status = S("Unknown error!")
910 meta:set_string("status", status)
911 easyvend.sound_error(sendername)
914 easyvend.set_formspec(pos, sender)
918 easyvend.after_place_node = function(pos, placer)
919 local node = minetest.get_node(pos)
920 local meta = minetest.get_meta(pos)
921 local inv = meta:get_inventory()
922 local player_name = placer:get_player_name()
923 inv:set_size("item", 1)
924 inv:set_size("gold", 1)
926 inv:set_stack( "gold", 1, easyvend.currency )
928 local d = ""
929 if node.name == "easyvend:vendor" then
930 d = S("Inactive vending machine (owned by @1)", player_name)
931 meta:set_int("wear", 1)
932 -- Total number of currency items earned for the machine's life time (excluding currency-currency trading)
933 meta:set_int("earnings", 0)
934 elseif node.name == "easyvend:depositor" then
935 d = S("Inactive depositing machine (owned by @1)", player_name)
936 meta:set_int("wear", 0)
938 meta:set_string("infotext", d)
939 meta:set_string("status", S("Awaiting configuration by owner."))
940 meta:set_string("message", S("Please select an item and amount, then confirm."))
941 meta:set_int("number", 1)
942 meta:set_int("cost", 1)
943 meta:set_int("stock", -1)
944 meta:set_int("configmode", 1)
945 meta:set_int("joketimer", -1)
946 meta:set_int("joke_id", 1)
947 meta:set_string("itemname", "")
949 meta:set_string("owner", player_name or "")
951 easyvend.set_formspec(pos, placer)
954 easyvend.can_dig = function(pos, player)
955 local meta = minetest.get_meta(pos)
956 local name = player:get_player_name()
957 local owner = meta:get_string("owner")
958 -- Owner can always dig shop
959 if owner == name then
960 return true
962 local chest_pos = easyvend.find_connected_chest(owner, pos)
963 local chest, meta_chest
964 if chest_pos then
965 chest = minetest.get_node(chest_pos)
966 meta_chest = minetest.get_meta(chest_pos)
967 else
968 return true --if no chest, enyone can dig this shop
970 if registered_chests[chest.name] then
971 if player and player:is_player() then
972 local owner_chest = meta_chest:get_string(registered_chests[chest.name].meta_owner)
973 if name == owner_chest then
974 return true --chest owner can also dig shop
977 return false
978 else
979 return true --if no chest, enyone can dig this shop
983 easyvend.on_receive_fields = function(pos, formname, fields, sender)
984 local meta = minetest.get_meta(pos)
985 local node = minetest.get_node(pos)
986 local owner = meta:get_string("owner")
987 local sendername = sender:get_player_name()
989 if fields.doc then
990 if minetest.get_modpath("doc") and minetest.get_modpath("doc_items") then
991 if easyvend.buysell(node.name) == "buy" then
992 doc.show_entry(sendername, "nodes", "easyvend:depositor", true)
993 else
994 doc.show_entry(sendername, "nodes", "easyvend:vendor", true)
997 elseif fields.config or fields.save or fields.usermode then
998 if sendername == owner then
999 easyvend.on_receive_fields_config(pos, formname, fields, sender)
1000 else
1001 meta:set_string("message", S("Only the owner may change the configuration."))
1002 easyvend.sound_error(sendername)
1003 easyvend.set_formspec(pos, sender)
1004 return
1006 elseif fields.select_item then
1007 if minetest.get_modpath("select_item") then
1008 if sendername == owner then
1009 active_item_selection[sendername] = pos
1010 select_item.show_dialog(sendername, "easyvend:trade_item", select_item.filters.creative)
1011 else
1012 meta:set_string("message", S("Only the owner may change the configuration."))
1013 easyvend.sound_error(sendername)
1014 easyvend.set_formspec(pos, sender)
1015 return
1018 elseif fields.wear ~= nil then
1019 if sender:get_player_name() == owner then
1020 if fields.wear == "true" then
1021 if easyvend.buysell(node.name) == "buy" then
1022 meta:set_string("message", S("Used tools are now accepted."))
1023 else
1024 meta:set_string("message", S("Used tools are now for sale."))
1026 meta:set_int("wear", 1)
1027 elseif fields.wear == "false" then
1028 if easyvend.buysell(node.name) == "buy" then
1029 meta:set_string("message", S("Used tools are now rejected."))
1030 else
1031 meta:set_string("message", S("Used tools wonā€™t be sold anymore."))
1033 meta:set_int("wear", 0)
1035 easyvend.set_formspec(pos, sender)
1036 return
1037 else
1038 meta:set_string("message", S("Only the owner may change the configuration."))
1039 easyvend.sound_error(sendername)
1040 easyvend.set_formspec(pos, sender)
1041 return
1043 elseif fields.buysell then
1044 easyvend.on_receive_fields_buysell(pos, formname, fields, sender)
1048 -- Jokes: Appear when machine exchanges currency for currency at equal rate
1050 -- Vendor
1051 local jokes_vendor = {
1052 S("Thank you. You have made a vending machine very happy."),
1053 S("Humans have a strange sense of humor."),
1054 S("Letā€™s get this over with ā€¦"),
1055 S("Item ā€œboughtā€."),
1056 S("Tit for tat."),
1057 S("Do you realize what youā€™ve just bought?"),
1059 -- Depositor
1060 local jokes_depositor = {
1061 S("Thank you, the money started to smell inside."),
1062 S("Money doesnā€™t grow on trees, you know?"),
1063 S("Sanity sold."),
1064 S("Well, that was an awkward exchange."),
1065 S("Are you having fun?"),
1066 S("Is this really trading?"),
1069 easyvend.assign_joke = function(buysell)
1070 local jokes
1071 if buysell == "sell" then
1072 jokes = jokes_vendor
1073 elseif buysell == "buy" then
1074 jokes = jokes_depositor
1076 local r = math.random(1,#jokes)
1077 return r
1080 easyvend.get_joke = function(buysell, id)
1081 local joke
1082 if buysell == nil or id == nil then
1083 -- Fallback message (should never happen)
1084 return S("Items exchanged.")
1086 if buysell == "sell" then
1087 joke = jokes_vendor[id]
1088 if joke == nil then joke = jokes_vendor[1] end
1089 elseif buysell == "buy" then
1090 joke = jokes_depositor[id]
1091 if joke == nil then joke = jokes_depositor[1] end
1093 return joke
1096 easyvend.sound_error = function(playername)
1097 minetest.sound_play("easyvend_error", {to_player = playername, gain = 0.25})
1100 easyvend.sound_setup = function(pos)
1101 minetest.sound_play("easyvend_activate", {pos = pos, gain = 0.5, max_hear_distance = 12,})
1104 easyvend.sound_disable = function(pos)
1105 minetest.sound_play("easyvend_disable", {pos = pos, gain = 0.9, max_hear_distance = 12,})
1108 easyvend.sound_vend = function(pos)
1109 minetest.sound_play("easyvend_vend", {pos = pos, gain = 0.4, max_hear_distance = 5,})
1112 easyvend.sound_deposit = function(pos)
1113 minetest.sound_play("easyvend_deposit", {pos = pos, gain = 0.4, max_hear_distance = 5,})
1116 --[[ Tower building ]]
1118 easyvend.is_traversable = function(pos)
1119 local node = minetest.get_node_or_nil(pos)
1120 if (node == nil) then
1121 return false
1123 return traversable_node_types[node.name] == true
1126 easyvend.neighboring_nodes = function(pos)
1127 local check = {
1128 {x=pos.x, y=pos.y-1, z=pos.z},
1129 {x=pos.x, y=pos.y+1, z=pos.z},
1131 local trav = {}
1132 for i=1,#check do
1133 if easyvend.is_traversable(check[i]) then
1134 table.insert(trav, check[i])
1137 return trav
1140 easyvend.find_connected_chest = function(owner, pos, nodename, check_wear, amount, removing)
1141 local nodes = easyvend.neighboring_nodes(pos)
1143 if (#nodes < 1 or #nodes > 2) then
1144 return nil, "no_chest"
1147 -- Find the stack direction
1148 local first = nil
1149 local second = nil
1150 for i=1,#nodes do
1151 if ( first == nil ) then
1152 first = nodes[i]
1153 else
1154 second = nodes[i]
1158 local chest_pos, chest_internal
1160 if (first ~= nil and second ~= nil) then
1161 local dy = (first.y - second.y)/2
1162 chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
1163 if ( chest_pos == nil ) then
1164 chest_pos, chest_internal = easyvend.find_chest(owner, pos, -dy, nodename, check_wear, amount, removing, chest_internal)
1166 else
1167 local dy = first.y - pos.y
1168 chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
1171 if chest_internal.chests == 0 then
1172 return nil, "no_chest"
1173 elseif chest_internal.chests == chest_internal.other_chests then
1174 return nil, "not_owned"
1175 elseif removing and chest_internal.stock < 1 then
1176 return nil, "no_stock"
1177 elseif not removing and chest_internal.space < 1 then
1178 return nil, "no_space"
1179 elseif chest_pos ~= nil then
1180 return chest_pos
1181 else
1182 return nil, "unknown"
1186 easyvend.find_chest = function(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1187 pos = {x=pos.x, y=pos.y + dy, z=pos.z}
1189 if internal == nil then
1190 internal = {}
1191 internal.chests = 0
1192 internal.other_chests = 0
1193 internal.stock = 0
1194 internal.space = 0
1197 local node = minetest.get_node_or_nil(pos)
1198 if ( node == nil ) then
1199 return nil, internal
1201 local chestdef = registered_chests[node.name]
1202 if (chestdef ~= nil) then
1203 internal.chests = internal.chests + 1
1204 local meta = minetest.get_meta(pos)
1205 if (owner ~= meta:get_string(chestdef.meta_owner)) then
1206 internal.other_chests = internal.other_chests + 1
1207 return nil, internal
1209 local inv = meta:get_inventory()
1210 if (inv ~= nil) then
1211 if (itemname ~= nil and minetest.registered_items[itemname] and amount ~= nil and removing ~= nil and check_wear ~= nil) then
1212 local chest_has, chest_free
1213 local stack = {name=itemname, count=amount, wear=0, metadata=""}
1214 local stack_max = minetest.registered_items[itemname].stack_max
1216 local stacks = math.modf(amount / stack_max)
1217 local stacksremainder = math.fmod(amount, stack_max)
1218 local free = stacks
1219 if stacksremainder > 0 then free = free + 1 end
1221 chest_has = easyvend.check_and_get_items(inv, chestdef.inv_list, stack, check_wear)
1222 if chest_has then
1223 internal.stock = internal.stock + 1
1225 chest_free = inv:room_for_item(chestdef.inv_list, stack) and easyvend.free_slots(inv, chestdef.inv_list) >= free
1226 if chest_free then
1227 internal.space = internal.space + 1
1230 if (removing and internal.stock == 0) or (not removing and internal.space == 0) then
1231 return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1232 else
1233 return pos, internal
1235 else
1236 return nil, internal
1238 else
1239 return nil, internal
1241 elseif not easyvend.is_machine(node.name) then
1242 return nil, internal
1245 return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1248 -- Pseudo-inventory handling
1249 easyvend.allow_metadata_inventory_put = function(pos, listname, index, stack, player)
1250 if listname=="item" then
1251 local meta = minetest.get_meta(pos);
1252 local owner = meta:get_string("owner")
1253 local name = player:get_player_name()
1254 if name == owner then
1255 local inv = meta:get_inventory()
1256 if stack == nil then
1257 inv:set_stack( "item", 1, nil )
1258 else
1259 inv:set_stack( "item", 1, stack:get_name() )
1260 meta:set_string("itemname", stack:get_name())
1261 easyvend.set_formspec(pos, player)
1265 return 0
1268 easyvend.allow_metadata_inventory_take = function(pos, listname, index, stack, player)
1269 return 0
1272 easyvend.allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
1273 return 0
1276 minetest.register_abm({
1277 nodenames = {"easyvend:vendor", "easyvend:vendor_on", "easyvend:depositor", "easyvend:depositor_on"},
1278 interval = 5,
1279 chance = 1,
1280 catch_up = false,
1281 action = function(pos, node, active_object_count, active_object_count_wider)
1282 easyvend.machine_check(pos, node)
1286 -- Legacy support for vendor mod:
1287 -- Transform the world and items to use the easyvend nodes/items
1289 -- For safety reasons, only do this when player requested so
1290 if minetest.settings:get_bool("easyvend_convert_vendor") == true then
1291 -- Replace vendor nodes
1292 minetest.register_lbm({
1293 name = "easyvend:replace_vendor",
1294 nodenames = { "vendor:vendor", "vendor:depositor" },
1295 run_at_every_load = true,
1296 action = function(pos, node)
1297 -- Replace node
1298 local newnodename
1299 if node.name == "vendor:vendor" then
1300 newnodename = "easyvend:vendor"
1301 elseif node.name == "vendor:depositor" then
1302 newnodename = "easyvend:depositor"
1304 -- Remove axis rotation; only allow 4 facedirs
1305 local p2 = math.fmod(node.param2, 4)
1306 minetest.swap_node(pos, { name = newnodename, param2 = p2 })
1308 -- Initialize metadata
1309 local meta = minetest.get_meta(pos)
1310 if node.name == "vendor:vendor" then
1311 meta:set_int("earnings", 0)
1313 meta:set_int("stock", -1)
1314 meta:set_int("joketimer", -1)
1315 meta:set_int("joke_id", 1)
1316 local inv = meta:get_inventory()
1317 inv:set_size("item", 1)
1318 inv:set_size("gold", 1)
1319 inv:set_stack("gold", 1, easyvend.currency)
1321 -- In vendor, all machines accepted worn tools
1322 meta:set_int("wear", 1)
1324 -- Set item
1325 local itemname = meta:get_string("itemname")
1326 if itemname == "" or itemname == nil then
1327 itemname = meta:get_string("itemtype")
1329 if itemname ~= "" and itemname ~= nil then
1330 inv:set_stack("item", 1, itemname)
1331 meta:set_string("itemname", itemname)
1334 -- Check for valid item, item count and price
1335 local configmode = 1
1336 if itemname ~= "" and itemname ~= nil then
1337 local itemstack = inv:get_stack("item", 1)
1338 local number_stack_max = itemstack:get_stack_max()
1339 local maxnumber = number_stack_max * slots_max
1340 local cost = meta:get_int("cost")
1341 local number = meta:get_int("number")
1342 if number >= 1 and number <= maxnumber and cost >= 1 and cost <= maxcost then
1343 -- Everything's OK, get out of config mode!
1344 configmode = 0
1348 -- Final initialization stuff
1349 meta:set_int("configmode", configmode)
1351 local owner = meta:get_string("owner")
1352 if easyvend.buysell(newnodename) == "sell" then
1353 meta:set_string("infotext", S("Vending machine (owned by @1)", owner))
1354 else
1355 meta:set_string("infotext", S("Depositing machine (owned by @1)", owner))
1359 meta:set_string("status", S("Initializing ā€¦"))
1360 meta:set_string("message", S("Upgrade successful."))
1361 easyvend.machine_check(pos, node)
1362 end,