api.lua 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. --- Returns true if given value is a finite number; otherwise false or nil if value is not of type string nor number.
  2. function x_marketplace.isfinite(value)
  3. if type(value) == "string" then
  4. value = tonumber(value)
  5. if value == nil then return nil end
  6. elseif type(value) ~= "number" then
  7. return nil
  8. end
  9. return value > -math.huge and value < math.huge
  10. end
  11. --- Returns true if given value is not a number (NaN); otherwise false or nil if value is not of type string nor number.
  12. function x_marketplace.isnan(value)
  13. if type(value) == "string" then
  14. value = tonumber(value)
  15. if value == nil then return nil end
  16. elseif type(value) ~= "number" then
  17. return nil
  18. end
  19. return value ~= value
  20. end
  21. --- rounds a number to the nearest decimal places
  22. -- @local
  23. local function round(val, decimal)
  24. if (decimal) then
  25. return math.floor( (val * 10^decimal) + 0.5) / (10^decimal)
  26. else
  27. return math.floor(val+0.5)
  28. end
  29. end
  30. local function string_endswith(full, part)
  31. return full:find(part, 1, true) == #full - #part + 1
  32. end
  33. --- Normalize nodename string without mod prefix and return nodename with mod prefix. This function was borrowed from WorldEdit mod.
  34. -- @param nodename name of the node as a string, can be without the mod prefix
  35. -- @return nil if node doesn't exists or nodename with mode prefix
  36. -- @see https://github.com/Uberi/Minetest-WorldEdit
  37. function x_marketplace.normalize_nodename(nodename)
  38. if not nodename then
  39. return false
  40. end
  41. nodename = nodename:gsub("^%s*(.-)%s*$", "%1") -- strip spaces
  42. if nodename == "" then return nil end
  43. local fullname = ItemStack({name=nodename}):get_name() -- resolve aliases
  44. if minetest.registered_nodes[fullname] or fullname == "air" then -- full name
  45. return fullname
  46. end
  47. for key, value in pairs(minetest.registered_nodes) do
  48. if string_endswith(key, ":" .. nodename) then -- matches name (w/o mod part)
  49. return key
  50. end
  51. end
  52. end
  53. --- Search items in marketplace object
  54. -- @param string the string
  55. -- @return string with found items, if no items found returns boolean false
  56. function x_marketplace.store_find(string)
  57. local found = ""
  58. local str = x_marketplace.normalize_nodename(string)
  59. if not str then
  60. return false
  61. end
  62. for k, v in pairs(x_marketplace.store_list) do
  63. if string.find(k, str) then
  64. found = found..k.." buy: "..string.format("%.2f", v.buy).." sell: "..string.format("%.2f", v.sell).."\n"
  65. end
  66. end
  67. if found == "" then
  68. found = false
  69. end
  70. return found
  71. end
  72. --- Get random items from the store
  73. -- @param number the integer
  74. -- @return string with found items
  75. function x_marketplace.store_get_random(number)
  76. local keys, i, suggest = {}, 1, ""
  77. local how_many = number or 5
  78. for k, v in pairs(x_marketplace.store_list) do
  79. keys[i] = k
  80. i = i + 1
  81. end
  82. for i = 1, how_many do
  83. suggest = suggest.."\n"..keys[math.random(1, #keys)]
  84. end
  85. return suggest
  86. end
  87. --- Get players balance of BitGold
  88. -- @param name the string of player name
  89. -- @return string the current balance
  90. function x_marketplace.get_player_balance(name)
  91. if not name then
  92. return ""
  93. end
  94. local player = minetest.get_player_by_name(name)
  95. local balance = player:get_attribute("balance") or 0
  96. return balance
  97. end
  98. --- Set players balance of BitGold
  99. -- @param name the string of player name
  100. -- @param amount the number of what should be added/deducted (if negative) from players balance
  101. -- @return string the balance info message, returns false if not enough funds
  102. function x_marketplace.set_player_balance(name, amount)
  103. if not name or not amount then
  104. return ""
  105. end
  106. local player = minetest.get_player_by_name(name)
  107. local balance = player:get_attribute("balance") or 0
  108. local new_balance = balance + amount
  109. if new_balance < 0 then
  110. return false, "below"
  111. end
  112. if new_balance > x_marketplace.max_balance then
  113. return false, "above"
  114. end
  115. player:set_attribute("balance", new_balance)
  116. return new_balance
  117. end
  118. function x_marketplace.find_signs(player_pos, text, sign)
  119. local pos0 = vector.subtract(player_pos, 2)
  120. local pos1 = vector.add(player_pos, 2)
  121. local positions = minetest.find_nodes_in_area(pos0, pos1, sign)
  122. local found = false
  123. if #positions <= 0 then
  124. return false
  125. end
  126. for k, v in pairs(positions) do
  127. local sign_meta = minetest.get_meta(v)
  128. local sign_text = sign_meta:get_string("text"):trim()
  129. if sign_text == text then
  130. found = true
  131. break
  132. end
  133. end
  134. return found
  135. end
  136. minetest.register_craftitem("x_marketplace:head", {
  137. description = "head",
  138. inventory_image = "x_marketplace_head-front.png",
  139. wield_image = "x_marketplace_head-front.png",
  140. stack_max = 1,
  141. wield_scale = {x=1.5, y=1.5, z=6},
  142. on_use = function(itemstack, user, pointed_thing)
  143. if pointed_thing.type == "node" then
  144. local node = minetest.get_node(pointed_thing.under)
  145. if node.name == "x_marketplace:sign_wall_bones" then
  146. local node_meta = minetest.get_meta(pointed_thing.under)
  147. if node_meta:get_string("text"):trim() == "/mp sellhead" then
  148. local stack_meta = itemstack:to_table().meta
  149. local stack_meta_value = tonumber(stack_meta.value)
  150. local stack_meta_owner = stack_meta.owner
  151. if not stack_meta_value then
  152. itemstack:take_item()
  153. return itemstack
  154. end
  155. -- sell item
  156. local new_balance = x_marketplace.set_player_balance(user:get_player_name(), stack_meta_value)
  157. if new_balance then
  158. minetest.sound_play("x_marketplace_gold", {
  159. object = user,
  160. max_hear_distance = 10,
  161. gain = 1.0
  162. })
  163. minetest.chat_send_player(user:get_player_name(), minetest.colorize(x_marketplace.colors.green, "MARKET PLACE: You sold "..stack_meta_owner.." head for "..stack_meta_value.." BitGold. Your new balance is: "..new_balance.." BitGold"))
  164. itemstack:take_item()
  165. else
  166. minetest.chat_send_player(user:get_player_name(), minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: You will go above the maximum balance if you sell this item. Transaction cancelled."))
  167. end
  168. end
  169. else
  170. minetest.chat_send_player(user:get_player_name(), minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: If you want to sell the head, you have to punch Bones Sign with text '/mp sellhead' on it."))
  171. end
  172. end
  173. return itemstack
  174. end,
  175. })
  176. minetest.register_on_dieplayer(function(player)
  177. local player_name = player:get_player_name()
  178. local balance = tonumber(x_marketplace.get_player_balance(player_name))
  179. local lost_value, new_balance
  180. if balance then
  181. -- no money, nothing to loose
  182. if balance == 0 then
  183. return
  184. -- almost no money, drop everything
  185. elseif balance <= 10 then
  186. lost_value = balance
  187. -- loose between 5-10% from balance
  188. else
  189. lost_value = (balance / 100) * math.random(5, 10)
  190. end
  191. lost_value = round(lost_value, 2)
  192. new_balance = x_marketplace.set_player_balance(player_name, lost_value * -1)
  193. local pos = vector.round(player:getpos())
  194. local itemstack = ItemStack("x_marketplace:head")
  195. local meta = itemstack:get_meta()
  196. local item_description = minetest.registered_items["x_marketplace:head"]["description"]
  197. meta:set_string("owner", player_name)
  198. meta:set_string("value", lost_value)
  199. meta:set_string("description", player_name.." "..item_description.."\nvalue: "..lost_value.." BitGold")
  200. local obj = minetest.add_item(pos, itemstack)
  201. if obj then
  202. obj:set_velocity({
  203. x = math.random(-10, 10) / 9,
  204. y = 5,
  205. z = math.random(-10, 10) / 9,
  206. })
  207. end
  208. minetest.chat_send_player(player_name, minetest.colorize(x_marketplace.colors.yellow, "MARKET PLACE: When you died you lost "..lost_value.." BitGold"))
  209. end
  210. end)