Towny Economy Setup

This commit is contained in:
Evert Prants 2019-11-21 15:28:04 +02:00
parent 01aefb5094
commit d6a158a6e7
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
11 changed files with 344 additions and 20 deletions

View File

@ -1,2 +1,3 @@
areas? areas?
protector? protector?
currency?

View File

@ -1,8 +1,6 @@
-- A township system for Minetest servers. -- A township system for Minetest servers.
-- The MIT License - 2019 Evert "Diamond" Prants <evert@lunasqu.ee> -- The MIT License - 2019 Evert "Diamond" Prants <evert@lunasqu.ee>
-- TODO: Protection on HUD
-- TODO: Nations
-- TODO: Economy -- TODO: Economy
local modpath = minetest.get_modpath(minetest.get_current_modname()) local modpath = minetest.get_modpath(minetest.get_current_modname())

View File

@ -1,3 +1,3 @@
name = towny name = towny
description = A township system for Minetest servers. description = A township system for Minetest servers.
optional_depends = areas,protector optional_depends = areas,protector,currency

View File

@ -1,13 +1,11 @@
# General [General]
##########
# Town metadata and region storage engine # Town metadata and region storage engine
# Recommended to keep as modstorage. # Recommended to keep as modstorage.
towny_storage_engine (Storage engine) enum modstorage modstorage,flatfile towny_storage_engine (Storage engine) enum modstorage modstorage,flatfile
# Claims settings [Claims]
##################
# Towny claim diameter # Towny claim diameter
towny_claim_size (Claim size) int 16 towny_claim_size (Claim size) int 16
@ -27,19 +25,7 @@ towny_distance (Max town claims) int 80
# Recommended to be kept as true, may cause issues with claims otherwise # Recommended to be kept as true, may cause issues with claims otherwise
towny_prevent_protector (Prevent protectors from being placed in a town) bool true towny_prevent_protector (Prevent protectors from being placed in a town) bool true
# Command settings [Command]
###################
# If true, players must be invited into towns (No direct joining) # If true, players must be invited into towns (No direct joining)
towny_invite (Invite-based membership) bool true towny_invite (Invite-based membership) bool true
# Economy settings
###################
towny_eco (Enable economy) bool false
towny_tax (Allow taxation) bool true
# Units depend on economy mod used in server
towny_create_cost (Town creation cost) int 10000
towny_claim_cost (Town claim block cost) int 1000
towny_upkeep_cost (Town daily upkeep cost, multiplied by member count) int 0

19
towny_eco/api.lua Normal file
View File

@ -0,0 +1,19 @@
--------------
-- Abstract --
--------------
-- Get currency name/description
function towny.eco.get_currency() return "" end
-- Format the number appropriately
function towny.eco.format_number(number) return number end
-- Get player's balance
function towny.eco.get_player_balance(player) return 0 end
-- Charge a player
function towny.eco.charge_player(player, amount) return 0 end
-- Pay a player
function towny.eco.pay_player(player, amount) return false end

2
towny_eco/depends.txt Normal file
View File

@ -0,0 +1,2 @@
towny
currency?

View File

@ -0,0 +1 @@
Towny Economy support

18
towny_eco/init.lua Normal file
View File

@ -0,0 +1,18 @@
-- A township system for Minetest servers.
-- The MIT License - 2019 Evert "Diamond" Prants <evert@lunasqu.ee>
local modpath = minetest.get_modpath(minetest.get_current_modname())
towny.eco = {
enabled = false,
create_cost = tonumber(minetest.settings:get("towny_create_cost")) or 10000,
claim_cost = tonumber(minetest.settings:get("towny_claim_cost")) or 1000,
upkeep_cost = tonumber(minetest.settings:get("towny_upkeep_cost")) or 0,
taxable = minetest.settings:get_bool("towny_tax", true)
}
dofile(modpath.."/api.lua")
if minetest.get_modpath("currency") ~= nil then
dofile(modpath.."/mods/currency.lua")
end

4
towny_eco/mod.conf Normal file
View File

@ -0,0 +1,4 @@
name = towny_eco
description = Towny Economy support
depends = towny
optional_depends = currency

289
towny_eco/mods/currency.lua Normal file
View File

@ -0,0 +1,289 @@
-- Simple "currency" mod API
local denoms = {
["currency:minegeld_cent_5"] = 0.05,
["currency:minegeld_cent_10"] = 0.10,
["currency:minegeld_cent_25"] = 0.25,
["currency:minegeld"] = 1,
["currency:minegeld_5"] = 5,
["currency:minegeld_10"] = 10,
["currency:minegeld_50"] = 50,
["currency:minegeld_100"] = 100,
}
function towny.eco.get_currency()
return "Minegeld"
end
function towny.eco.format_number(number)
return ("%.2f MG$"):format(number)
end
local function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
-- Item-based functions
local function to_stacks(items)
local counted = {}
for _,i in pairs(items) do
if counted[i] then
counted[i] = counted[i] + 1
else
counted[i] = 1
end
end
local stacks = {}
for itm,cnt in pairs(counted) do
table.insert(stacks, ItemStack(itm .. " " .. cnt))
end
return stacks
end
local function get_closest_note(amount, notes)
local t = nil
local a = 0
for itm,val in pairs(denoms) do
local b = (notes == nil)
if notes and notes[itm] ~= nil and notes[itm] > 0 then
b = true
end
if val <= amount and a <= val and b then
t = itm
a = val
end
end
return a, t
end
local function denominate(amount)
local items = {}
local tc = amount
while tc > 0 do
local amount,item = get_closest_note(tc)
if amount == 0 then break end
tc = tc - amount
table.insert(items, item)
end
return to_stacks(items)
end
local function notes_inv(inventory)
local total = 0
for _,stack in pairs(inventory:get_list("main")) do
local value = denoms[stack:get_name()]
if value then
total = total + (value * stack:get_count())
end
end
return total
end
local function highest_note(notes, amount)
local result = nil
local tmount = 0
for note,cnt in pairs(notes) do
local nt = denoms[note]
if nt > amount and cnt > 0 then
result = note
tmount = nt
end
end
return tmount, result
end
local function take_notes(inventory, total)
-- Take an audit of all the notes in the inventory
local notes = {}
for _,stack in pairs(inventory:get_list("main")) do
local name = stack:get_name()
if denoms[name] then
if notes[name] then
notes[name] = notes[name] + stack:get_count()
else
notes[name] = stack:get_count()
end
end
end
local original = table.copy(notes)
-- Loop through, getting the highest notes first
while total > 0 do
local amount,item = get_closest_note(total,notes)
if amount == 0 then break end
if notes[item] then
notes[item] = notes[item] - 1
end
total = total - amount
end
-- If the total was not reached, try to get the next highest note
local give = 0
if total > 0 then
local nxam,note = highest_note(notes, total)
if nxam > total then
notes[note] = notes[note] - 1
give = nxam - total
total = 0
end
end
-- Couldn't take total balance
if total > 0 then
return nil
end
-- Take from inventory
for note,count in pairs(notes) do
if original[note] then
local taken = original[note] - count
if taken > 0 then
inventory:remove_item("main", ItemStack(note .. " " .. taken))
end
end
end
if give > 0 then
local stacks = denominate(give)
for _,stack in pairs(stacks) do
inventory:add_item("main", stack)
end
end
return total
end
-- Public functions
function towny.eco.get_player_balance(player)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
if not player then return 0 end
if towny.eco.type == "item" then
return notes_inv(player:get_inventory())
else
local meta = player:get_meta()
return meta:get_float("money")
end
end
function towny.eco.charge_player(player, amount)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
if not player then return false end
if towny.eco.type == "item" then
return take_notes(player:get_inventory(), amount)
else
local meta = player:get_meta()
local money = meta:get_float("money")
if money < amount then
return false
end
meta:set_float(money - amount)
return amount
end
end
function towny.eco.pay_player(player, amount)
if type(player) == "string" then
player = minetest.get_player_by_name(player)
end
if not player then return false end
if towny.eco.type == "item" then
local inventory = player:get_inventory()
local stacks = denominate(amount)
for _,stack in pairs(stacks) do
inventory:add_item("main", stack)
end
else
local meta = player:get_meta()
local money = meta:get_float("money")
meta:set_float(money + amount)
return true
end
end
local requests = {}
local function c(msg)
return minetest.colorize("#09b700",msg)
end
local function b(msg)
return minetest.colorize("#078c00",msg)
end
local function msg(name,msg)
minetest.chat_send_player(name,msg)
return true
end
local function fm(amount)
return towny.eco.format_number(amount)
end
local function help()
return minetest.colorize("#e5b002", "Command usage:") .. "\n" ..
b("/money") .. c(" - Check your balance") .. "\n" ..
b("/money transfer") .. c(" <player> <amount> - Give money to a player") .. "\n" ..
b("/money request") .. c(" <player> <amount> - Request money from a player") .. "\n"
end
local function money_command(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "Only an online player can run this command."
end
if param == "" then
return true, b("Balance: ") .. c(fm(towny.eco.get_player_balance(player)))
end
local command,target,amount = param:match("^(%a+) ([%a%d_-]+) ([%d.]+)$")
local target_player = minetest.get_player_by_name(target or "")
if command and not target then
return false, "The target player doesn't exist."
end
amount = tonumber(amount)
if command == "transfer" or command == "pay" or command == "give" then
local taken = towny.eco.charge_player(player, amount)
if not taken then
return false, "You do not have enough money."
end
towny.eco.pay_player(target_player, amount)
minetest.chat_send_player(target, c("Player %s has paid you %s!"):format(name, fm(amount)))
return true, c("Successfully given %s to %s."):format(fm(amount), target)
elseif command == "request" then
if requests[name.."-"..target] then
return false, "You have already requested money from that player."
end
requests[name.."-"..target] = true
minetest.chat_send_player(target, c("Player %s requested a total of %s from you. Run '/money pay %s %d' to pay them.")
:format(name, fm(amount), name, amount))
return true, c("Request sent.")
end
return false, help()
end
minetest.register_chatcommand("money", {
description = "View and transfer your money",
privs = {interact = true},
func = money_command
})
towny.eco.type = "item"
towny.eco.enabled = true

View File

@ -0,0 +1,6 @@
towny_tax (Allow taxation) bool true
# Units depend on economy mod used in server
towny_create_cost (Town creation cost) int 10000
towny_claim_cost (Town claim block cost) int 1000
towny_upkeep_cost (Town daily upkeep cost, multiplied by member count) int 0