3 --Copyright (C) 2012 Bad_Command
6 --This library is free software; you can redistribute it and/or
7 --modify it under the terms of the GNU Lesser General Public
8 --License as published by the Free Software Foundation; either
9 --version 2.1 of the License, or (at your option) any later version.
11 --This program is distributed in the hope that it will be useful,
12 --but WITHOUT ANY WARRANTY; without even the implied warranty of
13 --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 --GNU General Public License for more details.
16 --You should have received a copy of the GNU Lesser General Public
17 --License along with this library; if not, write to the Free Software
18 --Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 -- TODO: Improve mod compability
24 -- Set item which is used as payment for vending and depositing machines
25 local currency
= minetest
.setting_get("easyvend_currency")
26 if currency
== nil or minetest
.registered_items
[currency
] == nil then
27 currency
= "default:gold_ingot"
30 local currency_desc
= minetest
.registered_items
[currency
].description
31 local registered_chests
= {}
32 local cost_stack_max
= ItemStack(currency
):get_stack_max()
33 local maxcost
= cost_stack_max
* slots_max
35 local joketimer_start
= 3
37 -- Allow for other mods to register custom chests
38 easyvend
.register_chest
= function(node_name
, inv_list
, meta_owner
)
39 registered_chests
[node_name
] = { inv_list
= inv_list
, meta_owner
= meta_owner
}
42 -- Partly a wrapper around contains_item, but does special treatment if the item
43 -- is a tool. Basically checks whether the items exist in the supplied inventory
44 -- list. If check_wear is true, only counts items without wear.
45 easyvend
.check_and_get_items
= function(inventory
, listname
, itemtable
, check_wear
)
46 local itemstring
= itemtable
.name
47 local minimum
= itemtable
.count
48 if check_wear
== nil then check_wear
= false end
51 if minetest
.registered_tools
[itemstring
] ~= nil then
53 for i
=1,inventory
:get_size(listname
) do
54 local stack
= inventory
:get_stack(listname
, i
)
55 if stack
:get_name() == itemstring
then
56 if not check_wear
or stack
:get_wear() == 0 then
58 table.insert(get_items
, {id
=i
, item
=stack
})
59 if count
>= minimum
then
60 return true, get_items
67 -- Normal Minetest check
68 return inventory
:contains_item(listname
, ItemStack(itemtable
))
73 if minetest
.get_modpath("default") ~= nil then
74 easyvend
.register_chest("default:chest_locked", "main", "owner")
77 easyvend
.free_slots
= function(inv
, listname
)
78 local size
= inv
:get_size(listname
)
81 local stack
= inv
:get_stack(listname
, i
)
82 if stack
:is_empty() then
89 easyvend
.buysell
= function(nodename
)
91 if ( nodename
== "easyvend:depositor" or nodename
== "easyvend:depositor_on" ) then
93 elseif ( nodename
== "easyvend:vendor" or nodename
== "easyvend:vendor_on" ) then
99 easyvend
.set_formspec
= function(pos
, player
)
100 local meta
= minetest
.get_meta(pos
)
101 local node
= minetest
.get_node(pos
)
103 local description
= minetest
.registered_nodes
[node
.name
].description
;
104 local number = meta
:get_int("number")
105 local cost
= meta
:get_int("cost")
107 local configmode
= meta
:get_int("configmode") == 1
108 if minetest
.get_modpath("default") then
109 bg
= default
.gui_bg
.. default
.gui_bg_img
.. default
.gui_slots
112 local numbertext
, costtext
, buysellbuttontext
113 local itemcounttooltip
= "Item count (append “s” to multiply with maximum stack size)"
114 local buysell
= easyvend
.buysell(node
.name
)
115 if buysell
== "sell" then
116 numbertext
= "Offered item"
118 buysellbuttontext
= "Buy"
119 elseif buysell
== "buy" then
120 numbertext
= "Requested item"
122 buysellbuttontext
= "Sell"
126 local status
= meta
:get_string("status")
127 if status
== "" then status
= "Unknown." end
128 local message
= meta
:get_string("message")
129 if message
== "" then message
= "No message." end
131 if node
.name
== "easyvend:vendor_on" or node
.name
== "easyvend:depositor_on" then
132 status_image
= "easyvend_status_on.png"
134 status_image
= "easyvend_status_off.png"
137 local formspec
= "size[8,7.3;]"
139 .."label[3,-0.2;" .. minetest
.formspec_escape(description
) .. "]"
141 .."image[7.5,0.2;0.5,1;" .. status_image
.. "]"
142 .."textarea[2.8,0.2;5.1,2;;Status: " .. minetest
.formspec_escape(status
) .. ";]"
143 .."textarea[2.8,1.3;5.6,2;;Message: " .. minetest
.formspec_escape(message
) .. ";]"
145 .."label[0,-0.15;"..numbertext
.."]"
146 .."label[0,1.2;"..costtext
.."]"
147 .."list[current_player;main;0,3.5;8,4;]"
150 if meta
:get_int("wear") == 1 then wear
= "true" end
152 .."item_image_button[0,1.65;1,1;"..currency
..";currency_image;]"
153 .."list[current_name;item;0,0.35;1,1;]"
154 .."listring[current_player;main]"
155 .."listring[current_name;item]"
156 .."field[1.3,0.65;1.5,1;number;;" .. number .. "]"
157 .."tooltip[number;"..itemcounttooltip
.."]"
158 .."field[1.3,1.95;1.5,1;cost;;" .. cost
.. "]"
159 .."tooltip[cost;"..itemcounttooltip
.."]"
160 .."button[6,2.8;2,0.5;save;Confirm]"
161 .."tooltip[save;Confirm configuration and activate machine (only for owner)]"
162 local weartext
, weartooltip
163 if buysell
== "buy" then
164 weartext
= "Accept worn tools"
165 weartooltip
= "If disabled, only tools in perfect condition will be bought from sellers (only settable by owner)"
167 weartext
= "Sell worn tools"
168 weartooltip
= "If disabled, only tools in perfect condition will be sold (only settable by owner)"
170 formspec
= formspec
.."checkbox[2,2.4;wear;"..minetest
.formspec_escape(weartext
)..";"..wear
.."]"
171 .."tooltip[wear;"..minetest
.formspec_escape(weartooltip
).."]"
173 local itemname
= meta
:get_string("itemname")
175 .."item_image_button[0,1.65;1,1;"..currency
..";currency_image;]"
176 .."item_image_button[0,0.35;1,1;"..itemname
..";item_image;]"
177 .."label[1,1.85;×" .. cost
.. "]"
178 .."label[1,0.55;×" .. number .. "]"
179 .."button[6,2.8;2,0.5;config;Configure]"
180 if buysell
== "sell" then
181 formspec
= formspec
.. "tooltip[config;Configure offered items and price (only for owner)]"
183 formspec
= formspec
.. "tooltip[config;Configure requested items and payment (only for owner)]"
185 formspec
= formspec
.."button[0,2.8;2,0.5;buysell;"..buysellbuttontext
.."]"
186 if minetest
.registered_tools
[itemname
] ~= nil then
188 if meta
:get_int("wear") == 0 then
189 if buysell
== "buy" then
190 weartext
= "Only intact tools are bought."
192 weartext
= "Only intact tools are sold."
194 elseif buysell
== "sell" then
195 weartext
= "Warning: Might sell worn tools."
197 if weartext
~= nil then
198 formspec
= formspec
.."textarea[2.3,2.6;3,1;;"..minetest
.formspec_escape(weartext
)..";]"
203 meta
:set_string("formspec", formspec
)
206 easyvend
.machine_disable
= function(pos
, node
, playername
)
207 if node
.name
== "easyvend:vendor_on" then
208 easyvend
.sound_disable(pos
)
209 minetest
.swap_node(pos
, {name
="easyvend:vendor", param2
= node
.param2
})
211 elseif node
.name
== "easyvend:depositor_on" then
212 easyvend
.sound_disable(pos
)
213 minetest
.swap_node(pos
, {name
="easyvend:depositor", param2
= node
.param2
})
216 if playername
~= nil then
217 easyvend
.sound_error(playername
)
223 easyvend
.machine_enable
= function(pos
, node
)
224 if node
.name
== "easyvend:vendor" then
225 easyvend
.sound_setup(pos
)
226 minetest
.swap_node(pos
, {name
="easyvend:vendor_on", param2
= node
.param2
})
228 elseif node
.name
== "easyvend:depositor" then
229 easyvend
.sound_setup(pos
)
230 minetest
.swap_node(pos
, {name
="easyvend:depositor_on", param2
= node
.param2
})
237 easyvend
.machine_check
= function(pos
, node
)
239 local status
= "Ready."
241 local chest
= minetest
.get_node({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
242 local meta
= minetest
.get_meta(pos
)
243 local number = meta
:get_int("number")
244 local cost
= meta
:get_int("cost")
245 local inv
= meta
:get_inventory()
246 local itemstack
= inv
:get_stack("item",1)
247 local itemname
=meta
:get_string("itemname")
248 local machine_owner
= meta
:get_string("owner")
249 local check_wear
= meta
:get_int("wear") == 0
250 local chestdef
= registered_chests
[chest
.name
]
253 local chest_meta
= minetest
.get_meta({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
254 local chest_inv
= chest_meta
:get_inventory()
256 if ( chest_meta
:get_string(chestdef
.meta_owner
) == machine_owner
and chest_inv
~= nil ) then
257 local buysell
= easyvend
.buysell(node
.name
)
259 if not itemstack
:is_empty() then
261 local number_stack_max
= itemstack
:get_stack_max()
263 local stack
= {name
=itemname
, count
=number, wear
=0, metadata
=""}
264 local price
= {name
=currency
, count
=cost
, wear
=0, metadata
=""}
266 local chest_has
, chest_free
268 local coststacks
= math
.modf(cost
/ cost_stack_max
)
269 local costremainder
= math
.fmod(cost
, cost_stack_max
)
270 local numberstacks
= math
.modf(number / number_stack_max
)
271 local numberremainder
= math
.fmod(number, number_stack_max
)
272 local numberfree
= numberstacks
273 local costfree
= coststacks
274 if numberremainder
> 0 then numberfree
= numberfree
+ 1 end
275 if costremainder
> 0 then costfree
= costfree
+ 1 end
277 if buysell
== "sell" then
278 chest_has
= easyvend
.check_and_get_items(chest_inv
, chestdef
.inv_list
, stack
, check_wear
)
279 chest_free
= chest_inv
:room_for_item(chestdef
.inv_list
, price
)
280 if chest_has
and chest_free
then
281 if cost
<= cost_stack_max
and number <= number_stack_max
then
283 elseif easyvend
.free_slots(chest_inv
, chestdef
.inv_list
) < costfree
then
285 status
= "No room in the machine’s storage!"
287 elseif not chest_has
then
289 status
= "The vending machine has insufficient materials!"
290 elseif not chest_free
then
292 status
= "No room in the machine’s storage!"
294 elseif buysell
== "buy" then
295 chest_has
= easyvend
.check_and_get_items(chest_inv
, chestdef
.inv_list
, price
, check_wear
)
296 chest_free
= chest_inv
:room_for_item(chestdef
.inv_list
, stack
)
297 if chest_has
and chest_free
then
298 if cost
<= cost_stack_max
and number <= number_stack_max
then
300 elseif easyvend
.free_slots(chest_inv
, chestdef
.inv_list
) < numberfree
then
302 status
= "No room in the machine’s storage!"
304 elseif not chest_has
then
306 status
= "The depositing machine is out of money!"
307 elseif not chest_free
then
309 status
= "No room in the machine’s storage!"
314 status
= "Awaiting configuration by owner."
318 status
= "Storage can’t be accessed because it is owned by a different person!"
322 status
= "No storage; machine needs a locked chest below it."
324 if meta
:get_int("configmode") == 1 then
326 status
= "Awaiting configuration by owner."
329 if itemname
== currency
and number == cost
and active
then
330 local jt
= meta
:get_int("joketimer")
335 meta
:set_string("message", "Ready.")
338 meta
:set_int("joketimer", jt
)
340 meta
:set_string("status", status
)
342 if not itemstack
:is_empty() then
343 if itemname
== nil or itemname
== "" then
344 itemname
= itemstack
:get_name()
346 meta
:set_string("infotext", easyvend
.make_infotext(node
.name
, machine_owner
, cost
, number, itemname
))
348 itemname
=itemstack
:get_name()
349 meta
:set_string("itemname", itemname
)
352 if node
.name
== "easyvend:vendor" or node
.name
== "easyvend:depositor" then
353 if active
then change
= easyvend
.machine_enable(pos
, node
) end
354 elseif node
.name
== "easyvend:vendor_on" or node
.name
== "easyvend:depositor_on" then
355 if not active
then change
= easyvend
.machine_disable(pos
, node
) end
357 easyvend
.set_formspec(pos
)
361 easyvend
.on_receive_fields_config
= function(pos
, formname
, fields
, sender
)
362 local node
= minetest
.get_node(pos
)
363 local meta
= minetest
.get_meta(pos
)
364 local inv_self
= meta
:get_inventory()
365 local itemstack
= inv_self
:get_stack("item",1)
366 local buysell
= easyvend
.buysell(node
.name
)
368 if fields
.config
then
369 meta
:set_int("configmode", 1)
370 easyvend
.machine_check(pos
, node
)
374 if not fields
.save
then
378 local number = fields
.number
379 local cost
= fields
.cost
381 --[[ Convenience function:
382 When appending “s” or “S” to the number, it is multiplied
383 by the maximum stack size.
384 TODO: Expose this in user documentation ]]
385 local number_stack_max
= itemstack
:get_stack_max()
386 local ss
= string.sub(number, #number, #number)
387 if ss
== "s" or ss
== "S" then
388 local n
= tonumber(string.sub(number, 1, #number-1))
389 if string.len(number) == 1 then n
= 1 end
391 number = n
* number_stack_max
394 ss
= string.sub(cost
, #cost
, #cost
)
395 if ss
== "s" or ss
== "S" then
396 local n
= tonumber(string.sub(cost
, 1, #cost
-1))
397 if string.len(cost
) == 1 then n
= 1 end
399 cost
= n
* cost_stack_max
402 number = tonumber(number)
403 cost
= tonumber(cost
)
407 local oldnumber
= meta
:get_int("number")
408 local oldcost
= meta
:get_int("cost")
409 local maxnumber
= number_stack_max
* slots_max
411 if ( itemstack
== nil or itemstack
:is_empty() ) then
412 meta
:set_string("status", "Awaiting configuration by owner.")
413 meta
:set_string("message", "You must specify an item.")
414 easyvend
.sound_error(sender
:get_player_name())
415 easyvend
.set_formspec(pos
, sender
)
417 elseif ( number == nil or number < 1 or number > maxnumber
) then
418 if maxnumber
> 1 then
419 meta
:set_string("message", string.format("Invalid item count; must be between 1 and %d!", maxnumber
))
421 meta
:set_string("message", "Invalid item count; must be exactly 1!")
423 meta
:set_int("number", oldnumber
)
424 easyvend
.sound_error(sender
:get_player_name())
425 easyvend
.set_formspec(pos
, sender
)
427 elseif ( cost
== nil or cost
< 1 or cost
> maxcost
) then
429 meta
:set_string("message", string.format("Invalid cost; must be between 1 and %d!", maxcost
))
431 meta
:set_string("message", "Invalid cost; must be exactly 1!")
433 meta
:set_int("cost", oldcost
)
434 easyvend
.sound_error(sender
:get_player_name())
435 easyvend
.set_formspec(pos
, sender
)
438 meta
:set_int("number", number)
439 meta
:set_int("cost", cost
)
440 itemname
=itemstack
:get_name()
441 meta
:set_string("itemname", itemname
)
442 meta
:set_int("configmode", 0)
444 local change
= easyvend
.machine_check(pos
, node
)
446 if itemname
== currency
and number == cost
and cost
<= cost_stack_max
then
447 meta
:set_string("message", "Configuration successful. I am feeling funny.")
448 meta
:set_int("joketimer", joketimer_start
)
449 meta
:set_int("joke_id", easyvend
.assign_joke(buysell
))
451 meta
:set_string("message", "Configuration successful.")
455 if (node
.name
== "easyvend:vendor_on" or node
.name
== "easyvend:depositor_on") then
456 easyvend
.sound_setup(pos
)
457 meta
:set_string("status", "Ready.")
459 easyvend
.sound_disable(pos
)
462 easyvend
.machine_check(pos
, node
)
465 easyvend
.make_infotext
= function(nodename
, owner
, cost
, number, itemstring
)
466 local iname
= minetest
.registered_items
[itemstring
].description
467 if iname
== nil then iname
= itemstring
end
469 local printitem
, printcost
473 printitem
= string.format("%d×%s", number, iname
)
476 printcost
= currency_desc
478 printcost
= string.format("%d×%s", cost
, currency_desc
)
480 if nodename
== "easyvend:vendor" or nodename
== "easyvend:vendor_on" then
481 d
= string.format("Vending machine (owned by %s)\nSelling: %s\nPrice: %s", owner
, printitem
, printcost
)
482 elseif nodename
== "easyvend:depositor" or nodename
== "easyvend:depositor_on" then
483 d
= string.format("Depositing machine (owned by %s)\nBuying: %s\nPayment: %s", owner
, printitem
, printcost
)
488 easyvend
.on_receive_fields_buysell
= function(pos
, formname
, fields
, sender
)
489 local sendername
= sender
:get_player_name()
490 local meta
= minetest
.get_meta(pos
)
492 if not fields
.buysell
then
496 local node
= minetest
.get_node(pos
)
497 local number = meta
:get_int("number")
498 local cost
= meta
:get_int("cost")
499 local itemname
=meta
:get_string("itemname")
500 local item
=meta
:get_inventory():get_stack("item", 1)
501 local check_wear
= meta
:get_int("wear") == 0 and minetest
.registered_tools
[itemname
] ~= nil
503 local buysell
= easyvend
.buysell(node
.name
)
505 local number_stack_max
= item
:get_stack_max()
506 local maxnumber
= number_stack_max
* slots_max
507 if ( number == nil or number < 1 or number > maxnumber
) or
508 ( cost
== nil or cost
< 1 or cost
> maxcost
) or
509 ( itemname
== nil or itemname
=="") then
510 meta
:set_string("status", "Invalid item count or price!")
511 easyvend
.machine_disable(pos
, node
, sendername
)
516 local chest
= minetest
.get_node({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
517 local chestdef
= registered_chests
[chest
.name
]
518 if chestdef
and sender
and sender
:is_player() then
519 local chest_meta
= minetest
.get_meta({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
520 local chest_inv
= chest_meta
:get_inventory()
521 local player_inv
= sender
:get_inventory()
522 if ( chest_meta
:get_string(chestdef
.meta_owner
) == meta
:get_string("owner") and chest_inv
~= nil and player_inv
~= nil ) then
524 local stack
= {name
=itemname
, count
=number, wear
=0, metadata
=""}
525 local price
= {name
=currency
, count
=cost
, wear
=0, metadata
=""}
526 local chest_has
, player_has
, chest_free
, player_free
, chest_out
, player_out
528 if buysell
== "sell" then
529 chest_has
, chest_out
= easyvend
.check_and_get_items(chest_inv
, "main", stack
, check_wear
)
530 player_has
, player_out
= easyvend
.check_and_get_items(player_inv
, "main", price
, check_wear
)
531 chest_free
= chest_inv
:room_for_item("main", price
)
532 player_free
= player_inv
:room_for_item("main", stack
)
533 if chest_has
and player_has
and chest_free
and player_free
then
534 if cost
<= cost_stack_max
and number <= number_stack_max
then
535 easyvend
.machine_enable(pos
, node
)
536 player_inv
:remove_item("main", price
)
538 chest_inv
:set_stack("main", chest_out
[1].id
, "")
539 player_inv
:add_item("main", chest_out
[1].item
)
541 stack
= chest_inv
:remove_item("main", stack
)
542 player_inv
:add_item("main", stack
)
544 chest_inv
:add_item("main", price
)
545 meta
:set_string("status", "Ready.")
546 if itemname
== currency
and number == cost
and cost
<= cost_stack_max
then
547 meta
:set_string("message", easyvend
.get_joke(buysell
, meta
:get_int("joke_id")))
548 meta
:set_int("joketimer", joketimer_start
)
550 meta
:set_string("message", "Item bought.")
552 easyvend
.sound_vend(pos
)
554 -- Large item counts (multiple stacks)
555 local coststacks
= math
.modf(cost
/ cost_stack_max
)
556 local costremainder
= math
.fmod(cost
, cost_stack_max
)
557 local numberstacks
= math
.modf(number / number_stack_max
)
558 local numberremainder
= math
.fmod(number, number_stack_max
)
559 local numberfree
= numberstacks
560 local costfree
= coststacks
561 if numberremainder
> 0 then numberfree
= numberfree
+ 1 end
562 if costremainder
> 0 then costfree
= costfree
+ 1 end
563 if easyvend
.free_slots(player_inv
, "main") < numberfree
then
564 if numberfree
> 1 then
565 msg
= string.format("No room in your inventory (%d empty slots required)!", numberfree
)
567 msg
= "No room in your inventory!"
569 meta
:set_string("message", msg
)
570 elseif easyvend
.free_slots(chest_inv
, "main") < costfree
then
571 meta
:set_string("status", "No room in the machine’s storage!")
572 easyvend
.machine_disable(pos
, node
, sendername
)
574 -- Remember items for transfer
575 local cheststacks
= {}
576 easyvend
.machine_enable(pos
, node
)
577 for i
=1, coststacks
do
578 price
.count
= cost_stack_max
579 player_inv
:remove_item("main", price
)
581 if costremainder
> 0 then
582 price
.count
= costremainder
583 player_inv
:remove_item("main", price
)
586 for o
=1,#chest_out
do
587 chest_inv
:set_stack("main", chest_out
[o
].id
, "")
590 for i
=1, numberstacks
do
591 stack
.count
= number_stack_max
592 table.insert(cheststacks
, chest_inv
:remove_item("main", stack
))
595 if numberremainder
> 0 then
596 stack
.count
= numberremainder
597 table.insert(cheststacks
, chest_inv
:remove_item("main", stack
))
599 for i
=1, coststacks
do
600 price
.count
= cost_stack_max
601 chest_inv
:add_item("main", price
)
603 if costremainder
> 0 then
604 price
.count
= costremainder
605 chest_inv
:add_item("main", price
)
608 for o
=1,#chest_out
do
609 player_inv
:add_item("main", chest_out
[o
].item
)
612 for i
=1,#cheststacks
do
613 player_inv
:add_item("main", cheststacks
[i
])
616 meta
:set_string("message", "Item bought.")
617 easyvend
.sound_vend(pos
)
620 elseif chest_has
and player_has
then
621 if not player_free
then
622 msg
= "No room in your inventory!"
623 meta
:set_string("message", msg
)
624 easyvend
.sound_error(sendername
)
625 elseif not chest_free
then
626 msg
= "No room in the machine’s storage!"
627 meta
:set_string("status", msg
)
628 easyvend
.machine_disable(pos
, node
, sendername
)
631 if not chest_has
then
632 msg
= "The vending machine has insufficient materials!"
633 meta
:set_string("status", msg
)
634 easyvend
.machine_disable(pos
, node
, sendername
)
635 elseif not player_has
then
636 msg
= "You can’t afford this item!"
637 meta
:set_string("message", msg
)
638 easyvend
.sound_error(sendername
)
642 chest_has
, chest_out
= easyvend
.check_and_get_items(chest_inv
, "main", price
, check_wear
)
643 player_has
, player_out
= easyvend
.check_and_get_items(player_inv
, "main", stack
, check_wear
)
644 chest_free
= chest_inv
:room_for_item("main", stack
)
645 player_free
= player_inv
:room_for_item("main", price
)
646 if chest_has
and player_has
and chest_free
and player_free
then
647 if cost
<= cost_stack_max
and number <= number_stack_max
then
648 easyvend
.machine_enable(pos
, node
)
650 player_inv
:set_stack("main", player_out
[1].id
, "")
651 chest_inv
:add_item("main", player_out
[1].item
)
653 stack
= player_inv
:remove_item("main", stack
)
654 chest_inv
:add_item("main", stack
)
656 chest_inv
:remove_item("main", price
)
657 player_inv
:add_item("main", price
)
658 meta
:set_string("status", "Ready.")
659 if itemname
== currency
and number == cost
and cost
<= cost_stack_max
then
660 meta
:set_string("message", easyvend
.get_joke(buysell
, meta
:get_int("joke_id")))
661 meta
:set_int("joketimer", joketimer_start
)
663 meta
:set_string("message", "Item sold.")
665 easyvend
.sound_deposit(pos
)
667 -- Large item counts (multiple stacks)
668 local coststacks
= math
.modf(cost
/ cost_stack_max
)
669 local costremainder
= math
.fmod(cost
, cost_stack_max
)
670 local numberstacks
= math
.modf(number / number_stack_max
)
671 local numberremainder
= math
.fmod(number, number_stack_max
)
672 local numberfree
= numberstacks
673 local costfree
= coststacks
674 if numberremainder
> 0 then numberfree
= numberfree
+ 1 end
675 if costremainder
> 0 then costfree
= costfree
+ 1 end
676 if easyvend
.free_slots(player_inv
, "main") < costfree
then
678 msg
= string.format("No room in your inventory (%d empty slots required)!", costfree
)
680 msg
= "No room in your inventory!"
682 meta
:set_string("status", msg
)
683 easyvend
.sound_error(sendername
)
684 elseif easyvend
.free_slots(chest_inv
, "main") < numberfree
then
685 easyvend
.machine_disable(pos
, node
, sendername
)
687 easyvend
.machine_enable(pos
, node
)
688 -- Remember removed items for transfer
689 local playerstacks
= {}
690 for i
=1, coststacks
do
691 price
.count
= cost_stack_max
692 chest_inv
:remove_item("main", price
)
694 if costremainder
> 0 then
695 price
.count
= costremainder
696 chest_inv
:remove_item("main", price
)
699 for o
=1,#player_out
do
700 player_inv
:set_stack("main", player_out
[o
].id
, "")
703 for i
=1, numberstacks
do
704 stack
.count
= number_stack_max
705 table.insert(playerstacks
, player_inv
:remove_item("main", stack
))
708 if numberremainder
> 0 then
709 stack
.count
= numberremainder
710 table.insert(playerstacks
, player_inv
:remove_item("main", stack
))
712 for i
=1, coststacks
do
713 price
.count
= cost_stack_max
714 player_inv
:add_item("main", price
)
716 if costremainder
> 0 then
717 price
.count
= costremainder
718 player_inv
:add_item("main", price
)
721 for o
=1,#player_out
do
722 chest_inv
:add_item("main", player_out
[o
].item
)
725 for i
=1,#playerstacks
do
726 chest_inv
:add_item("main", playerstacks
[i
])
729 meta
:set_string("message", "Item sold.")
730 easyvend
.sound_deposit(pos
)
733 elseif chest_has
and player_has
then
734 if not player_free
then
735 msg
= "No room in your inventory!"
736 meta
:set_string("message", msg
)
737 easyvend
.sound_error(sendername
)
738 elseif not chest_free
then
739 msg
= "No room in the machine’s storage!"
740 meta
:set_string("status", msg
)
741 easyvend
.machine_disable(pos
, node
, sendername
)
744 if not player_has
then
745 msg
= "You have insufficient materials!"
746 meta
:set_string("message", msg
)
747 easyvend
.sound_error(sendername
)
748 elseif not chest_has
then
749 msg
= "The depositing machine is out of money!"
750 meta
:set_string("status", msg
)
751 easyvend
.machine_disable(pos
, node
, sendername
)
756 meta
:set_string("status", "Storage can’t be accessed because it is owned by a different person!")
757 easyvend
.machine_disable(pos
, node
, sendername
)
760 if sender
and sender
:is_player() then
761 meta
:set_string("status", "No storage; machine needs a locked chest below it.")
762 easyvend
.machine_disable(pos
, node
, sendername
)
766 easyvend
.set_formspec(pos
, sender
)
770 easyvend
.after_place_node
= function(pos
, placer
)
771 local node
= minetest
.get_node(pos
)
772 local meta
= minetest
.get_meta(pos
)
773 local inv
= meta
:get_inventory()
774 local player_name
= placer
:get_player_name()
775 inv
:set_size("item", 1)
776 inv
:set_size("gold", 1)
778 inv
:set_stack( "gold", 1, currency
)
781 if node
.name
== "easyvend:vendor" then
782 d
= string.format("New vending machine (owned by %s)", player_name
)
783 meta
:set_int("wear", 1)
784 elseif node
.name
== "easyvend:depositor" then
785 d
= string.format("New depositing machine (owned by %s)", player_name
)
786 meta
:set_int("wear", 0)
788 meta
:set_string("infotext", d
)
789 local chest
= minetest
.get_node({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
790 if registered_chests
[chest
.name
] then
791 meta
:set_string("status", "Awaiting configuration by owner.")
793 meta
:set_string("status", "No storage; machine needs a locked chest below it.")
795 meta
:set_string("message", "Welcome! Please prepare the machine.")
796 meta
:set_int("number", 1)
797 meta
:set_int("cost", 1)
798 meta
:set_int("configmode", 1)
799 meta
:set_int("joketimer", -1)
800 meta
:set_int("joke_id", 1)
801 meta
:set_string("itemname", "")
803 meta
:set_string("owner", player_name
or "")
805 easyvend
.set_formspec(pos
, placer
)
808 easyvend
.can_dig
= function(pos
, player
)
809 local meta
= minetest
.get_meta(pos
)
810 local name
= player
:get_player_name()
811 -- Owner can always dig shop
812 if meta
:get_string("owner") == name
then
815 local chest
= minetest
.get_node({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
})
816 local meta_chest
= minetest
.get_meta({x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
});
817 if registered_chests
[chest
.name
] then
818 if player
and player
:is_player() then
819 local owner_chest
= meta_chest
:get_string(registered_chests
[chest
.name
].meta_owner
)
820 if name
== owner_chest
then
821 return true --chest owner can also dig shop
826 return true --if no chest, enyone can dig this shop
830 easyvend
.on_receive_fields
= function(pos
, formname
, fields
, sender
)
831 local meta
= minetest
.get_meta(pos
)
832 local node
= minetest
.get_node(pos
)
833 local owner
= meta
:get_string("owner")
834 local sendername
= sender
:get_player_name(sender
)
836 if fields
.config
or fields
.save
or fields
.usermode
then
837 if sender
:get_player_name() == owner
then
838 easyvend
.on_receive_fields_config(pos
, formname
, fields
, sender
)
840 meta
:set_string("message", "Only owner may change the configuration.")
841 easyvend
.sound_error(sendername
)
842 easyvend
.set_formspec(pos
, sender
)
845 elseif fields
.wear
~= nil then
846 if sender
:get_player_name() == owner
then
847 if fields
.wear
== "true" then
848 if easyvend
.buysell(node
.name
) == "buy" then
849 meta
:set_string("message", "Used tools are now accepted.")
851 meta
:set_string("message", "Used tools are now for sale.")
853 meta
:set_int("wear", 1)
854 elseif fields
.wear
== "false" then
855 if easyvend
.buysell(node
.name
) == "buy" then
856 meta
:set_string("message", "Used tools are now rejected.")
858 meta
:set_string("message", "Used tools won’t be sold anymore.")
860 meta
:set_int("wear", 0)
862 easyvend
.set_formspec(pos
, sender
)
865 meta
:set_string("message", "Only owner may change the configuration.")
866 easyvend
.sound_error(sendername
)
867 easyvend
.set_formspec(pos
, sender
)
870 elseif fields
.buysell
then
871 easyvend
.on_receive_fields_buysell(pos
, formname
, fields
, sender
)
875 -- Jokes: Appear when machine exchanges currency for currency at equal rate
878 local jokes_vendor
= {
879 "Thank you. You have made a vending machine very happy.",
880 "Humans have a strange sense of humor.",
881 "Let’s get this over with …",
884 "Do you realize what you’ve just bought?",
887 local jokes_depositor
= {
888 "Thank you, the money started to smell inside.",
889 "Money doesn’t grow on trees, you know?",
891 "Well, that was an awkward exchange.",
892 "Are you having fun?",
893 "Is this really trading?",
896 easyvend
.assign_joke
= function(buysell
)
898 if buysell
== "sell" then
900 elseif buysell
== "buy" then
901 jokes
= jokes_depositor
903 local r
= math
.random(1,#jokes
)
907 easyvend
.get_joke
= function(buysell
, id
)
908 if buysell
== nil or id
== nil then
909 -- Fallback message (should never happen)
910 return "Items exchanged."
912 if buysell
== "sell" then
913 joke
= jokes_vendor
[id
]
914 if joke
== nil then joke
= jokes_vendor
[1] end
915 elseif buysell
== "buy" then
916 joke
= jokes_depositor
[id
]
917 if joke
== nil then joke
= jokes_depositor
[1] end
922 easyvend
.sound_error
= function(playername
)
923 minetest
.sound_play("easyvend_error", {to_player
= playername
, gain
= 0.25})
926 easyvend
.sound_setup
= function(pos
)
927 minetest
.sound_play("easyvend_activate", {pos
= pos
, gain
= 0.5, max_hear_distance
= 12,})
930 easyvend
.sound_disable
= function(pos
)
931 minetest
.sound_play("easyvend_disable", {pos
= pos
, gain
= 0.9, max_hear_distance
= 12,})
934 easyvend
.sound_vend
= function(pos
)
935 minetest
.sound_play("easyvend_vend", {pos
= pos
, gain
= 0.4, max_hear_distance
= 5,})
938 easyvend
.sound_deposit
= function(pos
)
939 minetest
.sound_play("easyvend_deposit", {pos
= pos
, gain
= 0.4, max_hear_distance
= 5,})
942 easyvend
.allow_metadata_inventory_put
= function(pos
, listname
, index
, stack
, player
)
943 if listname
=="item" then
944 local meta
= minetest
.get_meta(pos
);
945 local owner
= meta
:get_string("owner")
946 local name
= player
:get_player_name()
947 if name
== owner
then
948 local inv
= meta
:get_inventory()
950 inv
:set_stack( "item", 1, nil )
952 inv
:set_stack( "item", 1, stack
:get_name() )
959 easyvend
.allow_metadata_inventory_take
= function(pos
, listname
, index
, stack
, player
)
963 easyvend
.allow_metadata_inventory_move
= function(pos
, from_list
, from_index
, to_list
, to_index
, count
, player
)
967 minetest
.register_abm({
968 nodenames
= {"easyvend:vendor", "easyvend:vendor_on", "easyvend:depositor", "easyvend:depositor_on"},
972 action
= function(pos
, node
, active_object_count
, active_object_count_wider
)
973 easyvend
.machine_check(pos
, node
)