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.

core.lua 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. --
  2. -- money3
  3. --
  4. -- Copyright © 2012 Bad_Command
  5. -- Copyright © 2012 kotolegokot
  6. -- Copyright © 2019 by luk3yx
  7. --
  8. -- This library is free software; you can redistribute it and/or
  9. -- modify it under the terms of the GNU Lesser General Public
  10. -- License as published by the Free Software Foundation; either
  11. -- version 2.1 of the License, or (at your option) any later version.
  12. --
  13. -- This program is distributed in the hope that it will be useful,
  14. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. -- GNU General Public License for more details.
  17. --
  18. -- You should have received a copy of the GNU Lesser General Public
  19. -- License along with this library; if not, write to the Free Software
  20. -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. --
  22. local storage = assert(...)
  23. local worldpath = minetest.get_worldpath()
  24. -- Raw get balance
  25. local function raw_get_balance(name)
  26. local bal = tonumber(storage:get_string("balance-" .. name:lower()))
  27. if not bal or bal ~= bal then return nil end
  28. return bal
  29. end
  30. -- Migrate an old balance
  31. local function migrate_old_balance(name, do_not_set)
  32. -- Make sure the name doesn't contain any insane characters
  33. if not name:find("^[A-Za-z0-9_%-]+$") then return end
  34. -- Try and get a handler to the balance file
  35. local path = worldpath .. "/money_" .. name .. ".txt"
  36. local file = io.open(path, "r")
  37. if not file then return end
  38. -- Read the credit and nuke the file.
  39. local credit = file:read("*n")
  40. file:close()
  41. os.remove(path)
  42. if not do_not_set and credit and credit == credit and credit >= 0 then
  43. return money3.set(name, (raw_get_balance(name) or 0) + credit)
  44. end
  45. end
  46. -- Combine the two above functions to provide seamless backwards compatibility
  47. function money3.get(name)
  48. migrate_old_balance(name)
  49. return raw_get_balance(name)
  50. end
  51. -- Round a balance
  52. function money3.round(balance)
  53. return math.floor(balance * 100) / 100
  54. end
  55. -- Set a balance
  56. function money3.set(name, balance)
  57. migrate_old_balance(name, true)
  58. balance = money3.round(balance)
  59. storage:set_string("balance-" .. name:lower(), tostring(balance))
  60. end
  61. -- Check if a user exists
  62. function money3.user_exists(name)
  63. local privs = minetest.get_player_privs(name)
  64. if not privs or not privs.money or not money3.get(name) then
  65. return false
  66. end
  67. return true
  68. end
  69. money3.has_credit = money3.user_exists
  70. -- Add money
  71. function money3.add(name, amount)
  72. if amount ~= amount or amount < 0 then
  73. return "The amount specified must be a positive non-NaN number."
  74. end
  75. local credit = money3.get(name)
  76. if not credit then
  77. return name .. " does not exist."
  78. end
  79. money3.set(name, credit + amount)
  80. return nil
  81. end
  82. function money3.dec(name, amount)
  83. if amount ~= amount or amount < 0 then
  84. return "The amount specified must be a positive non-NaN number."
  85. end
  86. local credit = money3.get(name)
  87. if not credit then
  88. return name .. " does not exist."
  89. elseif credit < amount then
  90. return name .. " does not have enough credit."
  91. end
  92. money3.set(name, credit - amount)
  93. end
  94. function money3.transfer(from, to, amount)
  95. if from == to then return end
  96. amount = money3.round(amount)
  97. if not money3.user_exists(from) then
  98. return from .. " does not have a credit account"
  99. elseif not money3.user_exists(to) then
  100. return to .. " does not have a credit account"
  101. end
  102. local err = money3.dec(from, amount)
  103. if err then return err end
  104. local err = money3.add(to, amount)
  105. if err then
  106. money3.add(from, amount)
  107. return err
  108. end
  109. minetest.log("action", "[money3] Credit transfer of " ..
  110. tostring(amount) .. " from " .. from .. " to " .. to)
  111. end
  112. -- Format currency
  113. function money3.format(amount)
  114. return tostring(amount) .. (money3.currency_name or "cr")
  115. end
  116. -- Migrate balances and set the initial amount.
  117. minetest.register_on_joinplayer(function(player)
  118. local name = player:get_player_name()
  119. if not money3.get(name) then
  120. money3.set(name, tostring(money3.initial_amount))
  121. end
  122. end)
  123. minetest.register_privilege("money",
  124. "Can use /money [pay <player> <amount>] command.")
  125. minetest.register_privilege("money_admin", {
  126. description = "Full access to all /money commands.",
  127. give_to_singleplayer = false,
  128. })
  129. minetest.register_chatcommand("money", {
  130. privs = {money=true},
  131. params = "[<player> | pay/set/add/dec <player> <amount>]",
  132. description = "Operations with credit",
  133. func = function(name, param)
  134. if param == "" then
  135. return true, "Your balance: " .. money3.format(money3.get(name))
  136. end
  137. local param1, reciever, amount = param:match("([^ ]+) ([^ ]+) (.+)")
  138. if not reciever and not amount then
  139. if not minetest.check_player_privs(name, {money_admin = true}) then
  140. return false, "Insufficient privileges!"
  141. elseif not money3.get(param) then
  142. return false, "Player named \"" ..
  143. param .. "\" does not exist or does not have an account."
  144. end
  145. return true, param .. "'s balance: " ..
  146. money3.format(money3.get(param))
  147. end
  148. if param1 ~= "pay" and param1 ~= "set" and param1 ~= "add" and
  149. param1 ~= "dec" or not reciever or not amount then
  150. return false, "Invalid parameters (see /help money)"
  151. elseif not money3.user_exists(reciever) then
  152. return false, "Player named \"" ..
  153. reciever .. "\" does not exist or does not have account."
  154. end
  155. amount = tonumber(amount)
  156. if not amount or amount ~= amount or amount < 0 then
  157. return false, "You must specify a valid non-negative number."
  158. end
  159. if param1 == "pay" then
  160. local err = money3.transfer(name, reciever, amount)
  161. if err then
  162. return false, err
  163. end
  164. local a = money3.format(amount)
  165. minetest.chat_send_player(reciever, "money3: " .. name ..
  166. " paid you " .. a)
  167. return true, "You paid " .. reciever .. " " .. a .. "."
  168. elseif not minetest.get_player_privs(name).money_admin then
  169. return false, "Insufficient privileges!"
  170. end
  171. local err = "Internal error!"
  172. if param1 == "add" then
  173. err = money3.add(reciever, amount)
  174. elseif param1 == "dec" then
  175. err = money3.dec(reciever, amount)
  176. elseif param1 == "set" then
  177. err = money3.set(reciever, amount)
  178. end
  179. return not err, err or "Done!"
  180. end,
  181. })
  182. -- A dummy money3.dignode() function. This is modified in convertval.lua.
  183. function money3.dignode(pos, node, player) end