barter.lua 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. if not minetest.global_exists("barter") then barter = {} end
  2. barter.chest = barter.chest or {}
  3. barter.reset_delay = 60*20 -- Number of seconds to reset after pressing start.
  4. barter.long_delay = 60*60*3
  5. barter.enable_logging = false
  6. -- Localize for performance.
  7. local math_floor = math.floor
  8. function barter.report(msg)
  9. if barter.enable_logging then
  10. local pref = utility.get_first_available_admin()
  11. if pref then
  12. minetest.chat_send_player(pref:get_player_name(), msg)
  13. end
  14. end
  15. end
  16. barter.chest.formspec = {
  17. main = "size[8,9]"..
  18. default.gui_bg ..
  19. default.gui_bg_img ..
  20. default.gui_slots ..
  21. "list[context;pl1;0,0;3,4;]"..
  22. "list[context;pl2;5,0;3,4;]"..
  23. "list[current_player;main;0,5;8,4;]",
  24. pl1 = {
  25. start = "button[3,1;1,1;pl1_start;Start]",
  26. player = function(name) return "label[3,0;" .. rename.gpn(name) .. "]" end,
  27. accept1 = "button[3,1;1,1;pl1_accept1;Confirm]"..
  28. "button[3,2;1,1;pl1_cancel;Cancel]",
  29. accept2 = "button[3,1;1,1;pl1_accept2;Exchange]"..
  30. "button[3,2;1,1;pl1_cancel;Cancel]",
  31. },
  32. pl2 = {
  33. start = "button[4,1;1,1;pl2_start;Start]",
  34. player = function(name) return "label[4,0;" .. rename.gpn(name) .. "]" end,
  35. accept1 = "button[4,1;1,1;pl2_accept1;Confirm]"..
  36. "button[4,2;1,1;pl2_cancel;Cancel]",
  37. accept2 = "button[4,1;1,1;pl2_accept2;Exchange]"..
  38. "button[4,2;1,1;pl2_cancel;Cancel]",
  39. },
  40. }
  41. barter.chest.check_privilege = function(listname,playername,meta)
  42. if listname == "pl1" then
  43. if playername ~= meta:get_string("pl1") then
  44. return false
  45. elseif meta:get_int("pl1step") ~= 1 then
  46. return false
  47. end
  48. end
  49. if listname == "pl2" then
  50. if playername ~= meta:get_string("pl2") then
  51. return false
  52. elseif meta:get_int("pl2step") ~= 1 then
  53. return false
  54. end
  55. end
  56. return true
  57. end
  58. barter.chest.update_formspec = function(meta)
  59. local formspec = barter.chest.formspec.main
  60. local pl_formspec = function(n)
  61. if meta:get_int(n.."step")==0 then
  62. formspec = formspec .. barter.chest.formspec[n].start
  63. else
  64. formspec = formspec .. barter.chest.formspec[n].player(meta:get_string(n))
  65. if meta:get_int(n.."step") == 1 then
  66. formspec = formspec .. barter.chest.formspec[n].accept1
  67. elseif meta:get_int(n.."step") == 2 then
  68. formspec = formspec .. barter.chest.formspec[n].accept2
  69. end
  70. end
  71. end
  72. pl_formspec("pl1")
  73. pl_formspec("pl2")
  74. meta:set_string("formspec", formspec)
  75. end
  76. barter.chest.give_inventory = function(inv, list, playername)
  77. barter.report("Giving list " .. list .. " to <" .. playername .. ">.")
  78. player = minetest.get_player_by_name(playername)
  79. if inv and player then
  80. local pinv = player:get_inventory()
  81. if pinv then
  82. barter.report("Moving items!")
  83. local from_list = inv:get_list(list)
  84. for k, v in ipairs(from_list) do
  85. pinv:add_item("main", v)
  86. inv:remove_item(list, v)
  87. end
  88. else
  89. barter.report("Couldn't get player inv!")
  90. end
  91. else
  92. barter.report("Missing inv or player!")
  93. end
  94. end
  95. barter.chest.cancel = function(meta)
  96. barter.chest.give_inventory(meta:get_inventory(),"pl1",meta:get_string("pl1"))
  97. barter.chest.give_inventory(meta:get_inventory(),"pl2",meta:get_string("pl2"))
  98. meta:set_string("pl1","")
  99. meta:set_string("pl2","")
  100. meta:set_int("pl1step",0)
  101. meta:set_int("pl2step",0)
  102. end
  103. -- This function expects to be called from minetest.after().
  104. -- Added by MustTest, to prevent players from locking these tables up so other players can't use them.
  105. barter.chest.hard_reset = function(pos, side, name)
  106. local node = minetest.get_node(pos)
  107. if node.name == "barter_table:barter" then
  108. local meta = minetest.get_meta(pos)
  109. if meta and meta:get_string(side) == name then
  110. barter.chest.give_inventory(meta:get_inventory(), side, meta:get_string(side))
  111. meta:set_string(side, "")
  112. meta:set_int(side .. "step", 0)
  113. barter.chest.update_formspec(meta)
  114. end
  115. end
  116. end
  117. -- Also need an hourly (or so) reset function, in case the server crashes before minetest.after() is run.
  118. barter.chest.reset2 = function(pos, elapsed)
  119. local node = minetest.get_node(pos)
  120. if node.name == "barter_table:barter" then
  121. local meta = minetest.get_meta(pos)
  122. barter.chest.give_inventory(meta:get_inventory(), "pl1", meta:get_string("pl1"))
  123. barter.chest.give_inventory(meta:get_inventory(), "pl2", meta:get_string("pl2"))
  124. meta:set_string("pl1", "")
  125. meta:set_string("pl2", "")
  126. meta:set_int("pl1step", 0)
  127. meta:set_int("pl2step", 0)
  128. barter.chest.update_formspec(meta)
  129. return true
  130. end
  131. end
  132. barter.chest.exchange = function(meta)
  133. barter.chest.give_inventory(meta:get_inventory(), "pl1", meta:get_string("pl2"))
  134. barter.chest.give_inventory(meta:get_inventory(), "pl2", meta:get_string("pl1"))
  135. meta:set_string("pl1","")
  136. meta:set_string("pl2","")
  137. meta:set_int("pl1step",0)
  138. meta:set_int("pl2step",0)
  139. end
  140. minetest.register_node("barter_table:barter", {
  141. drawtype = "nodebox",
  142. description = "Barter Table",
  143. paramtype = "light",
  144. paramtype2 = "facedir",
  145. tiles = {
  146. "barter_top.png",
  147. "barter_base.png",
  148. "barter_side.png",
  149. },
  150. inventory_image = "barter_top.png",
  151. node_box = {
  152. type = "fixed",
  153. fixed = {
  154. {-0.500000,0.312500,-0.500000,0.500000,0.500000,0.500000},
  155. {-0.437500,-0.500000,-0.437500,-0.250000,0.500000,-0.250000},
  156. {-0.437500,-0.500000,0.250000,-0.250000,0.500000,0.437500},
  157. {0.250000,-0.500000,-0.437500,0.437500,0.500000,-0.250000},
  158. {0.250000,-0.500000,0.250000,0.437500,0.500000,0.447500},
  159. },
  160. },
  161. groups = utility.dig_groups("furniture"),
  162. sounds = default.node_sound_wood_defaults(),
  163. on_timer = barter.chest.reset2,
  164. on_construct = function(pos)
  165. local meta = minetest.get_meta(pos)
  166. meta:set_string("infotext", "Trade/Barter Table")
  167. meta:set_string("pl1","")
  168. meta:set_string("pl2","")
  169. barter.chest.update_formspec(meta)
  170. local inv = meta:get_inventory()
  171. inv:set_size("pl1", 3*4)
  172. inv:set_size("pl2", 3*4)
  173. local timer = minetest.get_node_timer(pos)
  174. timer:start(barter.long_delay)
  175. end,
  176. on_receive_fields = function(pos, formname, fields, sender)
  177. local meta = minetest.get_meta(pos)
  178. local pl_receive_fields = function(n)
  179. if fields[n.."_start"] and meta:get_string(n) == "" then
  180. meta:set_string(n,sender:get_player_name())
  181. minetest.chat_send_player(sender:get_player_name(),
  182. "# Server: This barter table will reset in " ..
  183. barter.reset_delay/60 .. " minutes. Please complete your transaction before then.")
  184. minetest.after(barter.reset_delay, barter.chest.hard_reset, pos, n, sender:get_player_name())
  185. -- Make sure the janitor timer is running.
  186. local timer = minetest.get_node_timer(pos)
  187. if timer then
  188. if not timer:is_started() then
  189. timer:start(barter.long_delay)
  190. end
  191. -- Alert players how much time is left.
  192. local elasped = timer:get_elapsed()
  193. minetest.chat_send_player(sender:get_player_name(), "# Server: The periodic reset for this table is scheduled to occure in " .. math_floor((barter.long_delay - elasped)/60) .. " minutes.")
  194. minetest.chat_send_player(sender:get_player_name(), "# Server: WARNING: make sure you have enough space in your inventory to receive bartered goods.")
  195. end
  196. end
  197. if meta:get_string(n) == "" then
  198. meta:set_int(n.."step",0)
  199. elseif meta:get_int(n.."step")==0 then
  200. meta:set_int(n.."step",1)
  201. end
  202. if sender:get_player_name() == meta:get_string(n) then
  203. if meta:get_int(n.."step")==1 and fields[n.."_accept1"] then
  204. meta:set_int(n.."step",2)
  205. end
  206. if meta:get_int(n.."step")==2 and fields[n.."_accept2"] then
  207. meta:set_int(n.."step",3)
  208. if n == "pl1" and meta:get_int("pl2step") == 3 then barter.chest.exchange(meta) end
  209. if n == "pl2" and meta:get_int("pl1step") == 3 then barter.chest.exchange(meta) end
  210. end
  211. if fields[n.."_cancel"] then barter.chest.cancel(meta) end
  212. end
  213. end
  214. pl_receive_fields("pl1")
  215. pl_receive_fields("pl2")
  216. -- End
  217. barter.chest.update_formspec(meta)
  218. end,
  219. allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
  220. local meta = minetest.get_meta(pos)
  221. if not barter.chest.check_privilege(from_list,player:get_player_name(),meta) then return 0 end
  222. if not barter.chest.check_privilege(to_list,player:get_player_name(),meta) then return 0 end
  223. return count
  224. end,
  225. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  226. local meta = minetest.get_meta(pos)
  227. if not barter.chest.check_privilege(listname,player:get_player_name(),meta) then return 0 end
  228. return stack:get_count()
  229. end,
  230. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  231. local meta = minetest.get_meta(pos)
  232. if not barter.chest.check_privilege(listname,player:get_player_name(),meta) then return 0 end
  233. return stack:get_count()
  234. end,
  235. })