A Minetest trading mod by crabman, under the original idea of Cyberpangolin.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1010 lines
35KB

  1. local shop_sell = {} --formspec temporary variables
  2. local shop_buy = {}
  3. local shop_admin = {}
  4. minercantile.shop.max_stock = 20000 --shop don't buy infinity items
  5. minercantile.shop.shop = {}
  6. minercantile.registered_items = {}
  7. --shop type
  8. minercantile.shop.shop_type = {"General", "Armors", "Beds", "Boats", "Brick", "Carts", "Chest", "Cobble", "Columnia", "Decor", "Doors", "Dye", "Farming", "Fences", "Fishing", "Flowers", "Furnaces", "Glass", "Ingot", "Mesecons", "Nether", "Runes", "Sea", "Sign", "Stair_Slab", "Stone", "Tools", "Wood", "Wool"}
  9. minercantile.shop.shop_sorted = {
  10. Armors = { groups = {"armor_heal"}, regex={"sword", "throwing", "spears"}},
  11. Beds = { groups = {"bed"}, regex={":bed"}},
  12. Boats = { groups = {}, regex={"boats"}},
  13. Brick = { groups = {}, regex={"brick"}},
  14. Carts = { groups = {"rail", "connect_to_raillike"}, regex={"cart"}},
  15. Chest = { groups = {}, regex={"chest"}},
  16. Cobble = { groups = {}, regex={"cobble"}},
  17. Columnia = { groups = {}, regex={"columnia"}},
  18. Decor = { groups = {}, regex={"decor"}},
  19. Doors = { groups = {}, regex={"door"}},
  20. Dye = { groups = {"dye"}, regex={}},
  21. Farming = { groups = {}, regex={"farming", "food"}},
  22. Fences = { groups = {"fence", "fences", "wall"}, regex={}},
  23. Flowers = { groups = {"flora", "flower"}, regex={}},
  24. Fishing = { groups = {}, regex={"fishing"}},
  25. Furnaces = { groups = {}, regex={"furnace"}},
  26. Glass = { groups = {}, regex={"glass"}},
  27. Ingot = { groups = {"ingot"}, regex={"lump", ":diamond", ":nyancat", ":mese"}},
  28. --Leaves = { groups = {"leaves"}, regex={}},
  29. Mesecons = { groups = {}, regex={"mesecon", "pipeworks"}},
  30. Nether = { groups = {"nether"}, regex={}},
  31. Runes = { groups = {"amulet", "magic", "rune"}, regex={}},
  32. Sea = { groups = {"sea", "seaplants", "seacoral"}, regex={}},
  33. Sign = { groups = {}, regex={"sign"}},
  34. Stair_Slab = { groups = {"stair", "slab"}, regex={}},
  35. Stone = { groups = {"stone", "sand"}, regex={"stone", "cobble", "sand", "brick"}},
  36. Tools = { groups = {}, regex={":pick", ":axe", ":shovel", ":hoe", ":bag"}},
  37. Wood = { groups = {"wood", "coloredsticks", "leaves", "stick", "tree", "tree_root", "sapling"}, regex={}},
  38. Wool = { groups = {"wool"}, regex={"cotton"}},
  39. }
  40. --function shop money
  41. function minercantile.shop.get_money()
  42. return (minercantile.stock.money or 0)
  43. end
  44. function minercantile.shop.take_money(money, saving)
  45. minercantile.stock.money = minercantile.shop.get_money() - money
  46. if minercantile.shop.get_money() < 0 then
  47. minercantile.stock.money = 0
  48. end
  49. if saving then
  50. minercantile.save_stock()
  51. end
  52. end
  53. function minercantile.shop.give_money(money, saving)
  54. minercantile.stock.money = minercantile.shop.get_money() + money
  55. if saving then
  56. minercantile.save_stock()
  57. end
  58. end
  59. function minercantile.shop.get_nb(itname)
  60. if minercantile.stock.items[itname] then
  61. return minercantile.stock.items[itname].nb
  62. end
  63. return 0
  64. end
  65. function minercantile.shop.get_transac_b()
  66. return minercantile.stock.transac_b
  67. end
  68. function minercantile.shop.get_transac_s()
  69. return minercantile.stock.transac_s
  70. end
  71. function minercantile.shop.set_transac_b()
  72. minercantile.stock.transac_b = minercantile.stock.transac_b + 1
  73. end
  74. function minercantile.shop.set_transac_s()
  75. minercantile.stock.transac_s = minercantile.stock.transac_s + 1
  76. end
  77. function minercantile.shop.is_available(itname)
  78. if minercantile.registered_items[itname] then
  79. return true
  80. end
  81. return false
  82. end
  83. function minercantile.shop.get_item_def(itname)
  84. if minercantile.registered_items[itname] then
  85. return minercantile.registered_items[itname]
  86. end
  87. return nil
  88. end
  89. function minercantile.shop.is_shop_type(itname, def, shop_def)
  90. for _, group in pairs(shop_def.groups) do
  91. if def.groups[group] then
  92. return true
  93. end
  94. end
  95. for _, regex in pairs(shop_def.regex) do
  96. if regex ~= "" and itname:find(regex) then
  97. return true
  98. end
  99. end
  100. return false
  101. end
  102. -- table of sellable/buyable items,ignore admin stuff
  103. function minercantile.shop.register_items()
  104. minercantile.registered_items = {}
  105. minercantile.shop.register_whitelist()
  106. for itname, def in pairs(minetest.registered_items) do
  107. if not itname:find("maptools:") --ignore maptools
  108. and not itname:find("_coin")
  109. and not def.groups.not_in_creative_inventory
  110. and not def.groups.unbreakable
  111. and (def.description and def.description ~= "") then
  112. minercantile.registered_items[itname] = {groups = def.groups, desc = def.description}
  113. end
  114. end
  115. minercantile.shop.shop["General"] = {}
  116. for itname, def in pairs(minercantile.registered_items) do
  117. table.insert(minercantile.shop.shop["General"], itname)
  118. for shop, shop_def in pairs(minercantile.shop.shop_sorted) do
  119. if not minercantile.shop.shop[shop] then
  120. minercantile.shop.shop[shop] = {}
  121. end
  122. if minercantile.shop.is_shop_type(itname, def, shop_def) then
  123. table.insert(minercantile.shop.shop[shop], itname)
  124. end
  125. end
  126. end
  127. end
  128. function minercantile.shop.register_whitelist()
  129. for _, itname in pairs(minercantile.shop.items_whitelist) do
  130. local def = minetest.registered_items[itname]
  131. if def then
  132. minercantile.registered_items[itname] = {groups = def.groups, desc = def.description}
  133. end
  134. end
  135. end
  136. function minercantile.shop.add_item(itname, nb)
  137. if minercantile.shop.is_available(itname) then
  138. if not minercantile.stock.items[itname] then
  139. minercantile.stock.items[itname] = {nb=0}
  140. end
  141. minercantile.stock.items[itname].nb = minercantile.stock.items[itname].nb + nb
  142. minercantile.save_stock()
  143. end
  144. end
  145. function minercantile.shop.del_item(itname, nb)
  146. if minercantile.shop.is_available(itname) then
  147. if not minercantile.stock.items[itname] then
  148. minercantile.stock.items[itname] = {nb=0}
  149. end
  150. minercantile.stock.items[itname].nb = minercantile.stock.items[itname].nb - nb
  151. if minercantile.stock.items[itname].nb < 0 then
  152. minercantile.stock.items[itname].nb = 0
  153. end
  154. minercantile.save_stock()
  155. end
  156. end
  157. --function save items_base
  158. function minercantile.save_stock_base()
  159. local input, err = io.open(minercantile.file_stock_base, "w")
  160. if input then
  161. input:write(minetest.serialize(minercantile.stock_base))
  162. input:close()
  163. else
  164. minetest.log("error", "open(" .. minercantile.file_stock_base .. ", 'w') failed: " .. err)
  165. end
  166. end
  167. --function load items_base from file
  168. function minercantile.load_stock_base()
  169. local file = io.open(minercantile.file_stock_base, "r")
  170. if file then
  171. local data = minetest.deserialize(file:read("*all"))
  172. file:close()
  173. if data and type(data) == "table" then
  174. minercantile.stock_base = table.copy(data)
  175. if minercantile.stock_base.money then
  176. minercantile.stock.money = minercantile.stock_base.money
  177. end
  178. if minercantile.stock_base.items then
  179. for itname, def in pairs(minercantile.stock_base.items) do
  180. minercantile.stock.items[itname] = table.copy(def)
  181. end
  182. end
  183. end
  184. end
  185. end
  186. --function save stock items
  187. function minercantile.save_stock()
  188. local input, err = io.open(minercantile.file_stock, "w")
  189. if input then
  190. input:write(minetest.serialize(minercantile.stock))
  191. input:close()
  192. else
  193. minetest.log("error", "open(" .. minercantile.file_stock .. ", 'w') failed: " .. err)
  194. end
  195. end
  196. --function load stock items from file
  197. function minercantile.load_stock()
  198. local file = io.open(minercantile.file_stock, "r")
  199. if file then
  200. local data = minetest.deserialize(file:read("*all"))
  201. file:close()
  202. if data and type(data) == "table" then
  203. if data.money then
  204. minercantile.stock.money = data.money
  205. end
  206. if data.items then
  207. for itname, def in pairs(data.items) do
  208. minercantile.stock.items[itname] = table.copy(def)
  209. end
  210. end
  211. if data.transac_b then
  212. minercantile.stock.transac_b = data.transac_b
  213. end
  214. if data.transac_s then
  215. minercantile.stock.transac_s = data.transac_s
  216. end
  217. end
  218. end
  219. end
  220. --create list items for formspec (search/pages)
  221. function minercantile.shop.set_items_buy_list(name, shop_type)
  222. shop_buy[name] = {page=1, search="", shop_type=shop_type}
  223. shop_buy[name].items_type = {}
  224. if minercantile.shop.shop[shop_type] then
  225. for _, itname in ipairs(minercantile.shop.shop[shop_type]) do
  226. if minercantile.shop.is_available(itname) and minercantile.shop.get_nb(itname) > 0 then
  227. table.insert(shop_buy[name].items_type, itname)
  228. end
  229. end
  230. table.sort(shop_buy[name].items_type)
  231. end
  232. end
  233. -- sell fonction
  234. function minercantile.shop.get_buy_price(shop_type, itname)
  235. local price
  236. local money = minercantile.shop.get_money()
  237. if not minercantile.stock.items[itname] then
  238. minercantile.stock.items[itname] = {nb=0}
  239. end
  240. local nb = minercantile.stock.items[itname].nb
  241. if minercantile.stock.items[itname].price ~= nil then -- if defined price
  242. price = math.ceil(minercantile.stock.items[itname].price)
  243. else
  244. price = math.ceil((money/1000)/((0.001*(2340+nb-99))^3.9)/13) -- was price = math.ceil((money/1000)/(math.log(nb+2000-99)*10)*1000000/(math.pow((nb+2000-99),(2.01))))
  245. end
  246. if price and shop_type ~= "General" then--specific shop sell -10%
  247. local pct = math.ceil((price * 10)/100)
  248. price = math.ceil(price - pct)
  249. end
  250. if price and price < 1 then price = 1 end
  251. return price
  252. end
  253. -- sell fonction
  254. function minercantile.shop.get_sell_price(itname, wear)
  255. local price
  256. local money = minercantile.shop.get_money()
  257. if not minercantile.stock.items[itname] then
  258. minercantile.stock.items[itname] = {nb=0}
  259. end
  260. local nb = minercantile.stock.items[itname].nb
  261. if minercantile.stock.items[itname].price ~= nil then -- if defined price
  262. price = math.floor(minercantile.stock.items[itname].price)
  263. else
  264. price = math.floor((money/1000)/((0.001*(2340+nb+99))^3.9)/13) --was price = math.floor(((money/1000)/(math.log(nb+2000+99)*10)*1000000/(math.pow((nb+2000+99),(2.01))))+0.5)
  265. end
  266. if wear and wear > 0 then --calcul price with % wear, (0-65535)
  267. local pct = math.ceil(((65535-wear)*100)/65535)
  268. price = math.floor((price * pct)/100)
  269. end
  270. if price < 1 then price = 1 end
  271. return price
  272. end
  273. local function set_pages_by_search(name, search)
  274. shop_buy[name].page = 1
  275. shop_buy[name].search = minetest.formspec_escape(search)
  276. shop_buy[name].items_list = {}
  277. for _, itname in ipairs(shop_buy[name].items_type) do
  278. if minercantile.shop.get_nb(itname) > 0 then
  279. local item = minercantile.registered_items[itname]
  280. if item then
  281. if string.find(itname, search) or string.find(string.lower(item.desc), search) then
  282. table.insert(shop_buy[name].items_list, itname)
  283. end
  284. end
  285. end
  286. end
  287. table.sort(shop_buy[name].items_list)
  288. end
  289. local function get_shop_inventory_by_page(name)
  290. local page = shop_buy[name].page
  291. local search = shop_buy[name].search
  292. local nb_items, nb_pages
  293. local shop_type = shop_buy[name].shop_type or "General"
  294. local inv_list = {}
  295. if search ~= "" then
  296. nb_items = #shop_buy[name].items_list
  297. nb_pages = math.ceil(nb_items/32)
  298. if page > nb_pages then page = nb_pages end
  299. local index = (page*32)-32
  300. for i=1, 32 do
  301. local itname = shop_buy[name].items_list[index+i]
  302. if not itname then break end
  303. local nb = minercantile.shop.get_nb(itname)
  304. if nb > 0 then
  305. local price = minercantile.shop.get_buy_price(shop_type, itname)
  306. if price and price > 0 then
  307. table.insert(inv_list, {name=itname, nb=nb, price=price})
  308. end
  309. end
  310. end
  311. else
  312. nb_items = #shop_buy[name].items_type
  313. nb_pages = math.ceil(nb_items/32)
  314. if page > nb_pages then page = nb_pages end
  315. local index = (page*32)-32
  316. for i=1, 32 do
  317. local itname = shop_buy[name].items_type[index+i]
  318. if itname then
  319. local nb = minercantile.shop.get_nb(itname)
  320. if nb > 0 then
  321. local price = minercantile.shop.get_buy_price(shop_type, itname)
  322. if price and price > 0 then
  323. table.insert(inv_list, {name=itname, nb=nb, price=price})
  324. end
  325. end
  326. end
  327. end
  328. end
  329. shop_buy[name].nb_pages = nb_pages
  330. return inv_list
  331. end
  332. --buy
  333. function minercantile.shop.buy(name, itname, nb, price)
  334. local player = minetest.get_player_by_name(name)
  335. if not player then return false end
  336. local player_inv = player:get_inventory()
  337. local player_money = minercantile.wallet.get_money(name)
  338. if player_money < 1 then
  339. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1,1;Sorry, you have not enough money]button[1.3,2.1;1.5,1;return_buy;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  340. return false
  341. end
  342. local items_nb = minercantile.stock.items[itname].nb
  343. if items_nb < 1 then
  344. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1,1;Sorry, shop have 0 item ".. itname.."]button[1.3,2.1;1.5,1;return_buy;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  345. return false
  346. end
  347. local item_can_sell = nb
  348. if items_nb < 4 then
  349. item_can_sell = 1
  350. elseif items_nb/4 < nb then
  351. item_can_sell = math.floor(items_nb/4)
  352. end
  353. local price_total = math.floor(item_can_sell * price)
  354. local player_can_buy = item_can_sell
  355. if player_money < price_total then
  356. player_can_buy = math.floor(player_money/price)
  357. end
  358. local sell_price = player_can_buy * price
  359. local stack = ItemStack(itname.." "..player_can_buy)
  360. --player_inv:room_for_item("main", stack)
  361. local nn = player_inv:add_item("main", stack)
  362. local count = nn:get_count()
  363. if count > 0 then
  364. minetest.spawn_item(player:getpos(), {name=itname, count=count, wear=0, metadata=""})
  365. end
  366. minercantile.stock.items[itname].nb = minercantile.stock.items[itname].nb - player_can_buy
  367. minercantile.shop.set_transac_b()
  368. minercantile.shop.give_money(sell_price, true)
  369. minercantile.wallet.take_money(name, sell_price, " Buy "..player_can_buy .." "..itname..", price "..sell_price)
  370. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1.3,0.8;You buy "..player_can_buy .." "..itname.."]label[1.3,1.3;price "..sell_price.."$]button[1.3,2.1;1.5,1;return_buy;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  371. return true
  372. end
  373. local function show_formspec_to_buy(name)
  374. local player = minetest.get_player_by_name(name)
  375. if not player or not shop_buy[name] then return end
  376. local formspec = {"size[13,10]bgcolor[#2A2A2A;]label[6,0;Buy Items]"}
  377. table.insert(formspec, "label[0,0;Your money:"..minercantile.wallet.get_money(name) .."$]")
  378. local inv_items = get_shop_inventory_by_page(name)
  379. table.insert(formspec, "label[0.8,1.4;Page: ".. shop_buy[name].page.." of ".. shop_buy[name].nb_pages.."]")
  380. if shop_buy[name].search ~= "" then
  381. table.insert(formspec, "label[3,1.4;Filter: ".. minetest.formspec_escape(shop_buy[name].search) .."]")
  382. end
  383. local x = 0.8
  384. local y = 2
  385. local j = 1
  386. for i=1, 32 do
  387. local item = inv_items[i]
  388. if item then
  389. table.insert(formspec, "item_image_button["..x..","..y..";1,1;"..item.name..";buttonchoice_"..item.name..";"..item.nb.."]")
  390. table.insert(formspec, "label["..(x)..","..(y+0.8)..";"..item.price.."$]")
  391. else
  392. table.insert(formspec, "image["..x..","..y..";1,1;minercantile_img_inv.png]")
  393. end
  394. x = x +1.5
  395. j = j +1
  396. if j > 8 then
  397. j = 1
  398. x = 0.8
  399. y = y + 1.6
  400. end
  401. end
  402. table.insert(formspec, "field[5.75,8.75;2.2,1;searchbox;;]")
  403. table.insert(formspec, "image_button[7.55,8.52;.8,.8;ui_search_icon.png;searchbutton;]tooltip[searchbutton;Search]")
  404. table.insert(formspec, "button[5.65,9.3;1,1;page_dec;<]")
  405. table.insert(formspec, "button[6.55,9.3;1,1;page_inc;>]")
  406. table.insert(formspec, "button_exit[11,9.3;1.5,1;choice;Close]")
  407. minetest.show_formspec(name, "minercantile:shop_buy", table.concat(formspec))
  408. end
  409. local function get_formspec_buy_items(name)
  410. local itname = shop_buy[name].itname
  411. local nb = shop_buy[name].nb
  412. local price = shop_buy[name].price
  413. local formspec = {"size[8,6]bgcolor[#2A2A2A;]label[3.5,0;Buy Items]"}
  414. table.insert(formspec, "label[3.4,1;Stock:"..minercantile.shop.get_nb(itname).."]")
  415. table.insert(formspec, "item_image_button[3.6,1.5;1,1;"..itname..";buttonchoice_"..itname..";"..nb.."]")
  416. if minetest.registered_items[itname] and minetest.registered_items[itname].stack_max and minetest.registered_items[itname].stack_max == 1 then
  417. table.insert(formspec, "label[2.2,2.5;This item is being sold by 1 max]")
  418. else
  419. table.insert(formspec, "button[0.6,1.5;1,1;amount;-1]")
  420. table.insert(formspec, "button[1.6,1.5;1,1;amount;-10]")
  421. table.insert(formspec, "button[2.6,1.5;1,1;amount;-20]")
  422. table.insert(formspec, "button[4.6,1.5;1,1;amount;+20]")
  423. table.insert(formspec, "button[5.6,1.5;1,1;amount;+10]")
  424. table.insert(formspec, "button[6.6,1.5;1,1;amount;+1]")
  425. end
  426. table.insert(formspec, "label[3.2,3;Price:"..price.."$]")
  427. table.insert(formspec, "label[3.2,3.4;Amount:".. nb.." items]")
  428. table.insert(formspec, "label[3.2,3.8;Total:"..nb * price.."$]")
  429. table.insert(formspec, "button[3.3,5;1.5,1;confirm;Confirm]")
  430. table.insert(formspec, "button[0,0;1.5,1;abort;Return]")
  431. return table.concat(formspec)
  432. end
  433. -- sell
  434. function minercantile.shop.player_sell(name)
  435. local player = minetest.get_player_by_name(name)
  436. if not player then return false end
  437. local player_inv = player:get_inventory()
  438. local shop_money = minercantile.shop.get_money()
  439. if shop_money < 4 then
  440. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1,1;Sorry, shop have not enough money]button[1.3,2.1;1.5,1;return_sell;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  441. return false
  442. end
  443. local item = shop_sell[name].item
  444. local index = item.index
  445. local nb = shop_sell[name].nb
  446. local price = shop_sell[name].price
  447. local stack = player_inv:get_stack("main", index)
  448. local itname = stack:get_name()
  449. local items_nb = stack:get_count()
  450. if itname ~= item.name or items_nb == 0 then
  451. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1.5,1;Sorry, You have 0 item ..".. itname.."]button[1.3,2.1;1.5,1;return_sell;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  452. return false
  453. end
  454. local item_can_sell = nb
  455. if items_nb < nb then
  456. item_can_sell = items_nb
  457. end
  458. local price_total = math.floor(item_can_sell * price)
  459. local shop_can_buy = item_can_sell
  460. if (shop_money/4) < price_total then
  461. shop_can_buy = math.floor((shop_money/4)/price)
  462. end
  463. if shop_can_buy == 0 then
  464. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1,1;Sorry, shop have not enough money]button[1.3,2.1;1.5,1;return_sell;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  465. return false
  466. end
  467. local taken = stack:take_item(shop_can_buy)
  468. local sell_price = math.floor((taken:get_count()) * price)
  469. player_inv:set_stack("main", index, stack)
  470. minercantile.stock.items[itname].nb = minercantile.stock.items[itname].nb + shop_can_buy
  471. minercantile.shop.set_transac_s()
  472. minercantile.shop.take_money(sell_price, true)
  473. minercantile.wallet.give_money(name, sell_price, " Sell "..shop_can_buy .." "..itname..", price "..sell_price)
  474. minetest.show_formspec(name, "minercantile:confirmed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1.3,0.8;You sell "..shop_can_buy .." "..itname.."]label[1.3,1.3;price "..sell_price.."$]button[1.3,2.1;1.5,1;return_sell;Return]button_exit[3.3,2.1;1.5,1;close;Close]")
  475. return true
  476. end
  477. local function get_wear_img(wear)
  478. local pct = math.floor(((65535-wear)*10)/65535)
  479. for i=9, 0, -1 do
  480. if pct == i then
  481. return "minercantile_wear_".. i ..".png"
  482. end
  483. end
  484. return nil
  485. end
  486. -- show sell formspec
  487. local function show_formspec_to_sell(name)
  488. local player = minetest.get_player_by_name(name)
  489. if not player then return end
  490. local formspec = {"size[13,10]bgcolor[#2A2A2A;]label[6,0;Sell Items]"}
  491. table.insert(formspec, "label[0,0;Your money:"..minercantile.wallet.get_money(name) .."$]")
  492. local player_inv = player:get_inventory()
  493. shop_sell[name] = {}
  494. shop_sell[name].items = {}
  495. for i=1, player_inv:get_size("main") do
  496. local stack = player_inv:get_stack("main", i)
  497. if not stack:is_empty() then
  498. local itname = stack:get_name()
  499. if minercantile.shop.is_available(itname) and minercantile.shop.get_nb(itname) < minercantile.shop.max_stock then
  500. local nb = stack:get_count()
  501. local wear = stack:get_wear()
  502. local price = minercantile.shop.get_sell_price(itname, wear)
  503. if price and price > 0 then
  504. table.insert(shop_sell[name].items, {name=itname, nb=nb, price=price, index=i, wear=wear})
  505. end
  506. end
  507. end
  508. end
  509. local x = 0.8
  510. local y = 2
  511. local j = 1
  512. for i=1, 32 do
  513. local item = shop_sell[name].items[i]
  514. if item then
  515. table.insert(formspec, "item_image_button["..x..","..y..";1,1;"..item.name..";buttonchoice_"..i..";"..item.nb.."]")
  516. table.insert(formspec, "label["..(x)..","..(y+0.9)..";"..item.price.."$]")
  517. if item.wear and item.wear > 0 then
  518. local img = get_wear_img(item.wear)
  519. if img then
  520. table.insert(formspec, "image["..x..","..(y+0.1)..";1,1;"..img.."]")
  521. end
  522. end
  523. else
  524. table.insert(formspec, "image["..x..","..y..";1,1;minercantile_img_inv.png]")
  525. end
  526. x = x +1.5
  527. j = j + 1
  528. if j > 8 then
  529. j = 1
  530. x = 0.8
  531. y = y + 1.6
  532. end
  533. end
  534. table.insert(formspec, "button_exit[5.8,9.3;1.5,1;choice;Close]")
  535. minetest.show_formspec(name, "minercantile:shop_sell", table.concat(formspec))
  536. end
  537. local function get_formspec_sell_items(name)
  538. local item = shop_sell[name].item
  539. local itname = item.name
  540. local index = shop_sell[name].index
  541. local nb = shop_sell[name].nb
  542. local price = minercantile.shop.get_sell_price(itname, item.wear)
  543. shop_sell[name].price = price
  544. local formspec = {"size[8,6]bgcolor[#2A2A2A;]label[3.5,0;Sell Items]"}
  545. table.insert(formspec, "item_image_button[3.6,1.5;1,1;"..itname..";buttonchoice_"..index..";"..nb.."]")
  546. if item.wear and item.wear > 0 then
  547. local img = get_wear_img(item.wear)
  548. if img then
  549. table.insert(formspec, "image[3.6,1.6;1,1;"..img.."]")
  550. end
  551. end
  552. if minetest.registered_items[itname] and minetest.registered_items[itname].stack_max and minetest.registered_items[itname].stack_max == 1 then
  553. table.insert(formspec, "label[2.2,2.5;This item is being sold by 1 max]")
  554. else
  555. table.insert(formspec, "button[0.6,1.5;1,1;amount;-1]")
  556. table.insert(formspec, "button[1.6,1.5;1,1;amount;-10]")
  557. table.insert(formspec, "button[2.6,1.5;1,1;amount;-20]")
  558. table.insert(formspec, "button[4.6,1.5;1,1;amount;+20]")
  559. table.insert(formspec, "button[5.6,1.5;1,1;amount;+10]")
  560. table.insert(formspec, "button[6.6,1.5;1,1;amount;+1]")
  561. end
  562. table.insert(formspec, "label[3.2,3;Price:"..price.."$]")
  563. table.insert(formspec, "label[3.2,3.4;Amount:".. nb.." items]")
  564. table.insert(formspec, "label[3.2,3.8;Total:"..nb * price.."$]")
  565. table.insert(formspec, "button[3.3,5;1.5,1;confirm;Confirm]")
  566. table.insert(formspec, "button[0,0;1.5,1;abort;Return]")
  567. return table.concat(formspec)
  568. end
  569. local function get_formspec_welcome(name)
  570. local formspec = {"size[6,5]bgcolor[#2A2A2A;]label[2.6,0;Shop]"}
  571. table.insert(formspec, "image[1,1;5,1.25;minercantile_shop_welcome.png]")
  572. table.insert(formspec, "label[1,2.5;Total purchases: "..minercantile.shop.get_transac_b().."]")
  573. table.insert(formspec, "label[1,3;Total sales: "..minercantile.shop.get_transac_s().."]")
  574. table.insert(formspec, "button[1,4.3;1.5,1;choice;Buy]")
  575. table.insert(formspec, "button[3.5,4.3;1.5,1;choice;Sell]")
  576. return table.concat(formspec)
  577. end
  578. -- formspec admin shop
  579. function minercantile.get_formspec_shop_admin_shop(pos, node_name, name)
  580. if not shop_admin[name] then
  581. shop_admin[name] = {}
  582. end
  583. shop_admin[name].pos = pos
  584. shop_admin[name].node_name = node_name
  585. local formspec = {"size[6,6]bgcolor[#2A2A2A;]label[2.2,0;Shop Admin]button[4.5,0;1.5,1;shop;Shop]"}
  586. local isnode = minetest.get_node_or_nil(pos)
  587. if not isnode or isnode.name ~= node_name then return end
  588. local meta = minetest.get_meta(pos)
  589. local shop_type = meta:get_int("shop_type")
  590. table.insert(formspec, "label[1,1;Shop Type:]")
  591. table.insert(formspec, "dropdown[3,1;3,1;select_type;"..table.concat(minercantile.shop.shop_type, ",")..";"..shop_type.."]")
  592. local isopen = meta:get_int("open")
  593. if isopen == 1 then
  594. table.insert(formspec, "label[1,2;Is Open: Yes]button[3.5,1.8;1.5,1;open_close;No]")
  595. else
  596. table.insert(formspec, "label[1,2;Is Open: No]button[3.5,1.8;1.5,1;open_close;Yes]")
  597. end
  598. local always_open = meta:get_int("always_open")
  599. if always_open == 1 then
  600. table.insert(formspec, "label[1,3;Open 24/24: Yes]button[3.5,2.8;1.5,1;always_open;No]")
  601. else
  602. table.insert(formspec, "label[1,3;Open 24/24: No]button[3.5,2.8;1.5,1;always_open;Yes]")
  603. end
  604. table.insert(formspec, "label[1,4;Shop money:"..minercantile.shop.get_money().."$]")
  605. table.insert(formspec, "button_exit[2.4,5.3;1.5,1;close;Close]")
  606. return table.concat(formspec)
  607. end
  608. minetest.register_on_player_receive_fields(function(player, formname, fields)
  609. local name = player:get_player_name()
  610. if not name or name == "" then return end
  611. if formname == "minercantile:shop_welcome" then
  612. if fields["choice"] then
  613. if fields["choice"] == "Buy" then
  614. show_formspec_to_buy(name)
  615. elseif fields["choice"] == "Sell" then
  616. show_formspec_to_sell(name)
  617. end
  618. return
  619. end
  620. elseif formname == "minercantile:shop_buy" then
  621. for b, n in pairs(fields) do
  622. if string.find(b, "buttonchoice_") then
  623. if not shop_buy[name] then return end
  624. local itname = string.sub(b, 14)
  625. shop_buy[name].itname = itname
  626. shop_buy[name].max = math.floor(minercantile.shop.get_nb(itname)/4)
  627. if minetest.registered_items[itname].stack_max and minetest.registered_items[itname].stack_max == 1 then
  628. shop_buy[name].max = 1
  629. shop_buy[name].nb = 1
  630. else
  631. shop_buy[name].max = math.floor(minercantile.shop.get_nb(itname)/4)
  632. shop_buy[name].nb = math.floor(minercantile.shop.get_nb(itname)/4)
  633. end
  634. if shop_buy[name].max > 99 then
  635. shop_buy[name].max = 99
  636. end
  637. if shop_buy[name].nb < 1 then
  638. shop_buy[name].nb = 1
  639. elseif shop_buy[name].nb > 99 then
  640. shop_buy[name].nb = 99
  641. end
  642. local shop_type = shop_buy[name].shop_type or "General"
  643. shop_buy[name].price = minercantile.shop.get_buy_price(shop_type, itname)
  644. minetest.show_formspec(name, "minercantile:shop_buy_items", get_formspec_buy_items(name))
  645. return
  646. end
  647. end
  648. if fields["quit"] then
  649. return
  650. elseif fields["searchbutton"] then
  651. local search = string.sub(string.lower(fields["searchbox"]), 1, 14)
  652. set_pages_by_search(name, search)
  653. elseif fields["page_inc"] then
  654. if shop_buy[name].page < shop_buy[name].nb_pages then
  655. shop_buy[name].page = shop_buy[name].page+1
  656. end
  657. elseif fields["page_dec"] then
  658. if shop_buy[name].page > 1 then
  659. shop_buy[name].page = shop_buy[name].page-1
  660. end
  661. end
  662. show_formspec_to_buy(name)
  663. elseif formname == "minercantile:shop_buy_items" then
  664. if fields["amount"] then
  665. local inc = tonumber(fields["amount"])
  666. if inc ~= nil then
  667. shop_buy[name].nb = shop_buy[name].nb + inc
  668. end
  669. if shop_buy[name].nb > 99 then
  670. shop_buy[name].nb = 99
  671. end
  672. if shop_buy[name].nb > shop_buy[name].max then
  673. shop_buy[name].nb = shop_buy[name].max
  674. end
  675. if shop_buy[name].nb < 1 then
  676. shop_buy[name].nb = 1
  677. end
  678. elseif fields["abort"] then
  679. show_formspec_to_buy(name)
  680. return
  681. elseif fields["confirm"] then
  682. if not shop_buy[name] or not shop_buy[name].itname or not shop_buy[name].nb or not shop_buy[name].price then return end
  683. minercantile.shop.buy(name, shop_buy[name].itname, shop_buy[name].nb, shop_buy[name].price)
  684. return
  685. elseif fields["quit"] then
  686. shop_buy[name] = nil
  687. return
  688. end
  689. minetest.show_formspec(name, "minercantile:shop_buy_items", get_formspec_buy_items(name))
  690. elseif formname == "minercantile:shop_sell" then
  691. for b, n in pairs(fields) do
  692. if string.find(b, "buttonchoice_") then
  693. if not shop_sell[name] then
  694. shop_sell[name] = {}
  695. end
  696. local index = tonumber(string.sub(b, 14))
  697. shop_sell[name].index = index
  698. local item = shop_sell[name].items[index]
  699. shop_sell[name].item = item
  700. shop_sell[name].itname = item.name
  701. shop_sell[name].max = item.nb
  702. if shop_sell[name].max > 99 then
  703. shop_sell[name].max = 99
  704. end
  705. shop_sell[name].wear = item.wear
  706. shop_sell[name].nb = shop_sell[name].max
  707. shop_sell[name].price = minercantile.shop.get_sell_price(item.name, item.wear)
  708. minetest.show_formspec(name, "minercantile:shop_sell_items", get_formspec_sell_items(name))
  709. break
  710. end
  711. end
  712. return
  713. elseif formname == "minercantile:shop_sell_items" then
  714. if fields["amount"] then
  715. local inc = tonumber(fields["amount"])
  716. if inc ~= nil then
  717. shop_sell[name].nb = shop_sell[name].nb + inc
  718. end
  719. if shop_sell[name].nb > shop_sell[name].max then
  720. shop_sell[name].nb = shop_sell[name].max
  721. end
  722. if shop_sell[name].nb > 99 then
  723. shop_sell[name].nb = 99
  724. end
  725. if shop_sell[name].nb < 1 then
  726. shop_sell[name].nb = 1
  727. end
  728. elseif fields["abort"] then
  729. show_formspec_to_sell(name)
  730. return
  731. elseif fields["confirm"] then
  732. minercantile.shop.player_sell(name)
  733. return
  734. elseif fields["quit"] then
  735. shop_sell[name] = nil
  736. return
  737. end
  738. minetest.show_formspec(name, "minercantile:shop_sell_items", get_formspec_sell_items(name))
  739. elseif formname == "minercantile:confirmed" then
  740. if fields["return_sell"] then
  741. show_formspec_to_sell(name)
  742. elseif fields["return_buy"] then
  743. show_formspec_to_buy(name)
  744. end
  745. -- admin conf
  746. elseif formname == "minercantile:shop_admin_shop" then
  747. if fields["quit"] then
  748. shop_admin[name] = nil
  749. return
  750. elseif fields["shop"] then
  751. minetest.show_formspec(name, "minercantile:shop_welcome", get_formspec_welcome(name))
  752. return
  753. end
  754. if not shop_admin[name] then return end
  755. local pos = shop_admin[name].pos
  756. local node_name = shop_admin[name].node_name
  757. local isnode = minetest.get_node_or_nil(pos)
  758. if not isnode or isnode.name ~= node_name then return end --FIXME
  759. local meta = minetest.get_meta(pos)
  760. if fields["open_close"] then
  761. local open = 0
  762. if fields["open_close"] == "Yes" then
  763. open = 1
  764. end
  765. meta:set_int("open", open)
  766. elseif fields["always_open"] then
  767. local always_open = 0
  768. if fields["always_open"] == "Yes" then
  769. always_open = 1
  770. end
  771. meta:set_int("always_open", always_open)
  772. elseif fields["select_type"] then
  773. for i, n in pairs(minercantile.shop.shop_type) do
  774. if n == fields["select_type"] then
  775. meta:set_int("shop_type", i)
  776. local t = string.gsub(n, "_$","")
  777. meta:set_string("infotext", t.." Shop")
  778. break
  779. end
  780. end
  781. end
  782. minetest.show_formspec(name, "minercantile:shop_admin_shop", minercantile.get_formspec_shop_admin_shop(pos, node_name, name))
  783. end
  784. end)
  785. --Barter shop.
  786. minetest.register_node("minercantile:shop", {
  787. description = "Barter Shop",
  788. tiles = {"minercantile_shop.png"},
  789. groups = {snappy=2,choppy=2,oddly_breakable_by_hand=2},
  790. sounds = default.node_sound_wood_defaults(),
  791. paramtype2 = "facedir",
  792. drawtype = "mesh",
  793. mesh = "minercantile_shop.obj",
  794. paramtype = "light",
  795. on_construct = function(pos)
  796. local meta = minetest.get_meta(pos)
  797. meta:set_string("infotext", "General Shop")
  798. meta:set_int("open", 1)
  799. meta:set_int("always_open", 0)
  800. meta:set_int("shop_type", 1)
  801. end,
  802. can_dig = function(pos, player)
  803. local name = player:get_player_name()
  804. return (minetest.check_player_privs(name, {protection_bypass = true}) or minetest.check_player_privs(name, {shop = true}))
  805. end,
  806. on_rightclick = function(pos, node, player, itemstack, pointed_thing)
  807. local name = player:get_player_name()
  808. if not name or name == "" then return end
  809. local meta = minetest.get_meta(pos)
  810. local shop_type = minercantile.shop.shop_type[meta:get_int("shop_type")] or "General"
  811. minercantile.shop.set_items_buy_list(name, shop_type)
  812. if minetest.check_player_privs(name, {protection_bypass = true}) or minetest.check_player_privs(name, {shop = true}) then
  813. minetest.show_formspec(name, "minercantile:shop_admin_shop", minercantile.get_formspec_shop_admin_shop(pos, node.name, name))
  814. else
  815. local isopen = meta:get_int("open")
  816. if (isopen and isopen == 1) then
  817. local always_open = meta:get_int("always_open")
  818. local tod = (minetest.get_timeofday() or 0) * 24000
  819. if always_open == 1 or (tod > 8000 and tod < 19000) then --FIXME check tod 8h-19h
  820. minetest.show_formspec(name, "minercantile:shop_welcome", get_formspec_welcome(name))
  821. else
  822. minetest.show_formspec(name, "minercantile:closed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1.2,1;Sorry shop is only open 8h-19h]button_exit[2.3,2.1;1.5,1;close;Close]")
  823. end
  824. else
  825. minetest.show_formspec(name, "minercantile:closed", "size[6,3]bgcolor[#2A2A2A;]label[2.6,0;Shop]label[1.7,1;Sorry shop is closed]button_exit[2.3,2.1;1.5,1;close;Close]")
  826. end
  827. end
  828. end,
  829. })
  830. minetest.register_chatcommand("shop_addmoney",{
  831. params = "money",
  832. description = "give money to the shop",
  833. privs = {shop = true},
  834. func = function(name, param)
  835. param = string.gsub(param, " ", "")
  836. local amount = tonumber(param)
  837. if amount == nil then
  838. minetest.chat_send_player(name, "invalid, you must add amount at param")
  839. return
  840. end
  841. minercantile.shop.give_money(amount, true)
  842. minetest.chat_send_player(name, "you add "..amount.. ", new total:".. minercantile.shop.get_money())
  843. end,
  844. })
  845. minetest.register_chatcommand("shop_delmoney",{
  846. params = "money",
  847. description = "del money from the shop",
  848. privs = {shop = true},
  849. func = function(name, param)
  850. param = string.gsub(param, " ", "")
  851. local amount = tonumber(param)
  852. if (amount == nil ) then
  853. minetest.chat_send_player(name, "invalid, you must add amount at param")
  854. return
  855. end
  856. minercantile.shop.take_money(amount, true)
  857. minetest.chat_send_player(name, "you delete "..amount.. ", new total:".. minercantile.shop.get_money())
  858. end,
  859. })
  860. minetest.register_chatcommand("shop_additem",{
  861. params = "name number",
  862. description = "give item to the shop",
  863. privs = {shop = true},
  864. func = function(name, param)
  865. if ( param == nil ) then
  866. minetest.chat_send_player(name, "invalid, no param")
  867. return
  868. end
  869. local itname, amount = param:match("^(%S+)%s(%S+)$")
  870. if itname == nil then
  871. minetest.chat_send_player(name, "invalid param item")
  872. return
  873. end
  874. if not minercantile.shop.is_available(itname) then
  875. minetest.chat_send_player(name, "invalid param item unknow")
  876. return
  877. end
  878. if amount == nil or not tonumber(amount) then
  879. minetest.chat_send_player(name, "invalid param amount")
  880. return
  881. end
  882. amount = tonumber(amount)
  883. if amount < 1 then
  884. minetest.chat_send_player(name, "invalid param amount")
  885. return
  886. end
  887. minercantile.shop.add_item(itname, amount)
  888. minetest.chat_send_player(name, "you add "..amount.. " items, new total:".. minercantile.shop.get_nb(itname))
  889. end,
  890. })
  891. minetest.register_chatcommand("shop_delitem",{
  892. params = "name number",
  893. description = "del item from the shop",
  894. privs = {shop = true},
  895. func = function(name, param)
  896. if ( param == nil ) then
  897. minetest.chat_send_player(name, "invalid, no param")
  898. return
  899. end
  900. local itname, amount = param:match("^(%S+)%s(%S+)$")
  901. if itname == nil then
  902. minetest.chat_send_player(name, "invalid param item")
  903. return
  904. end
  905. if not minercantile.shop.is_available(itname) then
  906. minetest.chat_send_player(name, "invalid param item unknow")
  907. return
  908. end
  909. if amount == nil or not tonumber(amount) then
  910. minetest.chat_send_player(name, "invalid param amount")
  911. return
  912. end
  913. amount = tonumber(amount)
  914. if amount < 1 then
  915. minetest.chat_send_player(name, "invalid param amount")
  916. return
  917. end
  918. minercantile.shop.del_item(itname, amount)
  919. minetest.chat_send_player(name, "you delete "..amount.. " items, new total:".. minercantile.shop.get_nb(itname))
  920. end,
  921. })