chatcommands.lua 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. --- Minetest API method. Adds definition to minetest.registered_chatcommands.
  2. -- @param cmd the string - commnad name
  3. -- @param chatcommand definition the table
  4. minetest.register_chatcommand("mp", {
  5. params = "<command> [<item name> <amount>]",
  6. description = "Marketplace commands, type '/mp help' for more help.",
  7. privs = { interact = true },
  8. func = function(caller, param)
  9. local params = {}
  10. for substring in param:gmatch("%S+") do
  11. table.insert(params, substring)
  12. end
  13. -- print("caller", dump(caller))
  14. -- print("params", dump(params))
  15. --
  16. -- find
  17. --
  18. if params[1] == "find" then
  19. -- item name is missing from param[2]
  20. if not params[2] then
  21. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You need to write the item name you want to find. example: /mp find default:stone. See some suggestion from the store: ")..x_marketplace.store_get_random()
  22. end
  23. local items = x_marketplace.store_find(params[2])
  24. if not items then
  25. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: Oops there is no item like this in the store. Check out other items in the store: ")..x_marketplace.store_get_random()
  26. end
  27. return true, minetest.colorize(x_marketplace.colors.cyan, items)
  28. --
  29. -- show balance
  30. --
  31. elseif params[1] == "balance" then
  32. local balance = x_marketplace.get_player_balance(caller)
  33. -- check for number sanity, positive number
  34. if not balance or
  35. x_marketplace.isnan(balance) or
  36. not x_marketplace.isfinite(balance) then
  37. local player = minetest.get_player_by_name(caller)
  38. player:set_attribute("balance", 0)
  39. balance = 0
  40. end
  41. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: Your balance is: "..balance.." BitGold")
  42. --
  43. -- sell hand
  44. --
  45. elseif params[1] == "sellhand" then
  46. local player = minetest.get_player_by_name(caller)
  47. local player_pos = player:get_pos()
  48. local find_signs = x_marketplace.find_signs(player:get_pos(), "/mp sell", "x_marketplace:sign_wall_mese")
  49. if not find_signs then
  50. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: There are no Mese Signs around you with text '/mp sell' on them. Transaction cancelled.")
  51. end
  52. local hand = player:get_wielded_item()
  53. local item_name = hand:get_name()
  54. local store_item = x_marketplace.store_list[item_name]
  55. -- item exists in the store
  56. if store_item then
  57. local item_count = hand:get_count()
  58. local itemstack = ItemStack(item_name)
  59. -- check for number sanity, positive number
  60. if x_marketplace.isnan(item_count) or
  61. not x_marketplace.isfinite(item_count) then
  62. item_count = 1
  63. end
  64. if item_count > itemstack:get_stack_max() then
  65. item_count = itemstack:get_stack_max()
  66. end
  67. local sell_price = store_item.sell * item_count
  68. local new_balance, msg = x_marketplace.set_player_balance(caller, sell_price)
  69. if msg == "above" then
  70. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You will go above the maximum balance if you sell this item. Transaction cancelled.")
  71. end
  72. player:set_wielded_item(ItemStack(""))
  73. minetest.sound_play("x_marketplace_gold", {
  74. object = player,
  75. max_hear_distance = 10,
  76. gain = 1.0
  77. })
  78. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You sold "..item_count.." item(s) of "..item_name.." for "..sell_price.." BitGold. Your new balance is: "..new_balance.." BitGold")
  79. else
  80. -- item does not exists in the store
  81. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: ")..x_marketplace.store_get_random()
  82. end
  83. --
  84. -- info hand
  85. --
  86. elseif params[1] == "infohand" then
  87. local player = minetest.get_player_by_name(caller)
  88. local hand = player:get_wielded_item()
  89. local item_name = hand:get_name()
  90. local item_count = hand:get_count()
  91. local store_item = x_marketplace.store_list[item_name]
  92. -- item exists in the store
  93. if store_item then
  94. local itemstack = ItemStack(item_name)
  95. if item_count > itemstack:get_stack_max() then
  96. item_count = itemstack:get_stack_max()
  97. end
  98. local sell_price = store_item.sell * item_count
  99. return true, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: "..item_name.." buy: "..store_item.buy.." sell: "..store_item.sell..". You can sell the item(s) you are holding for: "..sell_price.." BitGold. example: /mp sellhand")
  100. else
  101. -- item does not exists in the store
  102. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: This item is not in store. See some suggestion from the store: ")..x_marketplace.store_get_random()
  103. end
  104. --
  105. -- buy hand
  106. --
  107. elseif params[1] == "buyhand" then
  108. local player = minetest.get_player_by_name(caller)
  109. local find_signs = x_marketplace.find_signs(player:get_pos(), "/mp buy", "x_marketplace:sign_wall_diamond")
  110. if not find_signs then
  111. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: There are no Diamond Signs around you with text '/mp buy' on them. Transaction cancelled.")
  112. end
  113. local hand = player:get_wielded_item()
  114. local item_name = hand:get_name()
  115. local store_item = x_marketplace.store_list[item_name]
  116. -- item exists in the store
  117. if store_item then
  118. local amount = tonumber(params[2])
  119. local inv = player:get_inventory("main")
  120. local itemstack = ItemStack(item_name)
  121. -- check for number sanity, positive number
  122. if not amount or
  123. x_marketplace.isnan(amount) or
  124. not x_marketplace.isfinite(amount) or
  125. amount <= 0 then
  126. amount = 1
  127. end
  128. if amount > itemstack:get_stack_max() then
  129. amount = itemstack:get_stack_max()
  130. end
  131. itemstack:set_count(amount)
  132. local buy_price = amount * store_item.buy
  133. local new_balance = x_marketplace.set_player_balance(caller, buy_price * -1)
  134. -- not enough money
  135. if not new_balance then
  136. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..item_name.." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold")
  137. end
  138. -- drop items what doesn't fit in the inventory
  139. local leftover_item = inv:add_item("main", itemstack)
  140. if leftover_item:get_count() > 0 then
  141. local p = table.copy(player:get_pos())
  142. p.y = p.y + 1.2
  143. local obj = minetest.add_item(p, leftover_item)
  144. if obj then
  145. local dir = player:get_look_dir()
  146. dir.x = dir.x * 2.9
  147. dir.y = dir.y * 2.9 + 2
  148. dir.z = dir.z * 2.9
  149. obj:set_velocity(dir)
  150. obj:get_luaentity().dropped_by = caller
  151. end
  152. end
  153. minetest.sound_play("x_marketplace_gold", {
  154. object = player,
  155. max_hear_distance = 10,
  156. gain = 1.0
  157. })
  158. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..item_name.." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold")
  159. else
  160. -- item does not exists in the store
  161. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: This item is not in store. See some suggestion from the store: ")..x_marketplace.store_get_random()
  162. end
  163. --
  164. -- sell inventory
  165. --
  166. elseif params[1] == "sellinv" then
  167. params[2] = x_marketplace.normalize_nodename(params[2])
  168. -- item name is missing from param[2]
  169. if not params[2] then
  170. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You need to write the item name you want to sell. example: /mp sellinv default:stone. See some suggestion from the store: ")..x_marketplace.store_get_random()
  171. end
  172. local player = minetest.get_player_by_name(caller)
  173. local find_signs = x_marketplace.find_signs(player:get_pos(), "/mp sell", "x_marketplace:sign_wall_mese")
  174. if not find_signs then
  175. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: There are no Mese Signs around you with text '/mp sell' on them. Transaction cancelled.")
  176. end
  177. local store_item = x_marketplace.store_list[params[2]]
  178. -- item exists in the store
  179. if store_item then
  180. local inv = player:get_inventory("main")
  181. local itemstack = ItemStack(params[2])
  182. local balance = x_marketplace.get_player_balance(caller)
  183. local amount = 0
  184. local over_max_balance = false
  185. for k, v in ipairs(inv:get_list("main")) do
  186. if v:get_name() == params[2] then
  187. local amount_to_remove = v:get_count()
  188. if amount_to_remove > itemstack:get_stack_max() then
  189. amount_to_remove = itemstack:get_stack_max()
  190. end
  191. amount = amount + amount_to_remove
  192. if (balance + amount * store_item.sell) > x_marketplace.max_balance then
  193. amount = amount - amount_to_remove
  194. over_max_balance = true
  195. break
  196. else
  197. inv:remove_item("main", v)
  198. end
  199. end
  200. end
  201. local sell_price = amount * store_item.sell
  202. local new_balance = x_marketplace.set_player_balance(caller, sell_price)
  203. if amount == 0 then
  204. return false, minetest.chat_send_player(caller, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You have nothing to sell in your inventory."))
  205. end
  206. if over_max_balance then
  207. minetest.chat_send_player(caller, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: We couldn't buy all your items without going above your maximum balance."))
  208. end
  209. minetest.sound_play("x_marketplace_gold", {
  210. object = player,
  211. max_hear_distance = 10,
  212. gain = 1.0
  213. })
  214. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You sold "..amount.." item(s) of "..params[2].." for "..sell_price.." BitGold. Your new balance is: "..x_marketplace.get_player_balance(caller).." BitGold")
  215. else
  216. -- item does not exists in the store
  217. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: ")..x_marketplace.store_get_random()
  218. end
  219. --
  220. -- buy inventory
  221. --
  222. elseif params[1] == "buyinv" then
  223. params[2] = x_marketplace.normalize_nodename(params[2])
  224. -- item name is missing from param[2]
  225. if not params[2] then
  226. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You need to write the item name you want to buy. example: /mp buyinv default:stone, or check out other items in the store: ")..x_marketplace.store_get_random()
  227. end
  228. local player = minetest.get_player_by_name(caller)
  229. local find_signs = x_marketplace.find_signs(player:get_pos(), "/mp buy", "x_marketplace:sign_wall_diamond")
  230. if not find_signs then
  231. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: There are no Diamond Signs around you with text '/mp buy' on them. Transaction cancelled.")
  232. end
  233. local store_item = x_marketplace.store_list[params[2]]
  234. if store_item then
  235. local itemstack = ItemStack(params[2])
  236. local inv = player:get_inventory("main")
  237. local amount = 0
  238. itemstack:set_count(itemstack:get_stack_max())
  239. for k, v in ipairs(inv:get_list("main")) do
  240. if v:get_name() == "" and v:get_count() == 0 then
  241. amount = amount + itemstack:get_count()
  242. end
  243. end
  244. if amount == 0 then
  245. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You don't have empty space in your inventory. Transaction cancelled.")
  246. end
  247. local buy_price = amount * store_item.buy
  248. local new_balance = x_marketplace.set_player_balance(caller, buy_price * -1)
  249. -- not enough money
  250. if not new_balance then
  251. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold.")
  252. end
  253. for k, v in ipairs(inv:get_list("main")) do
  254. if v:get_name() == "" and v:get_count() == 0 then
  255. inv:add_item("main", itemstack)
  256. end
  257. end
  258. minetest.sound_play("x_marketplace_gold", {
  259. object = player,
  260. max_hear_distance = 10,
  261. gain = 1.0
  262. })
  263. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold")
  264. else
  265. -- item not in store
  266. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: This item is not in store, check out other items from the store: ")..x_marketplace.store_get_random()
  267. end
  268. --
  269. -- buy
  270. --
  271. elseif params[1] == "buy" then
  272. local amount = tonumber(params[3])
  273. params[2] = x_marketplace.normalize_nodename(params[2])
  274. -- check for param[2] - item name
  275. if not params[2] then
  276. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You need to write the item name you want to buy. example: /mp buy default:stone 10, or check out other items in the store: ")..x_marketplace.store_get_random()
  277. end
  278. -- find sign
  279. local player = minetest.get_player_by_name(caller)
  280. local find_signs = x_marketplace.find_signs(player:get_pos(), "/mp buy", "x_marketplace:sign_wall_diamond")
  281. if not find_signs then
  282. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: There are no Diamond Signs around you with text '/mp buy' on them. Transaction cancelled.")
  283. end
  284. -- item not in store
  285. if not x_marketplace.store_list[params[2]] then
  286. return false, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: This item is not in store, check out other items from the store: ")..x_marketplace.store_get_random()
  287. end
  288. -- check for param[3] - amount
  289. local itemstack = ItemStack(params[2])
  290. -- check for number sanity, positive number
  291. if not amount or
  292. x_marketplace.isnan(amount) or
  293. not x_marketplace.isfinite(amount) or
  294. amount <= 0 then
  295. amount = 1
  296. end
  297. if amount > itemstack:get_stack_max() then
  298. amount = itemstack:get_stack_max()
  299. end
  300. itemstack:set_count(amount)
  301. -- add items to main inventory
  302. local store_item = x_marketplace.store_list[params[2]]
  303. local inv = player:get_inventory("main")
  304. local buy_price = amount * store_item.buy
  305. local new_balance = x_marketplace.set_player_balance(caller, buy_price * -1)
  306. -- not enough money
  307. if not new_balance then
  308. return false, minetest.colorize(x_marketplace.colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold")
  309. end
  310. -- drop items what doesn't fit in the inventory
  311. local leftover_item = inv:add_item("main", itemstack)
  312. if leftover_item:get_count() > 0 then
  313. local p = table.copy(player:get_pos())
  314. p.y = p.y + 1.2
  315. local obj = minetest.add_item(p, leftover_item)
  316. if obj then
  317. local dir = player:get_look_dir()
  318. dir.x = dir.x * 2.9
  319. dir.y = dir.y * 2.9 + 2
  320. dir.z = dir.z * 2.9
  321. obj:set_velocity(dir)
  322. obj:get_luaentity().dropped_by = caller
  323. end
  324. end
  325. minetest.sound_play("x_marketplace_gold", {
  326. object = player,
  327. max_hear_distance = 10,
  328. gain = 1.0
  329. })
  330. return true, minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold")
  331. --
  332. -- top 5 richest
  333. --
  334. elseif params[1] == "top" then
  335. local players = minetest.get_connected_players()
  336. local temp_tbl = {}
  337. for k, v in ipairs(players) do
  338. local pname = v:get_player_name()
  339. local balance = x_marketplace.get_player_balance(pname)
  340. table.insert(temp_tbl, { name = pname, balance = tonumber(balance) })
  341. end
  342. table.sort(temp_tbl, function(a, b) return a.balance > b.balance end)
  343. local msg = "MARKET PLACE: \n"
  344. local length = 5
  345. if length > #temp_tbl then
  346. length = #temp_tbl
  347. end
  348. for i = 1, length do
  349. msg = msg..i..". "..temp_tbl[i].name.."\n"
  350. end
  351. -- print(dump(temp_tbl))
  352. return true, minetest.colorize(x_marketplace.colors.yellow, msg)
  353. --
  354. -- help
  355. --
  356. elseif params[1] == "help" then
  357. local msg =
  358. minetest.colorize(x_marketplace.colors.cyan, "/mp find").." <item name>, find item in store\n"..
  359. minetest.colorize(x_marketplace.colors.cyan, "/mp balance")..", show your current balance in BitGold\n"..
  360. minetest.colorize(x_marketplace.colors.cyan, "/mp sellhand")..", sell item(s) currently holding in hand, you must be near Mese Sign with text '/mp sell' on it\n"..
  361. minetest.colorize(x_marketplace.colors.cyan, "/mp buyhand").." [<amount>], buy <amount> of item(s) currently holding in hand, when <amount> is not provided then amount is 1, you must be near Diamond Sign with text '/mp buy' on it\n"..
  362. minetest.colorize(x_marketplace.colors.cyan, "/mp infohand")..", show more information about the item(s) you are currently holding in hand from the store\n"..
  363. minetest.colorize(x_marketplace.colors.cyan, "/mp buy").." <item name> [<amount>], buy <amount> of <item name> from store, if <amount> is not provided then amount is 1, you must be near Diamond Sign with text '/mp buy' on it\n"..
  364. minetest.colorize(x_marketplace.colors.cyan, "/mp sellinv").." <item name>, sell all items <item name> from the 'main' inventory list, you must be near Mese Sign with text '/mp sell' on it\n"..
  365. minetest.colorize(x_marketplace.colors.cyan, "/mp buyinv").." <item name>, buy full inventory of items <item name>, empty slots in the 'main' inventory are required, you must be near Diamond Sign with text '/mp buy' on it\n"..
  366. minetest.colorize(x_marketplace.colors.cyan, "/mp top")..", show top 5 richest players currently online\n"..
  367. minetest.colorize(x_marketplace.colors.cyan, "/mp help")..", print out this help\n"
  368. -- print(msg)
  369. return true, msg
  370. end
  371. end
  372. })