Add Wuzzy to mailmap
[minetest_easyvend.git] / easyvend.lua
blob8ef6ae02612b9d3a31b76a28e9e5680e04a5fc05
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,1.45;;"..F(S("Status: @1", status)) .. ";]"
180 .."textarea[2.8,1.3;5.6,1.45;;"..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 local desc = ItemStack(easyvend.currency):get_description()
190 formspec = formspec
191 .."item_image[0,1.65;1,1;"..easyvend.currency.."]"
192 .."tooltip[0,1.65;0.8,0.8;"..F(desc).."]"
193 .."list[current_name;item;0,0.35;1,1;]"
194 .."listring[current_player;main]"
195 .."listring[current_name;item]"
196 .."field[1.3,0.65;1.5,1;number;;" .. number .. "]"
197 .."tooltip[number;"..F(itemcounttooltip).."]"
198 .."field[1.3,1.95;1.5,1;cost;;" .. F(cost) .. "]"
199 .."tooltip[cost;"..F(itemcounttooltip).."]"
200 .."button[6,2.8;2,0.5;save;"..F(S("Confirm")).."]"
201 .."tooltip[save;"..F(S("Confirm configuration and activate machine (only for owner)")).."]"
202 if minetest.get_modpath("select_item") then
203 formspec = formspec .. "button[0,2.8;2,0.5;select_item;"..F(S("Select item")).."]"
205 local weartext, weartooltip
206 if buysell == "buy" then
207 weartext = S("Buy worn tools")
208 weartooltip = S("If disabled, only tools in perfect condition will be bought from sellers (only settable by owner)")
209 else
210 weartext = S("Sell worn tools")
211 weartooltip = S("If disabled, only tools in perfect condition will be sold (only settable by owner)")
213 if minetest.registered_tools[itemname] ~= nil then
214 formspec = formspec .."checkbox[2,2.4;wear;"..F(weartext)..";"..wear.."]"
215 .."tooltip[wear;"..F(weartooltip).."]"
217 else
218 local desc_c = ItemStack(easyvend.currency):get_description()
219 local tt_i = ""
220 if minetest.registered_items[itemname] then
221 local desc_i = ItemStack(itemname):get_description()
222 tt_i = "tooltip[0,0.35;0.8,0.8;"..F(desc_i).."]"
224 formspec = formspec
225 .."item_image[0,1.65;1,1;"..easyvend.currency.."]"
226 .."tooltip[0,1.65;0.8,0.8;"..F(desc_c).."]"
227 .."item_image[0,0.35;1,1;"..itemname.."]"
228 ..tt_i
229 .."label[1,1.85;Ɨ" .. cost .. "]"
230 .."label[1,0.55;Ɨ" .. number .. "]"
231 .."button[6,2.8;2,0.5;config;"..F(S("Configure")).."]"
232 if buysell == "sell" then
233 formspec = formspec .. "tooltip[config;"..F(S("Configure offered items and price (only for owner)")).."]"
234 else
235 formspec = formspec .. "tooltip[config;"..F(S("Configure requested items and payment (only for owner)")).."]"
237 formspec = formspec .."button[0,2.8;2,0.5;buysell;"..F(buysellbuttontext).."]"
238 if minetest.registered_tools[itemname] ~= nil then
239 local weartext
240 if meta:get_int("wear") == 0 then
241 if buysell == "buy" then
242 weartext = S("Only intact tools are bought.")
243 else
244 weartext = S("Only intact tools are sold.")
246 else
247 if buysell == "sell" then
248 weartext = S("Note: Might sell worn tools.")
249 else
250 weartext = S("Accepts worn tools.")
253 if weartext ~= nil then
254 formspec = formspec .."textarea[2.3,2.6;4,1;;"..F(weartext)..";]"
259 meta:set_string("formspec", formspec)
262 easyvend.machine_disable = function(pos, node, playername)
263 if node.name == "easyvend:vendor_on" then
264 easyvend.sound_disable(pos)
265 minetest.swap_node(pos, {name="easyvend:vendor", param2 = node.param2})
266 return true
267 elseif node.name == "easyvend:depositor_on" then
268 easyvend.sound_disable(pos)
269 minetest.swap_node(pos, {name="easyvend:depositor", param2 = node.param2})
270 return true
271 else
272 if playername ~= nil then
273 easyvend.sound_error(playername)
275 return false
279 easyvend.machine_enable = function(pos, node)
280 if node.name == "easyvend:vendor" then
281 easyvend.sound_setup(pos)
282 minetest.swap_node(pos, {name="easyvend:vendor_on", param2 = node.param2})
283 return true
284 elseif node.name == "easyvend:depositor" then
285 easyvend.sound_setup(pos)
286 minetest.swap_node(pos, {name="easyvend:depositor_on", param2 = node.param2})
287 return true
288 else
289 return false
293 easyvend.machine_check = function(pos, node)
294 local active = true
295 local status = S("Ready.")
297 local meta = minetest.get_meta(pos)
299 local machine_owner = meta:get_string("owner")
300 local number = meta:get_int("number")
301 local cost = meta:get_int("cost")
302 local itemname = meta:get_string("itemname")
303 local check_wear = meta:get_int("wear") == 0
304 local inv = meta:get_inventory()
305 local itemstack = inv:get_stack("item",1)
306 local buysell = easyvend.buysell(node.name)
308 local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
309 if buysell == "sell" then
310 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
311 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, false)
312 else
313 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, true)
314 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
316 if chest_pos_remove and chest_pos_add then
317 local rchest, rchestdef, rchest_meta, rchest_inv
318 rchest = minetest.get_node(chest_pos_remove)
319 rchestdef = registered_chests[rchest.name]
320 rchest_meta = minetest.get_meta(chest_pos_remove)
321 rchest_inv = rchest_meta:get_inventory()
323 local checkstack, checkitem
324 if buysell == "buy" then
325 checkitem = easyvend.currency
326 else
327 checkitem = itemname
329 local stock = 0
330 -- Count stock
331 -- FIXME: Ignore tools with bad wear level
332 for i=1,rchest_inv:get_size(rchestdef.inv_list) do
333 checkstack = rchest_inv:get_stack(rchestdef.inv_list, i)
334 if checkstack:get_name() == checkitem then
335 stock = stock + checkstack:get_count()
338 meta:set_int("stock", stock)
340 if not itemstack:is_empty() then
341 local number_stack_max = itemstack:get_stack_max()
342 local maxnumber = number_stack_max * slots_max
343 if not(number >= 1 and number <= maxnumber and cost >= 1 and cost <= maxcost) then
344 active = false
345 if buysell == "sell" then
346 status = S("Invalid item count or price.")
347 else
348 status = S("Invalid item count or payment.")
351 else
352 active = false
353 status = S("Awaiting configuration by owner.")
355 else
356 active = false
357 meta:set_int("stock", 0)
358 if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
359 status = S("No storage; machine needs to be connected with a locked chest.")
360 elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
361 status = S("Storage canā€™t be accessed because it is owned by a different person!")
362 elseif chest_error_remove == "no_stock" then
363 if buysell == "sell" then
364 status = S("The vending machine has insufficient materials!")
365 else
366 status = S("The depositing machine is out of money!")
368 elseif chest_error_add == "no_space" then
369 status = S("No room in the machineā€™s storage!")
370 else
371 status = S("Unknown error!")
374 if meta:get_int("configmode") == 1 then
375 active = false
376 status = S("Awaiting configuration by owner.")
379 if itemname == easyvend.currency and number == cost and active then
380 local jt = meta:get_int("joketimer")
381 if jt > 0 then
382 jt = jt - 1
384 if jt == 0 then
385 if buysell == "sell" then
386 meta:set_string("message", S("Item bought."))
387 else
388 meta:set_string("message", S("Item sold."))
390 jt = -1
392 meta:set_int("joketimer", jt)
394 meta:set_string("status", status)
396 meta:set_string("infotext", easyvend.make_infotext(node.name, machine_owner, cost, number, itemname))
397 itemname=itemstack:get_name()
398 meta:set_string("itemname", itemname)
400 if minetest.get_modpath("awards") and buysell == "sell" then
401 if minetest.get_player_by_name(machine_owner) then
402 local earnings = meta:get_int("earnings")
403 if earnings >= 1 then
404 awards.unlock(machine_owner, "easyvend_seller")
406 if earnings >= easyvend.powerseller then
407 awards.unlock(machine_owner, "easyvend_powerseller")
412 local change
413 if node.name == "easyvend:vendor" or node.name == "easyvend:depositor" then
414 if active then change = easyvend.machine_enable(pos, node) end
415 elseif node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on" then
416 if not active then change = easyvend.machine_disable(pos, node) end
418 easyvend.set_formspec(pos)
419 return change
422 easyvend.on_receive_fields_config = function(pos, formname, fields, sender)
423 local node = minetest.get_node(pos)
424 local meta = minetest.get_meta(pos)
425 local inv_self = meta:get_inventory()
426 local itemstack = inv_self:get_stack("item",1)
427 local buysell = easyvend.buysell(node.name)
429 if fields.config then
430 meta:set_int("configmode", 1)
431 local was_active = easyvend.is_active(node.name)
432 if was_active then
433 meta:set_string("message", S("Configuration mode activated; machine disabled."))
434 else
435 meta:set_string("message", S("Configuration mode activated."))
437 easyvend.machine_check(pos, node)
438 return
441 if not fields.save then
442 return
445 local number = fields.number
446 local cost = fields.cost
448 --[[ Convenience function:
449 When appending ā€œsā€ or ā€œSā€ to the number, it is multiplied
450 by the maximum stack size. ]]
451 local number_stack_max = itemstack:get_stack_max()
452 local ss = string.sub(number, #number, #number)
453 if ss == "s" or ss == "S" then
454 local n = tonumber(string.sub(number, 1, #number-1))
455 if string.len(number) == 1 then n = 1 end
456 if n ~= nil then
457 number = n * number_stack_max
460 ss = string.sub(cost, #cost, #cost)
461 if ss == "s" or ss == "S" then
462 local n = tonumber(string.sub(cost, 1, #cost-1))
463 if string.len(cost) == 1 then n = 1 end
464 if n ~= nil then
465 cost = n * cost_stack_max
468 number = tonumber(number)
469 cost = tonumber(cost)
471 local itemname=""
473 local oldnumber = meta:get_int("number")
474 local oldcost = meta:get_int("cost")
475 local maxnumber = number_stack_max * slots_max
477 if ( itemstack == nil or itemstack:is_empty() ) then
478 meta:set_string("status", S("Awaiting configuration by owner."))
479 meta:set_string("message", S("No item specified."))
480 easyvend.sound_error(sender:get_player_name())
481 easyvend.set_formspec(pos, sender)
482 return
483 elseif ( not itemstack:is_known() ) then
484 meta:set_string("status", S("Awaiting configuration by owner."))
485 meta:set_string("message", S("Unknown item specified."))
486 easyvend.sound_error(sender:get_player_name())
487 easyvend.set_formspec(pos, sender)
488 return
489 elseif ( number == nil or number < 1 or number > maxnumber ) then
490 if maxnumber > 1 then
491 meta:set_string("message", S("Invalid item count; must be between 1 and @1!", maxnumber))
492 else
493 meta:set_string("message", S("Invalid item count; must be exactly 1!"))
495 meta:set_int("number", oldnumber)
496 easyvend.sound_error(sender:get_player_name())
497 easyvend.set_formspec(pos, sender)
498 return
499 elseif ( cost == nil or cost < 1 or cost > maxcost ) then
500 if maxcost > 1 then
501 meta:set_string("message", S("Invalid cost; must be between 1 and @1!", maxcost))
502 else
503 meta:set_string("message", S("Invalid cost; must be exactly 1!"))
505 meta:set_int("cost", oldcost)
506 easyvend.sound_error(sender:get_player_name())
507 easyvend.set_formspec(pos, sender)
508 return
510 meta:set_int("number", number)
511 meta:set_int("cost", cost)
512 itemname=itemstack:get_name()
513 meta:set_string("itemname", itemname)
514 meta:set_int("configmode", 0)
516 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
517 meta:set_string("message", S("Configuration successful. I am feeling funny."))
518 meta:set_int("joketimer", joketimer_start)
519 meta:set_int("joke_id", easyvend.assign_joke(buysell))
520 else
521 meta:set_string("message", S("Configuration successful."))
524 local change = easyvend.machine_check(pos, node)
526 if not change then
527 if (node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on") then
528 easyvend.sound_setup(pos)
529 else
530 easyvend.sound_disable(pos)
535 easyvend.make_infotext = function(nodename, owner, cost, number, itemstring)
536 local d = ""
537 if itemstring == nil or itemstring == "" or number == 0 or cost == 0 then
538 if easyvend.buysell(nodename) == "sell" then
539 d = S("Inactive vending machine (owned by @1)", owner)
540 else
541 d = S("Inactive depositing machine (owned by @1)", owner)
543 return d
545 local iname
546 if minetest.registered_items[itemstring] then
547 iname = minetest.registered_items[itemstring].description
548 else
549 iname = S("Unknown Item (@1)", itemstring)
551 if iname == nil then iname = itemstring end
552 local printitem, printcost
553 if number == 1 then
554 printitem = iname
555 else
556 printitem = S("@1Ɨ@2", number, iname)
558 if cost == 1 then
559 printcost = easyvend.currency_desc
560 else
561 printcost = S("@1Ɨ@2", cost, easyvend.currency_desc)
563 if nodename == "easyvend:vendor_on" then
564 d = S("Vending machine (owned by @1)", owner).."\n"..S("Selling: @1", printitem).."\n"..S("Price: @1", printcost)
565 elseif nodename == "easyvend:vendor" then
566 d = S("Inactive vending machine (owned by @1)", owner).."\n"..S("Selling: @1", printitem).."\n"..S("Price: @1", printcost)
567 elseif nodename == "easyvend:depositor_on" then
568 d = S("Depositing machine (owned by @1)", owner).."\n"..S("Buying: @1", printitem).."\n"..S("Payment: @1", printcost)
569 elseif nodename == "easyvend:depositor" then
570 d = S("Inactive depositing machine (owned by @1)", owner).."\n"..S("Buying: @1", printitem).."\n"..S("Payment: @1", printcost)
572 return d
575 if minetest.get_modpath("awards") then
576 awards.register_achievement("easyvend_seller",{
577 title = S("First Sale"),
578 description = S("Sell something with a vending machine."),
579 icon = "easyvend_vendor_front_on.png^awards_level1.png",
581 local desc_powerseller
582 if easyvend.currency == "default:gold_ingot" then
583 desc_powerseller = S("Earn @1 gold ingots by selling goods with a single vending machine.", easyvend.powerseller)
584 else
585 desc_powerseller = S("Earn @1 currency items by selling goods with a single vending machine.", easyvend.powerseller)
587 awards.register_achievement("easyvend_powerseller",{
588 title = S("Power Seller"),
589 description = desc_powerseller,
590 icon = "easyvend_vendor_front_on.png^awards_level2.png",
594 easyvend.check_earnings = function(buyername, nodemeta)
595 local owner = nodemeta:get_string("owner")
596 if buyername ~= owner then
597 local cost = nodemeta:get_int("cost")
598 local itemname = nodemeta:get_string("itemname")
599 -- First sell
600 if minetest.get_modpath("awards") and minetest.get_player_by_name(owner) ~= nil then
601 awards.unlock(owner, "easyvend_seller")
603 if itemname ~= easyvend.currency then
604 local newearnings = nodemeta:get_int("earnings") + cost
605 if newearnings >= easyvend.powerseller and minetest.get_modpath("awards") then
606 if minetest.get_player_by_name(owner) ~= nil then
607 awards.unlock(owner, "easyvend_powerseller")
610 nodemeta:set_int("earnings", newearnings)
615 easyvend.on_receive_fields_buysell = function(pos, formname, fields, sender)
616 local sendername = sender:get_player_name()
617 local meta = minetest.get_meta(pos)
619 if not fields.buysell then
620 return
623 local node = minetest.get_node(pos)
624 local number = meta:get_int("number")
625 local cost = meta:get_int("cost")
626 local itemname=meta:get_string("itemname")
627 local item=meta:get_inventory():get_stack("item", 1)
628 local check_wear = meta:get_int("wear") == 0 and minetest.registered_tools[itemname] ~= nil
629 local machine_owner = meta:get_string("owner")
631 local buysell = easyvend.buysell(node.name)
633 local number_stack_max = item:get_stack_max()
634 local maxnumber = number_stack_max * slots_max
636 if ( number == nil or number < 1 or number > maxnumber ) or
637 ( cost == nil or cost < 1 or cost > maxcost ) or
638 ( itemname == nil or itemname=="") then
639 meta:set_string("status", S("Invalid item count or price!"))
640 easyvend.machine_disable(pos, node, sendername)
641 return
644 local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
645 if buysell == "sell" then
646 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
647 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, false)
648 else
649 chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, easyvend.currency, check_wear, cost, true)
650 chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
653 if chest_pos_remove ~= nil and chest_pos_add ~= nil and sender and sender:is_player() then
654 local rchest = minetest.get_node(chest_pos_remove)
655 local rchestdef = registered_chests[rchest.name]
656 local rchest_meta = minetest.get_meta(chest_pos_remove)
657 local rchest_inv = rchest_meta:get_inventory()
658 local achest = minetest.get_node(chest_pos_add)
659 local achestdef = registered_chests[achest.name]
660 local achest_meta = minetest.get_meta(chest_pos_add)
661 local achest_inv = achest_meta:get_inventory()
663 local player_inv = sender:get_inventory()
665 local stack = {name=itemname, count=number, wear=0, metadata=""}
666 local price = {name=easyvend.currency, count=cost, wear=0, metadata=""}
667 local chest_has, player_has, chest_free, player_free, chest_out, player_out
668 local msg = ""
669 if buysell == "sell" then
670 chest_has, chest_out = easyvend.check_and_get_items(rchest_inv, rchestdef.inv_list, stack, check_wear)
671 player_has, player_out = easyvend.check_and_get_items(player_inv, "main", price, check_wear)
672 chest_free = achest_inv:room_for_item(achestdef.inv_list, price)
673 player_free = player_inv:room_for_item("main", stack)
674 if chest_has and player_has and chest_free and player_free then
675 if cost <= cost_stack_max and number <= number_stack_max then
676 easyvend.machine_enable(pos, node)
677 player_inv:remove_item("main", price)
678 if check_wear then
679 rchest_inv:set_stack(rchestdef.inv_list, chest_out[1].id, "")
680 player_inv:add_item("main", chest_out[1].item)
681 else
682 stack = rchest_inv:remove_item(rchestdef.inv_list, stack)
683 player_inv:add_item("main", stack)
685 achest_inv:add_item(achestdef.inv_list, price)
686 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
687 meta:set_string("message", easyvend.get_joke(buysell, meta:get_int("joke_id")))
688 meta:set_int("joketimer", joketimer_start)
689 else
690 meta:set_string("message", S("Item bought."))
692 easyvend.check_earnings(sendername, meta)
693 easyvend.sound_vend(pos)
694 easyvend.machine_check(pos, node)
695 else
696 -- Large item counts (multiple stacks)
697 local coststacks = math.modf(cost / cost_stack_max)
698 local costremainder = math.fmod(cost, cost_stack_max)
699 local numberstacks = math.modf(number / number_stack_max)
700 local numberremainder = math.fmod(number, number_stack_max)
701 local numberfree = numberstacks
702 local costfree = coststacks
703 if numberremainder > 0 then numberfree = numberfree + 1 end
704 if costremainder > 0 then costfree = costfree + 1 end
705 if not player_free and easyvend.free_slots(player_inv, "main") < numberfree then
706 if numberfree > 1 then
707 msg = S("No room in your inventory (@1 empty slots required)!", numberfree)
708 else
709 msg = S("No room in your inventory!")
711 meta:set_string("message", msg)
712 elseif not chest_free and easyvend.free_slots(achest_inv, achestdef.inv_list) < costfree then
713 meta:set_string("status", S("No room in the machineā€™s storage!"))
714 easyvend.machine_disable(pos, node, sendername)
715 else
716 -- Remember items for transfer
717 local cheststacks = {}
718 easyvend.machine_enable(pos, node)
719 for i=1, coststacks do
720 price.count = cost_stack_max
721 player_inv:remove_item("main", price)
723 if costremainder > 0 then
724 price.count = costremainder
725 player_inv:remove_item("main", price)
727 if check_wear then
728 for o=1,#chest_out do
729 rchest_inv:set_stack(rchestdef.inv_list, chest_out[o].id, "")
731 else
732 for i=1, numberstacks do
733 stack.count = number_stack_max
734 table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
737 if numberremainder > 0 then
738 stack.count = numberremainder
739 table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
741 for i=1, coststacks do
742 price.count = cost_stack_max
743 achest_inv:add_item(achestdef.inv_list, price)
745 if costremainder > 0 then
746 price.count = costremainder
747 achest_inv:add_item(achestdef.inv_list, price)
749 if check_wear then
750 for o=1,#chest_out do
751 player_inv:add_item("main", chest_out[o].item)
753 else
754 for i=1,#cheststacks do
755 player_inv:add_item("main", cheststacks[i])
758 meta:set_string("message", S("Item bought."))
759 easyvend.check_earnings(sendername, meta)
760 easyvend.sound_vend(pos)
761 easyvend.machine_check(pos, node)
764 elseif chest_has and player_has then
765 if not player_free then
766 msg = S("No room in your inventory!")
767 meta:set_string("message", msg)
768 easyvend.sound_error(sendername)
769 elseif not chest_free then
770 msg = S("No room in the machineā€™s storage!")
771 meta:set_string("status", msg)
772 easyvend.machine_disable(pos, node, sendername)
774 else
775 if not chest_has then
776 msg = S("The vending machine has insufficient materials!")
777 meta:set_string("status", msg)
778 easyvend.machine_disable(pos, node, sendername)
779 elseif not player_has then
780 msg = S("You canā€™t afford this item!")
781 meta:set_string("message", msg)
782 easyvend.sound_error(sendername)
785 else
786 chest_has, chest_out = easyvend.check_and_get_items(rchest_inv, rchestdef.inv_list, price, check_wear)
787 player_has, player_out = easyvend.check_and_get_items(player_inv, "main", stack, check_wear)
788 chest_free = achest_inv:room_for_item(achestdef.inv_list, stack)
789 player_free = player_inv:room_for_item("main", price)
790 if chest_has and player_has and chest_free and player_free then
791 if cost <= cost_stack_max and number <= number_stack_max then
792 easyvend.machine_enable(pos, node)
793 if check_wear then
794 player_inv:set_stack("main", player_out[1].id, "")
795 achest_inv:add_item(achestdef.inv_list, player_out[1].item)
796 else
797 stack = player_inv:remove_item("main", stack)
798 achest_inv:add_item(achestdef.inv_list, stack)
800 rchest_inv:remove_item(rchestdef.inv_list, price)
801 player_inv:add_item("main", price)
802 meta:set_string("status", S("Ready."))
803 if itemname == easyvend.currency and number == cost and cost <= cost_stack_max then
804 meta:set_string("message", easyvend.get_joke(buysell, meta:get_int("joke_id")))
805 meta:set_int("joketimer", joketimer_start)
806 else
807 meta:set_string("message", S("Item sold."))
809 easyvend.sound_deposit(pos)
810 easyvend.machine_check(pos, node)
811 else
812 -- Large item counts (multiple stacks)
813 local coststacks = math.modf(cost / cost_stack_max)
814 local costremainder = math.fmod(cost, cost_stack_max)
815 local numberstacks = math.modf(number / number_stack_max)
816 local numberremainder = math.fmod(number, number_stack_max)
817 local numberfree = numberstacks
818 local costfree = coststacks
819 if numberremainder > 0 then numberfree = numberfree + 1 end
820 if costremainder > 0 then costfree = costfree + 1 end
821 if not player_free and easyvend.free_slots(player_inv, "main") < costfree then
822 if costfree > 1 then
823 msg = S("No room in your inventory (@1 empty slots required)!", costfree)
824 else
825 msg = S("No room in your inventory!")
827 meta:set_string("message", msg)
828 easyvend.sound_error(sendername)
829 elseif not chest_free and easyvend.free_slots(achest_inv, achestdef.inv_list) < numberfree then
830 meta:set_string("status", S("No room in the machineā€™s storage!"))
831 easyvend.machine_disable(pos, node, sendername)
832 else
833 easyvend.machine_enable(pos, node)
834 -- Remember removed items for transfer
835 local playerstacks = {}
836 for i=1, coststacks do
837 price.count = cost_stack_max
838 rchest_inv:remove_item(rchestdef.inv_list, price)
840 if costremainder > 0 then
841 price.count = costremainder
842 rchest_inv:remove_item(rchestdef.inv_list, price)
844 if check_wear then
845 for o=1,#player_out do
846 player_inv:set_stack("main", player_out[o].id, "")
848 else
849 for i=1, numberstacks do
850 stack.count = number_stack_max
851 table.insert(playerstacks, player_inv:remove_item("main", stack))
854 if numberremainder > 0 then
855 stack.count = numberremainder
856 table.insert(playerstacks, player_inv:remove_item("main", stack))
858 for i=1, coststacks do
859 price.count = cost_stack_max
860 player_inv:add_item("main", price)
862 if costremainder > 0 then
863 price.count = costremainder
864 player_inv:add_item("main", price)
866 if check_wear then
867 for o=1,#player_out do
868 achest_inv:add_item(achestdef.inv_list, player_out[o].item)
870 else
871 for i=1,#playerstacks do
872 achest_inv:add_item(achestdef.inv_list, playerstacks[i])
875 meta:set_string("message", S("Item sold."))
876 easyvend.sound_deposit(pos)
877 easyvend.machine_check(pos, node)
880 elseif chest_has and player_has then
881 if not player_free then
882 msg = S("No room in your inventory!")
883 meta:set_string("message", msg)
884 easyvend.sound_error(sendername)
885 elseif not chest_free then
886 msg = S("No room in the machineā€™s storage!")
887 meta:set_string("status", msg)
888 easyvend.machine_disable(pos, node, sendername)
890 else
891 if not player_has then
892 msg = S("You have insufficient materials!")
893 meta:set_string("message", msg)
894 easyvend.sound_error(sendername)
895 elseif not chest_has then
896 msg = S("The depositing machine is out of money!")
897 meta:set_string("status", msg)
898 easyvend.machine_disable(pos, node, sendername)
902 else
903 local status
904 meta:set_int("stock", 0)
905 if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
906 status = S("No storage; machine needs to be connected with a locked chest.")
907 elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
908 status = S("Storage canā€™t be accessed because it is owned by a different person!")
909 elseif chest_error_remove == "no_stock" then
910 if buysell == "sell" then
911 status = S("The vending machine has insufficient materials!")
912 else
913 status = S("The depositing machine is out of money!")
915 elseif chest_error_add == "no_space" then
916 status = S("No room in the machineā€™s storage!")
917 else
918 status = S("Unknown error!")
920 meta:set_string("status", status)
921 easyvend.sound_error(sendername)
924 easyvend.set_formspec(pos, sender)
928 easyvend.after_place_node = function(pos, placer)
929 local node = minetest.get_node(pos)
930 local meta = minetest.get_meta(pos)
931 local inv = meta:get_inventory()
932 local player_name = placer:get_player_name()
933 inv:set_size("item", 1)
934 inv:set_size("gold", 1)
936 inv:set_stack( "gold", 1, easyvend.currency )
938 local d = ""
939 if node.name == "easyvend:vendor" then
940 d = S("Inactive vending machine (owned by @1)", player_name)
941 meta:set_int("wear", 1)
942 -- Total number of currency items earned for the machine's life time (excluding currency-currency trading)
943 meta:set_int("earnings", 0)
944 elseif node.name == "easyvend:depositor" then
945 d = S("Inactive depositing machine (owned by @1)", player_name)
946 meta:set_int("wear", 0)
948 meta:set_string("infotext", d)
949 meta:set_string("status", S("Awaiting configuration by owner."))
950 meta:set_string("message", S("Please select an item and amount, then confirm."))
951 meta:set_int("number", 1)
952 meta:set_int("cost", 1)
953 meta:set_int("stock", -1)
954 meta:set_int("configmode", 1)
955 meta:set_int("joketimer", -1)
956 meta:set_int("joke_id", 1)
957 meta:set_string("itemname", "")
959 meta:set_string("owner", player_name or "")
961 easyvend.set_formspec(pos, placer)
964 easyvend.can_dig = function(pos, player)
965 local meta = minetest.get_meta(pos)
966 local name = player:get_player_name()
967 local owner = meta:get_string("owner")
968 -- Owner can always dig shop
969 if owner == name then
970 return true
972 local chest_pos = easyvend.find_connected_chest(owner, pos)
973 local chest, meta_chest
974 if chest_pos then
975 chest = minetest.get_node(chest_pos)
976 meta_chest = minetest.get_meta(chest_pos)
977 else
978 return true --if no chest, enyone can dig this shop
980 if registered_chests[chest.name] then
981 if player and player:is_player() then
982 local owner_chest = meta_chest:get_string(registered_chests[chest.name].meta_owner)
983 if name == owner_chest then
984 return true --chest owner can also dig shop
987 return false
988 else
989 return true --if no chest, enyone can dig this shop
993 easyvend.on_receive_fields = function(pos, formname, fields, sender)
994 local meta = minetest.get_meta(pos)
995 local node = minetest.get_node(pos)
996 local owner = meta:get_string("owner")
997 local sendername = sender:get_player_name()
999 if fields.doc then
1000 if minetest.get_modpath("doc") and minetest.get_modpath("doc_items") then
1001 if easyvend.buysell(node.name) == "buy" then
1002 doc.show_entry(sendername, "nodes", "easyvend:depositor", true)
1003 else
1004 doc.show_entry(sendername, "nodes", "easyvend:vendor", true)
1007 elseif fields.config or fields.save or fields.usermode then
1008 if sendername == owner then
1009 easyvend.on_receive_fields_config(pos, formname, fields, sender)
1010 else
1011 meta:set_string("message", S("Only the owner may change the configuration."))
1012 easyvend.sound_error(sendername)
1013 easyvend.set_formspec(pos, sender)
1014 return
1016 elseif fields.select_item then
1017 if minetest.get_modpath("select_item") then
1018 if sendername == owner then
1019 active_item_selection[sendername] = pos
1020 select_item.show_dialog(sendername, "easyvend:trade_item", select_item.filters.creative)
1021 else
1022 meta:set_string("message", S("Only the owner may change the configuration."))
1023 easyvend.sound_error(sendername)
1024 easyvend.set_formspec(pos, sender)
1025 return
1028 elseif fields.wear ~= nil then
1029 if sender:get_player_name() == owner then
1030 if fields.wear == "true" then
1031 if easyvend.buysell(node.name) == "buy" then
1032 meta:set_string("message", S("Used tools are now accepted."))
1033 else
1034 meta:set_string("message", S("Used tools are now for sale."))
1036 meta:set_int("wear", 1)
1037 elseif fields.wear == "false" then
1038 if easyvend.buysell(node.name) == "buy" then
1039 meta:set_string("message", S("Used tools are now rejected."))
1040 else
1041 meta:set_string("message", S("Used tools wonā€™t be sold anymore."))
1043 meta:set_int("wear", 0)
1045 easyvend.set_formspec(pos, sender)
1046 return
1047 else
1048 meta:set_string("message", S("Only the owner may change the configuration."))
1049 easyvend.sound_error(sendername)
1050 easyvend.set_formspec(pos, sender)
1051 return
1053 elseif fields.buysell then
1054 easyvend.on_receive_fields_buysell(pos, formname, fields, sender)
1058 -- Jokes: Appear when machine exchanges currency for currency at equal rate
1060 -- Vendor
1061 local jokes_vendor = {
1062 S("Thank you. You have made a vending machine very happy."),
1063 S("Humans have a strange sense of humor."),
1064 S("Letā€™s get this over with ā€¦"),
1065 S("Item ā€œboughtā€."),
1066 S("Tit for tat."),
1067 S("Do you realize what youā€™ve just bought?"),
1069 -- Depositor
1070 local jokes_depositor = {
1071 S("Thank you, the money started to smell inside."),
1072 S("Money doesnā€™t grow on trees, you know?"),
1073 S("Sanity sold."),
1074 S("Well, that was an awkward exchange."),
1075 S("Are you having fun?"),
1076 S("Is this really trading?"),
1079 easyvend.assign_joke = function(buysell)
1080 local jokes
1081 if buysell == "sell" then
1082 jokes = jokes_vendor
1083 elseif buysell == "buy" then
1084 jokes = jokes_depositor
1086 local r = math.random(1,#jokes)
1087 return r
1090 easyvend.get_joke = function(buysell, id)
1091 local joke
1092 if buysell == nil or id == nil then
1093 -- Fallback message (should never happen)
1094 return S("Items exchanged.")
1096 if buysell == "sell" then
1097 joke = jokes_vendor[id]
1098 if joke == nil then joke = jokes_vendor[1] end
1099 elseif buysell == "buy" then
1100 joke = jokes_depositor[id]
1101 if joke == nil then joke = jokes_depositor[1] end
1103 return joke
1106 easyvend.sound_error = function(playername)
1107 minetest.sound_play("easyvend_error", {to_player = playername, gain = 0.25}, true)
1110 easyvend.sound_setup = function(pos)
1111 minetest.sound_play("easyvend_activate", {pos = pos, gain = 0.5, max_hear_distance = 12,}, true)
1114 easyvend.sound_disable = function(pos)
1115 minetest.sound_play("easyvend_disable", {pos = pos, gain = 0.9, max_hear_distance = 12,}, true)
1118 easyvend.sound_vend = function(pos)
1119 minetest.sound_play("easyvend_vend", {pos = pos, gain = 0.4, max_hear_distance = 5,}, true)
1122 easyvend.sound_deposit = function(pos)
1123 minetest.sound_play("easyvend_deposit", {pos = pos, gain = 0.4, max_hear_distance = 5,}, true)
1126 --[[ Tower building ]]
1128 easyvend.is_traversable = function(pos)
1129 local node = minetest.get_node_or_nil(pos)
1130 if (node == nil) then
1131 return false
1133 return traversable_node_types[node.name] == true
1136 easyvend.neighboring_nodes = function(pos)
1137 local check = {
1138 {x=pos.x, y=pos.y-1, z=pos.z},
1139 {x=pos.x, y=pos.y+1, z=pos.z},
1141 local trav = {}
1142 for i=1,#check do
1143 if easyvend.is_traversable(check[i]) then
1144 table.insert(trav, check[i])
1147 return trav
1150 easyvend.find_connected_chest = function(owner, pos, nodename, check_wear, amount, removing)
1151 local nodes = easyvend.neighboring_nodes(pos)
1153 if (#nodes < 1 or #nodes > 2) then
1154 return nil, "no_chest"
1157 -- Find the stack direction
1158 local first = nil
1159 local second = nil
1160 for i=1,#nodes do
1161 if ( first == nil ) then
1162 first = nodes[i]
1163 else
1164 second = nodes[i]
1168 local chest_pos, chest_internal
1170 if (first ~= nil and second ~= nil) then
1171 local dy = (first.y - second.y)/2
1172 chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
1173 if ( chest_pos == nil ) then
1174 chest_pos, chest_internal = easyvend.find_chest(owner, pos, -dy, nodename, check_wear, amount, removing, chest_internal)
1176 else
1177 local dy = first.y - pos.y
1178 chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
1181 if chest_internal.chests == 0 then
1182 return nil, "no_chest"
1183 elseif chest_internal.chests == chest_internal.other_chests then
1184 return nil, "not_owned"
1185 elseif removing and chest_internal.stock < 1 then
1186 return nil, "no_stock"
1187 elseif not removing and chest_internal.space < 1 then
1188 return nil, "no_space"
1189 elseif chest_pos ~= nil then
1190 return chest_pos
1191 else
1192 return nil, "unknown"
1196 easyvend.find_chest = function(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1197 pos = {x=pos.x, y=pos.y + dy, z=pos.z}
1199 if internal == nil then
1200 internal = {}
1201 internal.chests = 0
1202 internal.other_chests = 0
1203 internal.stock = 0
1204 internal.space = 0
1207 local node = minetest.get_node_or_nil(pos)
1208 if ( node == nil ) then
1209 return nil, internal
1211 local chestdef = registered_chests[node.name]
1212 if (chestdef ~= nil) then
1213 internal.chests = internal.chests + 1
1214 local meta = minetest.get_meta(pos)
1215 if (owner ~= meta:get_string(chestdef.meta_owner)) then
1216 internal.other_chests = internal.other_chests + 1
1217 return nil, internal
1219 local inv = meta:get_inventory()
1220 if (inv ~= nil) then
1221 if (itemname ~= nil and minetest.registered_items[itemname] and amount ~= nil and removing ~= nil and check_wear ~= nil) then
1222 local chest_has, chest_free
1223 local stack = {name=itemname, count=amount, wear=0, metadata=""}
1224 local stack_max = minetest.registered_items[itemname].stack_max
1226 local stacks = math.modf(amount / stack_max)
1227 local stacksremainder = math.fmod(amount, stack_max)
1228 local free = stacks
1229 if stacksremainder > 0 then free = free + 1 end
1231 chest_has = easyvend.check_and_get_items(inv, chestdef.inv_list, stack, check_wear)
1232 if chest_has then
1233 internal.stock = internal.stock + 1
1235 chest_free = inv:room_for_item(chestdef.inv_list, stack) and easyvend.free_slots(inv, chestdef.inv_list) >= free
1236 if chest_free then
1237 internal.space = internal.space + 1
1240 if (removing and internal.stock == 0) or (not removing and internal.space == 0) then
1241 return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1242 else
1243 return pos, internal
1245 else
1246 return nil, internal
1248 else
1249 return nil, internal
1251 elseif not easyvend.is_machine(node.name) then
1252 return nil, internal
1255 return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
1258 -- Pseudo-inventory handling
1259 easyvend.allow_metadata_inventory_put = function(pos, listname, index, stack, player)
1260 if listname=="item" then
1261 local meta = minetest.get_meta(pos);
1262 local owner = meta:get_string("owner")
1263 local name = player:get_player_name()
1264 if name == owner then
1265 local inv = meta:get_inventory()
1266 if stack == nil then
1267 inv:set_stack( "item", 1, nil )
1268 else
1269 inv:set_stack( "item", 1, stack:get_name() )
1270 meta:set_string("itemname", stack:get_name())
1271 easyvend.set_formspec(pos, player)
1275 return 0
1278 easyvend.allow_metadata_inventory_take = function(pos, listname, index, stack, player)
1279 return 0
1282 easyvend.allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
1283 return 0
1286 minetest.register_abm({
1287 nodenames = {"easyvend:vendor", "easyvend:vendor_on", "easyvend:depositor", "easyvend:depositor_on"},
1288 interval = 5,
1289 chance = 1,
1290 catch_up = false,
1291 action = function(pos, node, active_object_count, active_object_count_wider)
1292 easyvend.machine_check(pos, node)
1296 -- Legacy support for vendor mod:
1297 -- Transform the world and items to use the easyvend nodes/items
1299 -- For safety reasons, only do this when player requested so
1300 if minetest.settings:get_bool("easyvend_convert_vendor") == true then
1301 -- Replace vendor nodes
1302 minetest.register_lbm({
1303 name = "easyvend:replace_vendor",
1304 nodenames = { "vendor:vendor", "vendor:depositor" },
1305 run_at_every_load = true,
1306 action = function(pos, node)
1307 -- Replace node
1308 local newnodename
1309 if node.name == "vendor:vendor" then
1310 newnodename = "easyvend:vendor"
1311 elseif node.name == "vendor:depositor" then
1312 newnodename = "easyvend:depositor"
1314 -- Remove axis rotation; only allow 4 facedirs
1315 local p2 = math.fmod(node.param2, 4)
1316 minetest.swap_node(pos, { name = newnodename, param2 = p2 })
1318 -- Initialize metadata
1319 local meta = minetest.get_meta(pos)
1320 if node.name == "vendor:vendor" then
1321 meta:set_int("earnings", 0)
1323 meta:set_int("stock", -1)
1324 meta:set_int("joketimer", -1)
1325 meta:set_int("joke_id", 1)
1326 local inv = meta:get_inventory()
1327 inv:set_size("item", 1)
1328 inv:set_size("gold", 1)
1329 inv:set_stack("gold", 1, easyvend.currency)
1331 -- In vendor, all machines accepted worn tools
1332 meta:set_int("wear", 1)
1334 -- Set item
1335 local itemname = meta:get_string("itemname")
1336 if itemname == "" or itemname == nil then
1337 itemname = meta:get_string("itemtype")
1339 if itemname ~= "" and itemname ~= nil then
1340 inv:set_stack("item", 1, itemname)
1341 meta:set_string("itemname", itemname)
1344 -- Check for valid item, item count and price
1345 local configmode = 1
1346 if itemname ~= "" and itemname ~= nil then
1347 local itemstack = inv:get_stack("item", 1)
1348 local number_stack_max = itemstack:get_stack_max()
1349 local maxnumber = number_stack_max * slots_max
1350 local cost = meta:get_int("cost")
1351 local number = meta:get_int("number")
1352 if number >= 1 and number <= maxnumber and cost >= 1 and cost <= maxcost then
1353 -- Everything's OK, get out of config mode!
1354 configmode = 0
1358 -- Final initialization stuff
1359 meta:set_int("configmode", configmode)
1361 local owner = meta:get_string("owner")
1362 if easyvend.buysell(newnodename) == "sell" then
1363 meta:set_string("infotext", S("Vending machine (owned by @1)", owner))
1364 else
1365 meta:set_string("infotext", S("Depositing machine (owned by @1)", owner))
1369 meta:set_string("status", S("Initializing ā€¦"))
1370 meta:set_string("message", S("Upgrade successful."))
1371 easyvend.machine_check(pos, node)
1372 end,