shop.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. local S = minetest.get_translator("currency")
  2. currency.shop = {}
  3. if minetest.global_exists("default") then
  4. default.shop = currency.shop
  5. end
  6. currency.shop.current_shop = {}
  7. currency.shop.formspec = {
  8. customer = function(pos)
  9. local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
  10. local formspec = "size[8,9.5]"..
  11. "label[0,0;" .. S("Customer gives (pay here!)") .. "]"..
  12. "list[current_player;customer_gives;0,0.5;3,2;]"..
  13. "label[0,2.5;" .. S("Customer gets:") .. "]"..
  14. "list[current_player;customer_gets;0,3;3,2;]"..
  15. "label[5,0;" .. S("Owner wants:") .. "]"..
  16. "list["..list_name..";owner_wants;5,0.5;3,2;]"..
  17. "label[5,2.5;" .. S("Owner gives:") .. "]"..
  18. "list["..list_name..";owner_gives;5,3;3,2;]"..
  19. "list[current_player;main;0,5.5;8,4;]"..
  20. "button[3,2;2,1;exchange;" .. S("Exchange") .. "]"
  21. return formspec
  22. end,
  23. owner = function(pos)
  24. local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
  25. local formspec = "size[8,9.5]"..
  26. "label[0,0;" .. S("Customers gave:") .. "]"..
  27. "list["..list_name..";customers_gave;0,0.5;3,2;]"..
  28. "label[0,2.5;" .. S("Your stock:") .. "]"..
  29. "list["..list_name..";stock;0,3;3,2;]"..
  30. "label[4,0;" .. S("You want:") .. "]"..
  31. "list["..list_name..";owner_wants;4,0.5;3,2;]"..
  32. "label[4,2.5;" .. S("In exchange, you give:") .. "]"..
  33. "list["..list_name..";owner_gives;4,3;3,2;]"..
  34. "label[0,5;" .. S("Owner, Use (E)+Place (right mouse button) for customer interface") .. "]"..
  35. "list[current_player;main;0,5.5;8,4;]"
  36. return formspec
  37. end,
  38. }
  39. local have_pipeworks = minetest.global_exists("pipeworks")
  40. currency.shop.check_privilege = function(listname,playername,meta)
  41. --[[if listname == "pl1" then
  42. if playername ~= meta:get_string("pl1") then
  43. return false
  44. elseif meta:get_int("pl1step") ~= 1 then
  45. return false
  46. end
  47. end
  48. if listname == "pl2" then
  49. if playername ~= meta:get_string("pl2") then
  50. return false
  51. elseif meta:get_int("pl2step") ~= 1 then
  52. return false
  53. end
  54. end]]
  55. return true
  56. end
  57. currency.shop.give_inventory = function(inv,list,playername)
  58. player = minetest.get_player_by_name(playername)
  59. if player then
  60. for k,v in ipairs(inv:get_list(list)) do
  61. player:get_inventory():add_item("main",v)
  62. inv:remove_item(list,v)
  63. end
  64. end
  65. end
  66. currency.shop.cancel = function(meta)
  67. --[[currency.shop.give_inventory(meta:get_inventory(),"pl1",meta:get_string("pl1"))
  68. currency.shop.give_inventory(meta:get_inventory(),"pl2",meta:get_string("pl2"))
  69. meta:set_string("pl1","")
  70. meta:set_string("pl2","")
  71. meta:set_int("pl1step",0)
  72. meta:set_int("pl2step",0)]]
  73. end
  74. currency.shop.exchange = function(meta)
  75. --[[currency.shop.give_inventory(meta:get_inventory(),"pl1",meta:get_string("pl2"))
  76. currency.shop.give_inventory(meta:get_inventory(),"pl2",meta:get_string("pl1"))
  77. meta:set_string("pl1","")
  78. meta:set_string("pl2","")
  79. meta:set_int("pl1step",0)
  80. meta:set_int("pl2step",0)]]
  81. end
  82. local check_stock = function(
  83. pos
  84. )
  85. local meta = minetest.get_meta(
  86. pos
  87. )
  88. local minv = meta:get_inventory(
  89. )
  90. local gives = minv:get_list(
  91. "owner_gives"
  92. )
  93. local can_exchange = true
  94. for i, item in pairs(
  95. gives
  96. ) do
  97. if not minv:contains_item(
  98. "stock",
  99. item
  100. ) then
  101. can_exchange = false
  102. end
  103. end
  104. local owner = meta:get_string(
  105. "owner"
  106. )
  107. if can_exchange then
  108. meta:set_string(
  109. "infotext",
  110. S(
  111. "Exchange shop (owned by @1)",
  112. owner
  113. )
  114. )
  115. local applicable = "currency:shop"
  116. local node = minetest.get_node(
  117. pos
  118. )
  119. if node.name == applicable then
  120. return
  121. end
  122. node.name = applicable
  123. minetest.swap_node(
  124. pos,
  125. node
  126. )
  127. else
  128. meta:set_string(
  129. "infotext",
  130. S(
  131. "Exchange shop (owned by @1)",
  132. owner
  133. ) .. ", " .. S(
  134. "out of stock"
  135. )
  136. )
  137. local applicable = "currency:shop_empty"
  138. local node = minetest.get_node(
  139. pos
  140. )
  141. if node.name == applicable then
  142. return
  143. end
  144. node.name = applicable
  145. minetest.swap_node(
  146. pos,
  147. node
  148. )
  149. end
  150. end
  151. minetest.register_node("currency:shop", {
  152. description = S("Shop"),
  153. paramtype2 = "facedir",
  154. tiles = {"shop_top.png",
  155. "shop_top.png",
  156. "shop_side.png",
  157. "shop_side.png",
  158. "shop_side.png",
  159. "shop_front.png"},
  160. inventory_image = "shop_front.png",
  161. groups = {choppy=2,oddly_breakable_by_hand=2,tubedevice=1,tubedevice_receiver=1},
  162. sounds = currency.node_sound_wood_defaults(),
  163. after_place_node = function(pos, placer, itemstack)
  164. local owner = placer:get_player_name()
  165. local meta = minetest.get_meta(pos)
  166. meta:set_string("infotext", S("Exchange shop (owned by @1)", owner))
  167. meta:set_string("owner", owner)
  168. --[[meta:set_string("pl1","")
  169. meta:set_string("pl2","")]]
  170. local inv = meta:get_inventory()
  171. inv:set_size("customers_gave", 3*2)
  172. inv:set_size("stock", 3*2)
  173. inv:set_size("owner_wants", 3*2)
  174. inv:set_size("owner_gives", 3*2)
  175. if have_pipeworks then pipeworks.after_place(pos) end
  176. check_stock(
  177. pos
  178. )
  179. end,
  180. after_dig_node = (have_pipeworks and pipeworks and pipeworks.after_dig),
  181. tube = {
  182. insert_object = function(pos, node, stack, direction)
  183. local meta = minetest.get_meta(pos)
  184. local inv = meta:get_inventory()
  185. local result = inv:add_item("stock",stack)
  186. check_stock(
  187. pos
  188. )
  189. return result
  190. end,
  191. can_insert = function(pos,node,stack,direction)
  192. local meta = minetest.get_meta(pos)
  193. local inv = meta:get_inventory()
  194. return inv:room_for_item("stock", stack)
  195. end,
  196. input_inventory = "customers_gave",
  197. connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
  198. },
  199. on_rightclick = function(pos, node, clicker, itemstack)
  200. clicker:get_inventory():set_size("customer_gives", 3*2)
  201. clicker:get_inventory():set_size("customer_gets", 3*2)
  202. currency.shop.current_shop[clicker:get_player_name()] = pos
  203. local meta = minetest.get_meta(pos)
  204. if clicker:get_player_name() == meta:get_string("owner") and not clicker:get_player_control().aux1 then
  205. minetest.show_formspec(clicker:get_player_name(),"currency:shop_formspec",currency.shop.formspec.owner(pos))
  206. else
  207. minetest.show_formspec(clicker:get_player_name(),"currency:shop_formspec",currency.shop.formspec.customer(pos))
  208. end
  209. end,
  210. allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
  211. local meta = minetest.get_meta(pos)
  212. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  213. return count
  214. end,
  215. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  216. local meta = minetest.get_meta(pos)
  217. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  218. return stack:get_count()
  219. end,
  220. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  221. local meta = minetest.get_meta(pos)
  222. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  223. return stack:get_count()
  224. end,
  225. on_metadata_inventory_move = check_stock,
  226. on_metadata_inventory_put = check_stock,
  227. on_metadata_inventory_take = check_stock,
  228. can_dig = function(pos, player)
  229. local meta = minetest.get_meta(pos)
  230. local inv = meta:get_inventory()
  231. return inv:is_empty("stock") and inv:is_empty("customers_gave") and inv:is_empty("owner_wants") and inv:is_empty("owner_gives")
  232. end
  233. })
  234. minetest.register_node("currency:shop_empty", {
  235. description = S("Shop") .. " (" .. S("out of stock") .. ")",
  236. paramtype2 = "facedir",
  237. tiles = {"shop_top.png",
  238. "shop_top.png",
  239. "shop_side_empty.png",
  240. "shop_side_empty.png",
  241. "shop_side_empty.png",
  242. "shop_front_empty.png"},
  243. drop = "currency:shop",
  244. groups = {choppy=2,oddly_breakable_by_hand=2,tubedevice=1,tubedevice_receiver=1,not_in_creative_inventory=1},
  245. sounds = currency.node_sound_wood_defaults(),
  246. after_dig_node = (have_pipeworks and pipeworks and pipeworks.after_dig),
  247. tube = {
  248. insert_object = function(pos, node, stack, direction)
  249. local meta = minetest.get_meta(pos)
  250. local inv = meta:get_inventory()
  251. local result = inv:add_item("stock",stack)
  252. check_stock(
  253. pos
  254. )
  255. return result
  256. end,
  257. can_insert = function(pos,node,stack,direction)
  258. local meta = minetest.get_meta(pos)
  259. local inv = meta:get_inventory()
  260. return inv:room_for_item("stock", stack)
  261. end,
  262. input_inventory = "customers_gave",
  263. connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
  264. },
  265. on_rightclick = function(pos, node, clicker, itemstack)
  266. clicker:get_inventory():set_size("customer_gives", 3*2)
  267. clicker:get_inventory():set_size("customer_gets", 3*2)
  268. currency.shop.current_shop[clicker:get_player_name()] = pos
  269. local meta = minetest.get_meta(pos)
  270. if clicker:get_player_name() == meta:get_string("owner") and not clicker:get_player_control().aux1 then
  271. minetest.show_formspec(clicker:get_player_name(),"currency:shop_formspec",currency.shop.formspec.owner(pos))
  272. else
  273. minetest.show_formspec(clicker:get_player_name(),"currency:shop_formspec",currency.shop.formspec.customer(pos))
  274. end
  275. end,
  276. allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
  277. local meta = minetest.get_meta(pos)
  278. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  279. return count
  280. end,
  281. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  282. local meta = minetest.get_meta(pos)
  283. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  284. return stack:get_count()
  285. end,
  286. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  287. local meta = minetest.get_meta(pos)
  288. if player:get_player_name() ~= meta:get_string("owner") then return 0 end
  289. return stack:get_count()
  290. end,
  291. on_metadata_inventory_move = check_stock,
  292. on_metadata_inventory_put = check_stock,
  293. on_metadata_inventory_take = check_stock,
  294. can_dig = function(pos, player)
  295. local meta = minetest.get_meta(pos)
  296. local inv = meta:get_inventory()
  297. return inv:is_empty("stock") and inv:is_empty("customers_gave") and inv:is_empty("owner_wants") and inv:is_empty("owner_gives")
  298. end
  299. })
  300. minetest.register_on_player_receive_fields(function(sender, formname, fields)
  301. if formname == "currency:shop_formspec" and fields.exchange ~= nil and fields.exchange ~= "" then
  302. local name = sender:get_player_name()
  303. local pos = currency.shop.current_shop[name]
  304. local meta = minetest.get_meta(pos)
  305. if meta:get_string("owner") == name then
  306. minetest.chat_send_player(name, S("This is your own shop, you can't exchange to yourself!"))
  307. else
  308. local minv = meta:get_inventory()
  309. local pinv = sender:get_inventory()
  310. local invlist_tostring = function(invlist)
  311. local out = {}
  312. for i, item in pairs(invlist) do
  313. out[i] = item:to_string()
  314. end
  315. return out
  316. end
  317. local wants = minv:get_list("owner_wants")
  318. local gives = minv:get_list("owner_gives")
  319. if wants == nil or gives == nil then return end -- do not crash the server
  320. -- Check if we can exchange
  321. local can_exchange = true
  322. local owners_fault = false
  323. for i, item in pairs(wants) do
  324. if not pinv:contains_item("customer_gives",item) then
  325. can_exchange = false
  326. end
  327. end
  328. for i, item in pairs(gives) do
  329. if not minv:contains_item("stock",item) then
  330. can_exchange = false
  331. owners_fault = true
  332. end
  333. end
  334. if can_exchange then
  335. for i, item in pairs(wants) do
  336. pinv:remove_item("customer_gives",item)
  337. minv:add_item("customers_gave",item)
  338. end
  339. for i, item in pairs(gives) do
  340. minv:remove_item("stock",item)
  341. pinv:add_item("customer_gets",item)
  342. end
  343. minetest.chat_send_player(name, S("Exchanged!"))
  344. check_stock(
  345. pos
  346. )
  347. else
  348. if owners_fault then
  349. minetest.chat_send_player(name, S("Exchange can not be done, contact the shop owner."))
  350. else
  351. minetest.chat_send_player(name, S("Exchange can not be done, check if you put all items!"))
  352. end
  353. end
  354. end
  355. end
  356. end)