barter.lua 8.2 KB

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