easyvend.lua 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. if not minetest.global_exists("easyvend") then easyvend = {} end
  2. easyvend.modpath = minetest.get_modpath("easyvend")
  3. -- Localize for performance.
  4. local math_floor = math.floor
  5. local traversable_node_types = easyvend.traversable_node_types
  6. local registered_chests = easyvend.registered_chests
  7. local currency_types = {}
  8. local initial_currency = 1
  9. for k, v in ipairs(currency.note_names) do
  10. table.insert(currency_types, v)
  11. end
  12. -- Maximum price that can be configured on a vendor or depositor.
  13. local maxcost = 1000000
  14. local slots_max = 30
  15. -- Allow for other mods to register custom chests
  16. easyvend.register_chest = function(node_name, inv_list, meta_owner)
  17. easyvend.registered_chests[node_name] = { inv_list = inv_list, meta_owner = meta_owner }
  18. easyvend.traversable_node_types[node_name] = true
  19. end
  20. -- Partly a wrapper around contains_item, but does special treatment if the item
  21. -- is a tool. Basically checks whether the items exist in the supplied inventory
  22. -- list. If check_wear is true, only counts items without wear.
  23. easyvend.check_and_get_items = function(inventory, listname, itemtable, check_wear)
  24. local itemstring = itemtable.name
  25. local minimum = itemtable.count
  26. if check_wear == nil then check_wear = false end
  27. local get_items = {}
  28. -- Tool workaround
  29. if minetest.registered_tools[itemstring] ~= nil then
  30. local count = 0
  31. for i=1,inventory:get_size(listname) do
  32. local stack = inventory:get_stack(listname, i)
  33. if stack:get_name() == itemstring then
  34. if not check_wear or stack:get_wear() == 0 then
  35. count = count + 1
  36. table.insert(get_items, {id=i, item=stack})
  37. if count >= minimum then
  38. return true, get_items
  39. end
  40. end
  41. end
  42. end
  43. return false
  44. else
  45. -- Normal Minetest check
  46. return inventory:contains_item(listname, ItemStack(itemtable))
  47. end
  48. end
  49. easyvend.free_slots = function(inv, listname)
  50. local size = inv:get_size(listname)
  51. local free = 0
  52. for i=1,size do
  53. local stack = inv:get_stack(listname, i)
  54. if stack:is_empty() then
  55. free = free + 1
  56. end
  57. end
  58. return free
  59. end
  60. easyvend.buysell = function(nodename)
  61. local buysell = nil
  62. if ( nodename == "easyvend:depositor" or nodename == "easyvend:depositor_on" ) then
  63. buysell = "buy"
  64. elseif ( nodename == "easyvend:vendor" or nodename == "easyvend:vendor_on" ) then
  65. buysell = "sell"
  66. end
  67. return buysell
  68. end
  69. easyvend.is_active = function(nodename)
  70. if ( nodename == "easyvend:depositor_on" or nodename == "easyvend:vendor_on" ) then
  71. return true
  72. elseif ( nodename == "easyvend:depositor" or nodename == "easyvend:vendor" ) then
  73. return false
  74. else
  75. return nil
  76. end
  77. end
  78. easyvend.set_formspec = function(pos)
  79. local meta = minetest.get_meta(pos)
  80. local node = minetest.get_node(pos)
  81. local description = utility.get_short_desc(minetest.reg_ns_nodes[node.name].description);
  82. local number = meta:get_int("number")
  83. local cost = meta:get_int("cost")
  84. local itemname = meta:get_string("itemname")
  85. local bg = ""
  86. local configmode = meta:get_int("configmode") == 1
  87. if minetest.get_modpath("default") then
  88. bg = default.formspec.get_form_colors() .. default.formspec.get_form_image() .. default.formspec.get_slot_colors()
  89. end
  90. local numbertext, costtext, buysellbuttontext
  91. local itemcounttooltip = "Item count"
  92. local buysell = easyvend.buysell(node.name)
  93. if buysell == "sell" then
  94. numbertext = "Offered Item"
  95. costtext = "Price"
  96. buysellbuttontext = "Buy"
  97. elseif buysell == "buy" then
  98. numbertext = "Requested Item"
  99. costtext = "Payment"
  100. buysellbuttontext = "Sell"
  101. else
  102. return
  103. end
  104. local status = meta:get_string("status")
  105. if status == "" then status = "Unknown." end
  106. local message = meta:get_string("message")
  107. if message == "" then message = "No message." end
  108. local status_image
  109. if node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on" then
  110. status_image = "easyvend_status_on.png"
  111. else
  112. status_image = "easyvend_status_off.png"
  113. end
  114. -- TODO: Expose number of items in stock
  115. local formspec = "size[8,7.3;]"
  116. .. bg
  117. .."label[3,-0.2;" .. minetest.formspec_escape(description) .. "]"
  118. .."image[7.5,0.2;0.5,1;" .. status_image .. "]"
  119. .."textarea[2.8,0.2;5.1,2;;Status: " .. minetest.formspec_escape(status) .. ";]"
  120. .."textarea[2.8,1.3;5.6,2;;Message: " .. minetest.formspec_escape(message) .. ";]"
  121. .."label[0,-0.15;"..numbertext.."]"
  122. .."label[0,1.2;"..costtext.."]"
  123. .."list[current_player;main;0,3.5;8,4;]"
  124. local machine_currency = meta:get_string("machine_currency")
  125. if configmode then
  126. local wear = "false"
  127. if meta:get_int("wear") == 1 then wear = "true" end
  128. formspec = formspec
  129. .."item_image_button[0,1.65;1,1;" .. machine_currency .. ";easyvend_currency_image;]"
  130. .."list[context;item;0,0.35;1,1;]"
  131. .."listring[current_player;main]"
  132. .."listring[context;item]"
  133. .."field[1.3,0.65;1.5,1;number;;" .. number .. "]"
  134. .."tooltip[number;"..itemcounttooltip.."]"
  135. .."field[1.3,1.95;1.5,1;cost;;" .. cost .. "]"
  136. .."tooltip[cost;"..itemcounttooltip.."]"
  137. .."button[6,2.8;2,0.5;save;Confirm]"
  138. .."tooltip[save;Confirm configuration and activate machine (only for owner)]"
  139. local weartext, weartooltip
  140. if buysell == "buy" then
  141. weartext = "Buy worn tools"
  142. weartooltip = "If disabled, only tools in perfect condition will be bought from sellers (only settable by owner)"
  143. else
  144. weartext = "Sell worn tools"
  145. weartooltip = "If disabled, only tools in perfect condition will be sold (only settable by owner)"
  146. end
  147. if minetest.registered_tools[itemname] ~= nil then
  148. formspec = formspec .."checkbox[2,2.4;wear;"..minetest.formspec_escape(weartext)..";"..wear.."]"
  149. .."tooltip[wear;"..minetest.formspec_escape(weartooltip).."]"
  150. end
  151. else
  152. formspec = formspec
  153. .."item_image_button[0,1.65;1,1;" .. machine_currency .. ";easyvend_currency_image;]"
  154. .."item_image_button[0,0.35;1,1;"..itemname..";item_image;]"
  155. .."label[1,1.85;×" .. cost .. "]"
  156. .."label[1,0.55;×" .. number .. "]"
  157. .."button[6,2.8;2,0.5;config;Configure]"
  158. if buysell == "sell" then
  159. formspec = formspec .. "tooltip[config;Configure offered items and price (only for owner)]"
  160. else
  161. formspec = formspec .. "tooltip[config;Configure requested items and payment (only for owner)]"
  162. end
  163. formspec = formspec .."button[0,2.8;2,0.5;buysell;"..buysellbuttontext.."]"
  164. if minetest.registered_tools[itemname] ~= nil then
  165. local weartext
  166. if meta:get_int("wear") == 0 then
  167. if buysell == "buy" then
  168. weartext = "Only intact tools are bought."
  169. else
  170. weartext = "Only intact tools are sold."
  171. end
  172. else
  173. if buysell == "sell" then
  174. weartext = "Warning: Might sell worn tools."
  175. else
  176. weartext = "Worn tools are bought, too."
  177. end
  178. end
  179. if weartext ~= nil then
  180. formspec = formspec .."textarea[2.3,2.6;3,1;;"..minetest.formspec_escape(weartext)..";]"
  181. end
  182. end
  183. end
  184. meta:set_string("formspec", formspec)
  185. end
  186. easyvend.machine_disable = function(pos, node, playername)
  187. if node.name == "easyvend:vendor_on" then
  188. easyvend.sound_disable(pos)
  189. minetest.swap_node(pos, {name="easyvend:vendor", param2 = node.param2})
  190. return true
  191. elseif node.name == "easyvend:depositor_on" then
  192. easyvend.sound_disable(pos)
  193. minetest.swap_node(pos, {name="easyvend:depositor", param2 = node.param2})
  194. return true
  195. else
  196. if playername ~= nil then
  197. easyvend.sound_error(playername)
  198. end
  199. return false
  200. end
  201. end
  202. easyvend.machine_enable = function(pos, node)
  203. if node.name == "easyvend:vendor" then
  204. easyvend.sound_setup(pos)
  205. minetest.swap_node(pos, {name="easyvend:vendor_on", param2 = node.param2})
  206. return true
  207. elseif node.name == "easyvend:depositor" then
  208. easyvend.sound_setup(pos)
  209. minetest.swap_node(pos, {name="easyvend:depositor_on", param2 = node.param2})
  210. return true
  211. else
  212. return false
  213. end
  214. end
  215. easyvend.upgrade_currency = function(pos, meta, old_currency, old_cost)
  216. if old_currency == "default:gold_ingot" then
  217. -- Upgrade gold to currency at 1 to 25. This is a fixed exchange rate.
  218. meta:set_string("machine_currency", "currency:minegeld_5")
  219. meta:set_int("cost", math_floor((old_cost * 25) / 5))
  220. return ("currency:minegeld_5"), math_floor((old_cost * 25) / 5)
  221. end
  222. return old_currency, old_cost
  223. end
  224. easyvend.machine_check = function(pos, node)
  225. local active = true
  226. local status = "Ready."
  227. local meta = minetest.get_meta(pos)
  228. local machine_owner = meta:get_string("owner")
  229. local itemname = meta:get_string("itemname")
  230. local number = meta:get_int("number")
  231. local check_wear = meta:get_int("wear") == 0
  232. local inv = meta:get_inventory()
  233. local itemstack = inv:get_stack("item", 1)
  234. local buysell = easyvend.buysell(node.name)
  235. local machine_currency = meta:get_string("machine_currency")
  236. local cost = meta:get_int("cost")
  237. -- If the machine uses a depreciated currency, this will upgrade it using a fixed exchange rate.
  238. machine_currency, cost = easyvend.upgrade_currency(pos, meta, machine_currency, cost)
  239. local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
  240. if buysell == "sell" then
  241. -- Vending machine.
  242. chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
  243. chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, machine_currency, check_wear, cost, false)
  244. else
  245. -- Depositing machine.
  246. chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, machine_currency, check_wear, cost, true)
  247. chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
  248. end
  249. if chest_pos_remove and chest_pos_add then
  250. local rchest, rchestdef, rchest_meta, rchest_inv
  251. rchest = minetest.get_node(chest_pos_remove)
  252. rchestdef = registered_chests[rchest.name]
  253. rchest_meta = minetest.get_meta(chest_pos_remove)
  254. rchest_inv = rchest_meta:get_inventory()
  255. local checkstack, checkitem
  256. if buysell == "buy" then
  257. checkitem = machine_currency
  258. else
  259. checkitem = itemname
  260. end
  261. local stock = 0
  262. -- Count stock
  263. -- FIXME: Ignore tools with bad wear level
  264. for i=1,rchest_inv:get_size(rchestdef.inv_list) do
  265. checkstack = rchest_inv:get_stack(rchestdef.inv_list, i)
  266. if checkstack:get_name() == checkitem then
  267. stock = stock + checkstack:get_count()
  268. end
  269. end
  270. meta:set_int("stock", stock)
  271. if not itemstack:is_empty() then
  272. local number_stack_max = itemstack:get_stack_max()
  273. local maxnumber = number_stack_max * slots_max
  274. if not(number >= 1 and number <= maxnumber and cost >= 1 and cost <= maxcost) then
  275. active = false
  276. if buysell == "sell" then
  277. status = "Invalid item count or price."
  278. else
  279. status = "Invalid item count or payment."
  280. end
  281. end
  282. else
  283. active = false
  284. status = "Awaiting configuration by owner."
  285. end
  286. else
  287. active = false
  288. meta:set_int("stock", 0)
  289. if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
  290. status = "No storage; machine needs to be connected with a locked chest."
  291. elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
  292. status = "Storage can’t be accessed because it is owned by a different person!"
  293. elseif chest_error_remove == "no_stock" then
  294. if buysell == "sell" then
  295. status = "The vending machine has insufficient materials!"
  296. else
  297. status = "The depositing machine is out of money!"
  298. end
  299. elseif chest_error_add == "no_space" then
  300. status = "No room in the machine’s storage!"
  301. else
  302. status = "Unknown error!"
  303. end
  304. end
  305. if meta:get_int("configmode") == 1 then
  306. active = false
  307. status = "Awaiting configuration by owner."
  308. end
  309. if currency.is_currency(itemname) then
  310. status = "Cannot treat currency as a directly saleable item!"
  311. active = false
  312. end
  313. -- If the currency type is depreciated, then this warning overrides all others.
  314. if not currency.is_currency(machine_currency) then
  315. status = "Machine uses a depreciated currency standard!"
  316. active = false
  317. end
  318. meta:set_string("status", status)
  319. itemname=itemstack:get_name()
  320. meta:set_string("itemname", itemname)
  321. -- Inform remote market system of any changes.
  322. depositor.update_info(pos, machine_owner, itemname, number, cost, machine_currency, buysell, active)
  323. local change
  324. if node.name == "easyvend:vendor" or node.name == "easyvend:depositor" then
  325. if active then change = easyvend.machine_enable(pos, node) end
  326. elseif node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on" then
  327. if not active then change = easyvend.machine_disable(pos, node) end
  328. end
  329. local current_node = minetest.get_node(pos)
  330. meta:set_string("infotext", easyvend.make_infotext(pos, current_node.name, machine_owner, cost, number, itemname))
  331. easyvend.set_formspec(pos)
  332. return change
  333. end
  334. easyvend.on_receive_fields_config = function(pos, formname, fields, sender)
  335. local node = minetest.get_node(pos)
  336. local meta = minetest.get_meta(pos)
  337. local inv_self = meta:get_inventory()
  338. local itemstack = inv_self:get_stack("item",1)
  339. local buysell = easyvend.buysell(node.name)
  340. if fields.config then
  341. meta:set_int("configmode", 1)
  342. local was_active = easyvend.is_active(node.name)
  343. if was_active then
  344. meta:set_string("message", "Configuration mode activated; machine disabled.")
  345. else
  346. meta:set_string("message", "Configuration mode activated.")
  347. end
  348. easyvend.machine_check(pos, node)
  349. return
  350. end
  351. if not fields.save then
  352. return
  353. end
  354. local number = fields.number
  355. local cost = fields.cost
  356. number = tonumber(number)
  357. cost = tonumber(cost)
  358. local itemname=""
  359. local number_stack_max = 0
  360. if itemstack and not itemstack:is_empty() then
  361. itemname = itemstack:get_name()
  362. number_stack_max = itemstack:get_stack_max()
  363. end
  364. local oldnumber = meta:get_int("number")
  365. local oldcost = meta:get_int("cost")
  366. local maxnumber = number_stack_max * slots_max
  367. if ( itemstack == nil or itemstack:is_empty() ) then
  368. meta:set_string("status", "Awaiting configuration by owner.")
  369. meta:set_string("message", "No item specified.")
  370. easyvend.sound_error(sender:get_player_name())
  371. easyvend.set_formspec(pos)
  372. return
  373. elseif ( number == nil or number < 1 or number > maxnumber ) then
  374. if maxnumber > 1 then
  375. meta:set_string("message", string.format("Invalid item count; must be between 1 and %d!", maxnumber))
  376. else
  377. meta:set_string("message", "Invalid item count; must be exactly 1!")
  378. end
  379. meta:set_int("number", oldnumber)
  380. easyvend.sound_error(sender:get_player_name())
  381. easyvend.set_formspec(pos)
  382. return
  383. elseif ( cost == nil or cost < 1 or cost > maxcost ) then
  384. if maxcost > 1 then
  385. meta:set_string("message", string.format("Invalid cost; must be between 1 and %d!", maxcost))
  386. else
  387. meta:set_string("message", "Invalid cost; must be exactly 1!")
  388. end
  389. meta:set_int("cost", oldcost)
  390. easyvend.sound_error(sender:get_player_name())
  391. easyvend.set_formspec(pos)
  392. return
  393. end
  394. meta:set_int("number", number)
  395. meta:set_int("cost", cost)
  396. meta:set_string("itemname", itemname)
  397. meta:set_int("configmode", 0)
  398. meta:set_string("message", "Configuration successful.")
  399. local change = easyvend.machine_check(pos, node)
  400. if not change then
  401. if (node.name == "easyvend:vendor_on" or node.name == "easyvend:depositor_on") then
  402. easyvend.sound_setup(pos)
  403. else
  404. easyvend.sound_disable(pos)
  405. end
  406. end
  407. end
  408. easyvend.make_infotext = function(pos, nodename, owner, cost, number, itemstring)
  409. local dname = rename.gpn(owner)
  410. local d = ""
  411. if itemstring == nil or itemstring == "" or number == 0 or cost == 0 then
  412. if easyvend.buysell(nodename) == "sell" then
  413. d = string.format("Inactive Vending Machine (Owned by <%s>!)", dname)
  414. else
  415. d = string.format("Inactive Depositing Machine (Owned by <%s>!)", dname)
  416. end
  417. return d
  418. end
  419. local iname = minetest.registered_items[itemstring].description
  420. if iname == nil then iname = itemstring end
  421. iname = utility.get_short_desc(iname)
  422. local printitem, printcost
  423. if number == 1 then
  424. printitem = iname
  425. else
  426. printitem = string.format("%d×%s", number, iname)
  427. end
  428. local meta = minetest.get_meta(pos)
  429. local machine_currency = meta:get_string("machine_currency")
  430. if currency.is_currency(machine_currency) then
  431. printcost = currency.get_stack_value(machine_currency, cost) .. " Minegeld"
  432. else
  433. printcost = "Depreciated Currency!"
  434. end
  435. if nodename == "easyvend:vendor_on" then
  436. d = string.format("Vending Machine (Owned by <%s>!)\nSelling: %s\nPrice: %s", dname, printitem, printcost)
  437. elseif nodename == "easyvend:vendor" then
  438. d = string.format("Inactive Vending Machine (Owned by <%s>!)\nSelling: %s\nPrice: %s", dname, printitem, printcost)
  439. elseif nodename == "easyvend:depositor_on" then
  440. d = string.format("Depositing Machine (Owned by <%s>!)\nBuying: %s\nPayment: %s", dname, printitem, printcost)
  441. elseif nodename == "easyvend:depositor" then
  442. d = string.format("Inactive Depositing Machine (Owned by <%s>!)\nBuying: %s\nPayment: %s", dname, printitem, printcost)
  443. end
  444. return d
  445. end
  446. easyvend.execute_trade = function(pos, sender, player_inv, pin, vendor_inv, iin, remote_tax)
  447. local sendername = sender:get_player_name()
  448. local meta = minetest.get_meta(pos)
  449. local node = minetest.get_node(pos)
  450. local number = meta:get_int("number")
  451. local cost = meta:get_int("cost")
  452. local itemname=meta:get_string("itemname")
  453. local item=meta:get_inventory():get_stack("item", 1)
  454. local check_wear = meta:get_int("wear") == 0 and minetest.registered_tools[itemname] ~= nil
  455. local buysell = easyvend.buysell(node.name)
  456. local number_stack_max = item:get_stack_max()
  457. local maxnumber = number_stack_max * slots_max
  458. if ( number == nil or number < 1 or number > maxnumber ) or
  459. ( cost == nil or cost < 1 or cost > maxcost ) or
  460. ( itemname == nil or itemname=="") then
  461. meta:set_string("status", "Invalid item count or price!")
  462. easyvend.machine_disable(pos, node, sendername)
  463. easyvend.set_formspec(pos)
  464. return
  465. end
  466. local machine_currency = meta:get_string("machine_currency")
  467. local machine_owner = meta:get_string("owner")
  468. -- Check currency.
  469. if not currency.is_currency(machine_currency) then
  470. easyvend.sound_error(sendername)
  471. minetest.chat_send_player(sendername, "# Server: Shop at " .. rc.pos_to_namestr(pos) .. " uses a depreciated currency, attempting to upgrade!")
  472. minetest.chat_send_player(sendername, "# Server: If this happens, try to use the shop again and it may work if nothing else is wrong.")
  473. easyvend.machine_check(pos, node)
  474. --meta:set_string("status", "Machine uses a depreciated currency standard!")
  475. --easyvend.machine_disable(pos, node, sendername)
  476. --easyvend.set_formspec(pos)
  477. return
  478. end
  479. -- Cannot sell or buy currency directly.
  480. if currency.is_currency(itemname) then
  481. meta:set_string("status", "Cannot treat currency as a directly saleable item!")
  482. easyvend.machine_disable(pos, node, sendername)
  483. easyvend.set_formspec(pos)
  484. return
  485. end
  486. local chest_pos_remove, chest_error_remove, chest_pos_add, chest_error_add
  487. if buysell == "sell" then
  488. -- Vending.
  489. chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, true)
  490. chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, machine_currency, check_wear, cost, false)
  491. else
  492. -- Depositing.
  493. chest_pos_remove, chest_error_remove = easyvend.find_connected_chest(machine_owner, pos, machine_currency, check_wear, cost, true)
  494. chest_pos_add, chest_error_add = easyvend.find_connected_chest(machine_owner, pos, itemname, check_wear, number, false)
  495. end
  496. if chest_pos_remove ~= nil and chest_pos_add ~= nil and sender and sender:is_player() then
  497. local rchest = minetest.get_node(chest_pos_remove)
  498. local rchestdef = registered_chests[rchest.name]
  499. local rchest_meta = minetest.get_meta(chest_pos_remove)
  500. local rchest_inv = rchest_meta:get_inventory()
  501. local achest = minetest.get_node(chest_pos_add)
  502. local achestdef = registered_chests[achest.name]
  503. local achest_meta = minetest.get_meta(chest_pos_add)
  504. local achest_inv = achest_meta:get_inventory()
  505. -- If passing a target inventory, redirect operations to it.
  506. -- This also indicates whether this is a remote trade executed via market.
  507. local vchest_inv = achest_inv
  508. local vchest_name = achestdef.inv_list
  509. if vendor_inv and iin then
  510. vchest_inv = vendor_inv
  511. vchest_name = iin
  512. end
  513. local stack = {name=itemname, count=number, wear=0, metadata=""}
  514. local price = currency.get_stack_value(machine_currency, cost)
  515. local chest_has, player_has, chest_free, player_free, chest_out, player_out
  516. local msg = ""
  517. if buysell == "sell" then
  518. -- Vending.
  519. local pricewithtax = price
  520. if vendor_inv then
  521. pricewithtax = currency.calculate_tax(price, 1, remote_tax)
  522. end
  523. chest_has, chest_out = easyvend.check_and_get_items(rchest_inv, rchestdef.inv_list, stack, check_wear)
  524. player_has = currency.has_cash_amount(player_inv, pin, pricewithtax)
  525. chest_free = currency.room_for_cash(vchest_inv, vchest_name, price)
  526. player_free = player_inv:room_for_item(pin, stack)
  527. if chest_has and player_has and chest_free and player_free then
  528. if number <= number_stack_max then
  529. easyvend.machine_enable(pos, node)
  530. -- Transfer items before transfering cash (this is because cash transfers can use up an unexpected number of free slots).
  531. if check_wear then
  532. rchest_inv:set_stack(rchestdef.inv_list, chest_out[1].id, "")
  533. player_inv:add_item(pin, chest_out[1].item)
  534. else
  535. stack = rchest_inv:remove_item(rchestdef.inv_list, stack)
  536. player_inv:add_item(pin, stack)
  537. end
  538. -- Transfer cash.
  539. currency.remove_cash(player_inv, pin, pricewithtax)
  540. currency.add_cash(vchest_inv, vchest_name, price)
  541. -- Deliver tax to the colonial government.
  542. currency.record_tax_income(pricewithtax - price)
  543. meta:set_string("message", "Item bought.")
  544. easyvend.sound_vend(pos)
  545. easyvend.machine_check(pos, node)
  546. local remote_str = ""
  547. if vendor_inv then
  548. remote_str = " remotely"
  549. end
  550. minetest.log("action", sendername .. remote_str .. " bought " .. number .. " " ..
  551. itemname .. " for " .. price .. " minegeld from vending machine owned by " ..
  552. machine_owner .. " at " .. minetest.pos_to_string(pos) .. ", tax was " .. (pricewithtax - price))
  553. else
  554. -- Large item counts (multiple stacks)
  555. local numberstacks = math.modf(number / number_stack_max)
  556. local numberremainder = math.fmod(number, number_stack_max)
  557. local numberfree = numberstacks
  558. if numberremainder > 0 then numberfree = numberfree + 1 end
  559. if not player_free and easyvend.free_slots(player_inv, pin) < numberfree then
  560. if numberfree > 1 then
  561. msg = string.format("No room in your inventory (%d empty slots required)!", numberfree)
  562. else
  563. msg = "No room in your inventory!"
  564. end
  565. meta:set_string("message", msg)
  566. elseif not chest_free and not currency.room_for_cash(vchest_inv, vchest_name, price) then
  567. meta:set_string("status", "No room in the machine’s storage!")
  568. easyvend.machine_disable(pos, node, sendername)
  569. else
  570. -- Remember items for transfer
  571. local cheststacks = {}
  572. easyvend.machine_enable(pos, node)
  573. -- Transfer items before transfering cash (this is because cash transfers can use up an unexpected number of free slots).
  574. if check_wear then
  575. for o=1, #chest_out do
  576. rchest_inv:set_stack(rchestdef.inv_list, chest_out[o].id, "")
  577. end
  578. else
  579. for i=1, numberstacks do
  580. stack.count = number_stack_max
  581. table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
  582. end
  583. end
  584. if numberremainder > 0 then
  585. stack.count = numberremainder
  586. table.insert(cheststacks, rchest_inv:remove_item(rchestdef.inv_list, stack))
  587. end
  588. if check_wear then
  589. for o=1, #chest_out do
  590. player_inv:add_item(pin, chest_out[o].item)
  591. end
  592. else
  593. for i=1, #cheststacks do
  594. player_inv:add_item(pin, cheststacks[i])
  595. end
  596. end
  597. -- Transfer money.
  598. currency.remove_cash(player_inv, pin, pricewithtax)
  599. currency.add_cash(vchest_inv, vchest_name, price)
  600. -- Deliver tax to the colonial government.
  601. currency.record_tax_income(pricewithtax - price)
  602. meta:set_string("message", "Item bought.")
  603. easyvend.sound_vend(pos)
  604. easyvend.machine_check(pos, node)
  605. local remote_str = ""
  606. if vendor_inv then
  607. remote_str = " remotely"
  608. end
  609. minetest.log("action", sendername .. remote_str .. " bought " .. number .. " " ..
  610. itemname .. " for " .. price .. " minegeld from vending machine owned by " ..
  611. machine_owner .. " at " .. minetest.pos_to_string(pos) .. ", tax was " .. (pricewithtax - price))
  612. end
  613. end
  614. elseif chest_has and player_has then
  615. if not player_free then
  616. msg = "No room in your inventory!"
  617. meta:set_string("message", msg)
  618. easyvend.sound_error(sendername)
  619. elseif not chest_free then
  620. msg = "No room in the machine’s storage!"
  621. meta:set_string("status", msg)
  622. easyvend.machine_disable(pos, node, sendername)
  623. end
  624. else
  625. if not chest_has then
  626. msg = "The vending machine has insufficient materials!"
  627. meta:set_string("status", msg)
  628. easyvend.machine_disable(pos, node, sendername)
  629. elseif not player_has then
  630. msg = "You can’t afford this item!"
  631. meta:set_string("message", msg)
  632. easyvend.sound_error(sendername)
  633. end
  634. end
  635. else
  636. -- Depositing.
  637. local pricewithtax = price
  638. if vendor_inv then
  639. pricewithtax = currency.calculate_tax(price, 2, remote_tax)
  640. end
  641. chest_has = currency.has_cash_amount(rchest_inv, rchestdef.inv_list, price)
  642. player_has, player_out = easyvend.check_and_get_items(player_inv, pin, stack, check_wear)
  643. chest_free = vchest_inv:room_for_item(vchest_name, stack)
  644. player_free = currency.room_for_cash(player_inv, pin, pricewithtax)
  645. if chest_has and player_has and chest_free and player_free then
  646. if number <= number_stack_max then
  647. easyvend.machine_enable(pos, node)
  648. -- Transfer items before transfering cash (this is because cash transfers can use up an unexpected number of free slots).
  649. if check_wear then
  650. player_inv:set_stack(pin, player_out[1].id, "")
  651. vchest_inv:add_item(vchest_name, player_out[1].item)
  652. else
  653. stack = player_inv:remove_item(pin, stack)
  654. vchest_inv:add_item(vchest_name, stack)
  655. end
  656. -- Transfer money.
  657. currency.remove_cash(rchest_inv, rchestdef.inv_list, price)
  658. currency.add_cash(player_inv, pin, pricewithtax)
  659. -- Deliver tax to the colonial government.
  660. currency.record_tax_income(price - pricewithtax)
  661. meta:set_string("status", "Ready.")
  662. meta:set_string("message", "Item sold.")
  663. easyvend.sound_deposit(pos)
  664. easyvend.machine_check(pos, node)
  665. local remote_str = ""
  666. if vendor_inv then
  667. remote_str = " remotely"
  668. end
  669. minetest.log("action", sendername .. remote_str .. " sold " .. number .. " " ..
  670. itemname .. " for " .. price .. " minegeld to depositing machine owned by " ..
  671. machine_owner .. " at " .. minetest.pos_to_string(pos) .. ", tax was " .. (price - pricewithtax))
  672. else
  673. -- Large item counts (multiple stacks)
  674. local numberstacks = math.modf(number / number_stack_max)
  675. local numberremainder = math.fmod(number, number_stack_max)
  676. local numberfree = numberstacks
  677. if numberremainder > 0 then numberfree = numberfree + 1 end
  678. if not player_free and not currency.room_for_cash(player_inv, pin, pricewithtax) then
  679. msg = "Not enough room in your inventory for payment!"
  680. meta:set_string("message", msg)
  681. easyvend.sound_error(sendername)
  682. elseif not chest_free and easyvend.free_slots(vchest_inv, vchest_name) < numberfree then
  683. meta:set_string("status", "No room in the machine’s storage!")
  684. easyvend.machine_disable(pos, node, sendername)
  685. else
  686. easyvend.machine_enable(pos, node)
  687. -- Remember removed items for transfer
  688. local playerstacks = {}
  689. -- Transfer items before transfering cash (this is because cash transfers can use up an unexpected number of free slots).
  690. if check_wear then
  691. for o=1, #player_out do
  692. player_inv:set_stack(pin, player_out[o].id, "")
  693. end
  694. else
  695. for i=1, numberstacks do
  696. stack.count = number_stack_max
  697. table.insert(playerstacks, player_inv:remove_item(pin, stack))
  698. end
  699. end
  700. if numberremainder > 0 then
  701. stack.count = numberremainder
  702. table.insert(playerstacks, player_inv:remove_item(pin, stack))
  703. end
  704. if check_wear then
  705. for o=1, #player_out do
  706. vchest_inv:add_item(vchest_name, player_out[o].item)
  707. end
  708. else
  709. for i=1, #playerstacks do
  710. vchest_inv:add_item(vchest_name, playerstacks[i])
  711. end
  712. end
  713. -- Transfer money.
  714. currency.remove_cash(rchest_inv, rchestdef.inv_list, price)
  715. currency.add_cash(player_inv, pin, pricewithtax)
  716. -- Deliver tax to the colonial government.
  717. currency.record_tax_income(price - pricewithtax)
  718. meta:set_string("message", "Item sold.")
  719. easyvend.sound_deposit(pos)
  720. easyvend.machine_check(pos, node)
  721. local remote_str = ""
  722. if vendor_inv then
  723. remote_str = " remotely"
  724. end
  725. minetest.log("action", sendername .. remote_str .. " sold " .. number .. " " ..
  726. itemname .. " for " .. price .. " minegeld to depositing machine owned by " ..
  727. machine_owner .. " at " .. minetest.pos_to_string(pos) .. ", tax was " .. (price - pricewithtax))
  728. end
  729. end
  730. elseif chest_has and player_has then
  731. if not player_free then
  732. msg = "No room in your inventory!"
  733. meta:set_string("message", msg)
  734. easyvend.sound_error(sendername)
  735. elseif not chest_free then
  736. msg = "No room in the machine’s storage!"
  737. meta:set_string("status", msg)
  738. easyvend.machine_disable(pos, node, sendername)
  739. end
  740. else
  741. if not player_has then
  742. msg = "You have insufficient materials!"
  743. meta:set_string("message", msg)
  744. easyvend.sound_error(sendername)
  745. elseif not chest_has then
  746. msg = "The depositing machine is out of money!"
  747. meta:set_string("status", msg)
  748. easyvend.machine_disable(pos, node, sendername)
  749. end
  750. end
  751. end
  752. else
  753. local status
  754. meta:set_int("stock", 0)
  755. if chest_error_remove == "no_chest" and chest_error_add == "no_chest" then
  756. status = "No storage; machine needs to be connected with a locked chest."
  757. elseif chest_error_remove == "not_owned" or chest_error_add == "not_owned" then
  758. status = "Storage can’t be accessed because it is owned by a different person!"
  759. elseif chest_error_remove == "no_stock" then
  760. if buysell == "sell" then
  761. status = "The vending machine has insufficient materials!"
  762. else
  763. status = "The depositing machine is out of money!"
  764. end
  765. elseif chest_error_add == "no_space" then
  766. status = "No room in the machine’s storage!"
  767. else
  768. status = "Unknown error!"
  769. end
  770. meta:set_string("status", status)
  771. easyvend.sound_error(sendername)
  772. end
  773. easyvend.set_formspec(pos)
  774. end
  775. -- Executed when player uses formspec on actual vending machine.
  776. easyvend.on_receive_fields_buysell = function(pos, formname, fields, sender)
  777. if not fields.buysell then
  778. return
  779. end
  780. return easyvend.execute_trade(pos, sender, sender:get_inventory(), "main", nil, nil, nil)
  781. end
  782. easyvend.after_place_node = function(pos, placer)
  783. local node = minetest.get_node(pos)
  784. local meta = minetest.get_meta(pos)
  785. local inv = meta:get_inventory()
  786. local player_name = placer:get_player_name()
  787. local dname = rename.gpn(player_name)
  788. inv:set_size("item", 1)
  789. inv:set_size("gold", 1)
  790. local machine_currency = currency_types[initial_currency]
  791. meta:set_string("machine_currency", machine_currency)
  792. meta:set_int("machine_currency_idx", initial_currency)
  793. inv:set_stack( "gold", 1, machine_currency )
  794. local d = ""
  795. if node.name == "easyvend:vendor" then
  796. d = string.format("Inactive Vending Machine (Owned by <%s>!)", dname)
  797. meta:set_int("wear", 1)
  798. elseif node.name == "easyvend:depositor" then
  799. d = string.format("Inactive Depositing Machine (Owned by <%s>!)", dname)
  800. meta:set_int("wear", 0)
  801. end
  802. meta:set_string("infotext", d)
  803. meta:set_string("status", "Awaiting configuration by owner.")
  804. meta:set_string("message", "Welcome! Please prepare the machine.")
  805. meta:set_int("number", 1)
  806. meta:set_int("cost", 1)
  807. meta:set_int("stock", -1)
  808. meta:set_int("configmode", 1)
  809. meta:set_string("itemname", "")
  810. meta:set_string("owner", player_name or "")
  811. meta:set_string("rename", dname)
  812. easyvend.set_formspec(pos)
  813. end
  814. easyvend.can_dig = function(pos, player)
  815. local meta = minetest.get_meta(pos)
  816. local name = player:get_player_name()
  817. local owner = meta:get_string("owner")
  818. -- Owner can always dig shop
  819. if owner == name then
  820. return true
  821. end
  822. local chest_pos = easyvend.find_connected_chest(owner, pos)
  823. local chest, meta_chest
  824. if chest_pos then
  825. chest = minetest.get_node(chest_pos)
  826. meta_chest = minetest.get_meta(chest_pos)
  827. else
  828. return true --if no chest, enyone can dig this shop
  829. end
  830. if registered_chests[chest.name] then
  831. if player and player:is_player() then
  832. local owner_chest = meta_chest:get_string(registered_chests[chest.name].meta_owner)
  833. if name == owner_chest then
  834. return true --chest owner can also dig shop
  835. end
  836. end
  837. return false
  838. else
  839. return true --if no chest, enyone can dig this shop
  840. end
  841. end
  842. easyvend.on_receive_fields = function(pos, formname, fields, sender)
  843. local meta = minetest.get_meta(pos)
  844. local node = minetest.get_node(pos)
  845. local owner = meta:get_string("owner")
  846. local sendername = sender:get_player_name(sender)
  847. if fields.easyvend_currency_image then
  848. if meta:get_int("configmode") == 1 and sendername == owner then
  849. -- Toggle through possible banknote denominations.
  850. local idx = meta:get_int("machine_currency_idx") or initial_currency
  851. idx = idx + 1
  852. if idx > #currency_types then idx = 1 end
  853. meta:set_string("machine_currency", currency_types[idx])
  854. meta:set_int("machine_currency_idx", idx)
  855. easyvend.set_formspec(pos)
  856. end
  857. end
  858. if fields.config or fields.save or fields.usermode then
  859. if sender:get_player_name() == owner then
  860. easyvend.on_receive_fields_config(pos, formname, fields, sender)
  861. else
  862. meta:set_string("message", "Only the owner may change the configuration.")
  863. easyvend.sound_error(sendername)
  864. easyvend.set_formspec(pos)
  865. return
  866. end
  867. elseif fields.wear ~= nil then
  868. if sender:get_player_name() == owner then
  869. if fields.wear == "true" then
  870. if easyvend.buysell(node.name) == "buy" then
  871. meta:set_string("message", "Used tools are now accepted.")
  872. else
  873. meta:set_string("message", "Used tools are now for sale.")
  874. end
  875. meta:set_int("wear", 1)
  876. elseif fields.wear == "false" then
  877. if easyvend.buysell(node.name) == "buy" then
  878. meta:set_string("message", "Used tools are now rejected.")
  879. else
  880. meta:set_string("message", "Used tools won’t be sold anymore.")
  881. end
  882. meta:set_int("wear", 0)
  883. end
  884. easyvend.set_formspec(pos)
  885. return
  886. else
  887. meta:set_string("message", "Only the owner may change the configuration.")
  888. easyvend.sound_error(sendername)
  889. easyvend.set_formspec(pos)
  890. return
  891. end
  892. elseif fields.buysell then
  893. easyvend.on_receive_fields_buysell(pos, formname, fields, sender)
  894. end
  895. end
  896. easyvend.sound_error = function(playername)
  897. minetest.sound_play("easyvend_error", {to_player = playername, gain = 0.25}, true)
  898. end
  899. easyvend.sound_setup = function(pos)
  900. minetest.sound_play("easyvend_activate", {pos = pos, gain = 0.5, max_hear_distance = 12}, true)
  901. end
  902. easyvend.sound_disable = function(pos)
  903. minetest.sound_play("easyvend_disable", {pos = pos, gain = 0.9, max_hear_distance = 12}, true)
  904. end
  905. easyvend.sound_vend = function(pos)
  906. minetest.sound_play("easyvend_vend", {pos = pos, gain = 0.4, max_hear_distance = 5}, true)
  907. end
  908. easyvend.sound_deposit = function(pos)
  909. minetest.sound_play("easyvend_deposit", {pos = pos, gain = 0.4, max_hear_distance = 5}, true)
  910. end
  911. --[[ Tower building ]]
  912. easyvend.is_traversable = function(pos)
  913. local node = minetest.get_node_or_nil(pos)
  914. if (node == nil) then
  915. return false
  916. end
  917. return traversable_node_types[node.name] == true
  918. end
  919. easyvend.neighboring_nodes = function(pos)
  920. local check = {
  921. {x=pos.x, y=pos.y-1, z=pos.z},
  922. {x=pos.x, y=pos.y+1, z=pos.z},
  923. }
  924. local trav = {}
  925. for i=1,#check do
  926. if easyvend.is_traversable(check[i]) then
  927. table.insert(trav, check[i])
  928. end
  929. end
  930. return trav
  931. end
  932. easyvend.find_connected_chest = function(owner, pos, nodename, check_wear, amount, removing)
  933. local nodes = easyvend.neighboring_nodes(pos)
  934. if (#nodes < 1 or #nodes > 2) then
  935. return nil, "no_chest"
  936. end
  937. -- Find the stack direction
  938. local first = nil
  939. local second = nil
  940. for i=1,#nodes do
  941. if ( first == nil ) then
  942. first = nodes[i]
  943. else
  944. second = nodes[i]
  945. end
  946. end
  947. local chest_pos, chest_internal
  948. if (first ~= nil and second ~= nil) then
  949. local dy = (first.y - second.y)/2
  950. chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
  951. if ( chest_pos == nil ) then
  952. chest_pos, chest_internal = easyvend.find_chest(owner, pos, -dy, nodename, check_wear, amount, removing, chest_internal)
  953. end
  954. else
  955. local dy = first.y - pos.y
  956. chest_pos, chest_internal = easyvend.find_chest(owner, pos, dy, nodename, check_wear, amount, removing)
  957. end
  958. if chest_internal.chests == 0 then
  959. return nil, "no_chest"
  960. elseif chest_internal.chests == chest_internal.other_chests then
  961. return nil, "not_owned"
  962. elseif removing and chest_internal.stock < 1 then
  963. return nil, "no_stock"
  964. elseif not removing and chest_internal.space < 1 then
  965. return nil, "no_space"
  966. elseif chest_pos ~= nil then
  967. return chest_pos
  968. else
  969. return nil, "unknown"
  970. end
  971. end
  972. easyvend.find_chest = function(owner, pos, dy, itemname, check_wear, amount, removing, internal)
  973. pos = {x=pos.x, y=pos.y + dy, z=pos.z}
  974. if internal == nil then
  975. internal = {}
  976. internal.chests = 0
  977. internal.other_chests = 0
  978. internal.stock = 0
  979. internal.space = 0
  980. end
  981. local node = minetest.get_node_or_nil(pos)
  982. if ( node == nil ) then
  983. return nil, internal
  984. end
  985. local chestdef = registered_chests[node.name]
  986. if (chestdef ~= nil) then
  987. internal.chests = internal.chests + 1
  988. local meta = minetest.get_meta(pos)
  989. if (owner ~= meta:get_string(chestdef.meta_owner)) then
  990. internal.other_chests = internal.other_chests + 1
  991. return nil, internal
  992. end
  993. local inv = meta:get_inventory()
  994. if (inv ~= nil) then
  995. if (itemname ~= nil and amount ~= nil and removing ~= nil and check_wear ~= nil) then
  996. local chest_has, chest_free
  997. -- We're going to query the chest to answer two questions:
  998. -- Does the chest contain the item in the amount requested?
  999. -- Does the chest contain free slots suitable to store the amount requested?
  1000. if currency.is_currency(itemname) then
  1001. -- Item is a fungible currency, use currency-related functions.
  1002. local value = currency.get_stack_value(itemname, amount)
  1003. chest_free = currency.room_for_cash(inv, chestdef.inv_list, value)
  1004. chest_has = currency.has_cash_amount(inv, chestdef.inv_list, value)
  1005. -- If the chest doesn't have enough space to ADD currency,
  1006. -- we can't safely remove currency, either (due to denomination splitting).
  1007. if not chest_free then
  1008. chest_has = false
  1009. end
  1010. else
  1011. -- Do regular itemstack-style check. Note: as of the current Minetest version,
  1012. -- the raw inv:room_for_item() check works with stacks over the stackmax limit.
  1013. -- The old version of this check also checked for number of free slots,
  1014. -- but that shouldn't be necessary.
  1015. local stack = {name=itemname, count=amount, wear=0, metadata=""}
  1016. chest_has = easyvend.check_and_get_items(inv, chestdef.inv_list, stack, check_wear)
  1017. chest_free = inv:room_for_item(chestdef.inv_list, stack)
  1018. end
  1019. if chest_has then
  1020. internal.stock = internal.stock + 1
  1021. end
  1022. if chest_free then
  1023. internal.space = internal.space + 1
  1024. end
  1025. if (removing and internal.stock == 0) or (not removing and internal.space == 0) then
  1026. return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
  1027. else
  1028. return pos, internal
  1029. end
  1030. end
  1031. end
  1032. elseif (node.name ~= "easyvend:vendor" and node.name~="easyvend:depositor" and node.name~="easyvend:vendor_on" and node.name~="easyvend:depositor_on") then
  1033. return nil, internal
  1034. end
  1035. return easyvend.find_chest(owner, pos, dy, itemname, check_wear, amount, removing, internal)
  1036. end
  1037. -- Pseudo-inventory handling
  1038. easyvend.allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  1039. if listname=="item" then
  1040. local meta = minetest.get_meta(pos);
  1041. local owner = meta:get_string("owner")
  1042. local name = player:get_player_name()
  1043. if name == owner then
  1044. local inv = meta:get_inventory()
  1045. if stack==nil then
  1046. inv:set_stack( "item", 1, nil )
  1047. else
  1048. local sn = stack:get_name()
  1049. -- Do not permit currency denominations to be placed in this slot.
  1050. if currency.is_currency(sn) then
  1051. return 0
  1052. end
  1053. inv:set_stack("item", 1, sn)
  1054. meta:set_string("itemname", sn)
  1055. easyvend.set_formspec(pos)
  1056. end
  1057. end
  1058. end
  1059. return 0
  1060. end
  1061. easyvend.allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  1062. return 0
  1063. end
  1064. easyvend.allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
  1065. return 0
  1066. end