diff --git a/towny/commands.lua b/towny/commands.lua index 87ae9cf..1ff82de 100644 --- a/towny/commands.lua +++ b/towny/commands.lua @@ -28,10 +28,14 @@ end local function invite_player(town,player,target) local utown = towny.get_player_town(player) - if not utown or utown ~= town then + if not utown then return false, "You are not in a town." end + if target == player then + return false, "You cannot invite yourself!" + end + if not minetest.get_player_by_name(target) then return false, "You can only invite online players to your town." end @@ -67,7 +71,7 @@ end local function invite_respond(player,response) local utown = towny.get_player_town(player) - if utown or utown ~= town then + if utown then return false, "You are already in a town." end @@ -88,7 +92,7 @@ local function invite_respond(player,response) return false, "You do not have any pending invites." end -local function send_flags (flags,message) +function towny.chat.send_flags (flags,message) local shiny = {} for flag,value in pairs(flags) do if type(value) == "table" then @@ -121,7 +125,7 @@ local function town_command (name, param) if (pr1 == "create" or pr1 == "new") and pr2 then return towny.create_town(nil, name, pr2) elseif (pr1 == "invite" and not minetest.get_player_by_name(pr2)) then - return invite_respond(name, (tyes:lower() == "accept" or minetest.is_yes(tyes))) + return invite_respond(name, (pr2:lower() == "accept" or minetest.is_yes(pr2))) elseif pr1 == "join" and towny.get_town_by_name(pr2) and not town then return join_town(pr2,name,false) elseif pr1 == "show" or pr1 == "info" then @@ -162,7 +166,7 @@ local function town_command (name, param) elseif param == "flags" then local flags = towny.get_flags(town) if flags then - return send_flags(flags,"Flags of your town") + return towny.chat.send_flags(flags,"Flags of your town") end elseif (param == "delete" or param == "abandon") or (pr1 == "delete" or pr1 == "abandon") then if towny.chat['delete_verify_' .. name] and pr2 == "I WANT TO DELETE MY TOWN" then @@ -208,7 +212,7 @@ local function town_command (name, param) elseif pr2 == "flags" then local flags = towny.get_plot_flags(town,nil,name) if flags then - return send_flags(flags,"Flags of this plot") + return towny.chat.send_flags(flags,"Flags of this plot") else return false, "There's no plot here." end diff --git a/towny/init.lua b/towny/init.lua index 29e3fe2..067cfb4 100644 --- a/towny/init.lua +++ b/towny/init.lua @@ -83,7 +83,7 @@ towny = { ['joinable'] = {"boolean", "if true, anyone can join this town. defaults to false"}, ['greeting'] = {"string", "town's greeting message"}, ['tax'] = {"number", "how much each member has to pay each day to stay in town"}, - ['mayor'] = {"member", "town's mayor"}, + ['mayor'] = {"member", "town's mayor"}, ['bank'] = {"number", "town's treasury", false}, ['claim_blocks'] = {"number", "town's bonus claim blocks", false}, ['origin'] = {"vector", "town's center position, set at town creation", false}, @@ -96,11 +96,11 @@ towny = { ['plot_delete'] = {"boolean", "member can delete plots"}, }, plot = { - ['teleport'] = {"vector", "plot's teleport point"}, - ['pvp'] = {"boolean", "players can fight here if true, ignores server pvp settings"}, - ['cost'] = {"number", "plot cost (only with economy)"}, + ['teleport'] = {"vector", "plot's teleport point"}, + ['pvp'] = {"boolean", "players can fight here if true, ignores server pvp settings"}, + ['cost'] = {"number", "plot cost (only with economy)"}, ['claimable'] = {"boolean", "is this plot available for claiming. if cost is more than 0, require payment"}, - ['greeting'] = {"string", "plot's greeting message (defaults to \"{owner}'s Plot\"/\"Unclaimed Plot\")"}, + ['greeting'] = {"string", "plot's greeting message (defaults to \"{owner}'s Plot\"/\"Unclaimed Plot\")"}, }, plot_member = { ['plot_build'] = {"boolean", "member can build on plot. defaults to 'plot_member_build' town flag"}, diff --git a/towny/storage/flatfile.lua b/towny/storage/flatfile.lua index 1e8c5c9..3a2c406 100644 --- a/towny/storage/flatfile.lua +++ b/towny/storage/flatfile.lua @@ -68,7 +68,17 @@ function towny.storage.save_town_meta(town) end end -local ldirs = { "meta", "region" } +function towny.storage.save_nation_meta(nation) + local nmeta = towny.nations.nations[nation] + if nmeta and nmeta.dirty then + minetest.after(0.2, function () + write_meta(town,"nation",nmeta) + nmeta.dirty = false + end) + end +end + +local ldirs = { "meta", "region", "nation" } function towny.storage.load_all_towns() local world = minetest.get_worldpath() local metadir = world.."/towny/"..ldirs[1] @@ -101,6 +111,24 @@ function towny.storage.load_all_towns() end) end end + + if towny.nations then + local nationdir = world.."/towny/"..ldirs[3] + minetest.mkdir(nationdir) + + local nations = minetest.get_dir_list(nationdir, false) + for _,file in pairs(nations) do + if file:match("."..extension.."$") then + local nation = file:gsub("."..extension,"") + minetest.after(0.1, function () + local nationdata = load_meta(nationdir.."/"..file) + if not nationdata then return end + towny.nations.nations[nation] = nationdata + towny.nations.get_nation_level(nation, true) + end) + end + end + end end function towny.storage.delete_all_meta(town) diff --git a/towny/storage/init.lua b/towny/storage/init.lua index e776937..24e80c1 100644 --- a/towny/storage/init.lua +++ b/towny/storage/init.lua @@ -22,6 +22,14 @@ local function carrier_tick() end end + if towny.nations then + for nation,data in pairs(towny.nations.nations) do + if data.dirty then + towny.storage.save_nation_meta(nation) + end + end + end + towny.dirty = false saving = false end diff --git a/towny/storage/modstorage.lua b/towny/storage/modstorage.lua index 4071b36..60de77b 100644 --- a/towny/storage/modstorage.lua +++ b/towny/storage/modstorage.lua @@ -4,11 +4,13 @@ local storage = minetest.get_mod_storage() local function write_meta(town,scope,data) + local data = table.copy(data) data.dirty = nil data.level = nil local serialized = minetest.serialize(data) storage:set_string(town.."/"..scope, serialized) + data = nil end function towny.storage.save_town_meta(town) @@ -26,6 +28,15 @@ function towny.storage.save_town_meta(town) end end +function towny.storage.save_nation_meta(nation) + if not towny.nations then return end + local rmeta = towny.nations.nations[nation] + if rmeta and rmeta.dirty then + write_meta(nation,"nation",rmeta) + rmeta.dirty = false + end +end + -- Ideally only ever called once function towny.storage.load_all_towns() local keys = {} @@ -44,6 +55,9 @@ function towny.storage.load_all_towns() towny.get_town_level(town, true) elseif scope == "region" then towny.regions.memloaded[town] = tbl + elseif scope == "nation" and towny.nations then + towny.nations.nations[town] = tbl + towny.nations.get_nation_level(town, true) end end end @@ -57,4 +71,8 @@ function towny.storage.delete_all_meta(town) if storage:get_string(town.."/region") ~= "" then storage:set_string(town.."/region", "") end + + if storage:get_string(town.."/nation") ~= "" then + storage:set_string(town.."/nation", "") + end end diff --git a/towny/town.lua b/towny/town.lua index bdde4a4..8e19abe 100644 --- a/towny/town.lua +++ b/towny/town.lua @@ -31,7 +31,7 @@ local function flag_typeify(value,pos) return value end -local function flag_validity(flag,scope,value,pos,members) +function towny.flag_validity(flag,scope,value,pos,members) value = flag_typeify(value,pos) local spd = towny.flags[scope] if type(spd[flag]) == "string" then @@ -586,7 +586,7 @@ function towny.set_plot_flags(pos,player,flag,value) return err_msg(player, "You do not have permission to modify this plot.") end - local fs,flag,res = flag_validity(flag, 'plot', value, pos) + local fs,flag,res = towny.flag_validity(flag, 'plot', value, pos) if not fs then return err_msg(player, "Invalid flag or flag value.") end @@ -627,7 +627,7 @@ function towny.set_plot_member_flags(pos,player,member,flag,value) return err_msg(player, "There is no such member in this plot.") end - local fs,flag,res = flag_validity(flag, 'plot_member', value, pos) + local fs,flag,res = towny.flag_validity(flag, 'plot_member', value, pos) if not fs then return err_msg(player, "Invalid flag or flag value.") end @@ -661,7 +661,7 @@ function towny.set_town_flags(pos,player,flag,value) return err_msg(player, "You do not have permission to modify this town.") end - local fs,flag,res = flag_validity(flag, 'town', value, pos, data.members) + local fs,flag,res = towny.flag_validity(flag, 'town', value, pos, data.members) if not fs then return err_msg(player, "Invalid flag or invalid or unchangeable flag value.") end @@ -702,7 +702,7 @@ function towny.set_town_member_flags(pos,player,member,flag,value) return err_msg(player, "There is no such member in this town.") end - local fs,flag,res = flag_validity(flag, 'town_member', value, pos) + local fs,flag,res = towny.flag_validity(flag, 'town_member', value, pos) if not fs then return err_msg(player, "Invalid flag or flag value.") end @@ -750,9 +750,19 @@ function towny.get_claims_max(town) if not tdata then return 0 end if not tdata.level then towny.get_town_level(town, true) end local bonus = 0 + if tdata.flags['claim_blocks'] and tdata.flags['claim_blocks'] > 0 then bonus = tdata.flags['claim_blocks'] end + + if towny.nations then + local n = towny.nations.get_town_nation(town) + local ndata = towny.nations.nations[n] + if n and ndata and ndata.level then + bonus = bonus + ndata.level.block_bonus + end + end + return tdata.level.claimblocks + bonus, tdata.level.claimblocks, bonus end @@ -776,6 +786,23 @@ function towny.get_full_name(town) return ("%s (%s)"):format(tdata.name, tdata.level.name_tag) end +function towny.get_player_name(player) + local town = towny.get_player_town(player) + local tdata = towny.towns[town] + if not tdata then return player end + if not tdata.level then return player end + if towny.nations and tdata.flags.mayor == player then + local n = towny.nations.get_town_nation(town) + if n then + local name = towny.nations.get_player_name(n,player) + if name then + return name + end + end + end + return ("%s %s"):format(tdata.level.mayor_tag, player) +end + function towny.get_town_level(town, update) local tdata = towny.towns[town] if not tdata then return nil end diff --git a/towny_chat/init.lua b/towny_chat/init.lua index c8baeab..786e6f3 100644 --- a/towny_chat/init.lua +++ b/towny_chat/init.lua @@ -3,3 +3,13 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) towny.chat.modpath = modpath + +minetest.register_on_chat_message(function (name, message) + local town = towny.get_player_town(name) + local result = ("<%s> %s"):format(name, message) + if town then + result = ("[%s] <%s> %s"):format(towny.get_full_name(town), towny.get_player_name(name), message) + end + minetest.chat_send_all(result) + return true +end) diff --git a/towny_hud/init.lua b/towny_hud/init.lua index 5fbbdb9..428f360 100644 --- a/towny_hud/init.lua +++ b/towny_hud/init.lua @@ -2,3 +2,83 @@ -- The MIT License - 2019 Evert "Diamond" Prants local modpath = minetest.get_modpath(minetest.get_current_modname()) + +-- This code is borrowed from [areas] by ShadowNinja +-- TODO: Support areas (areas:getExternalHudEntries) + +towny.hud = {} + +minetest.register_globalstep(function(dtime) + for _, player in pairs(minetest.get_connected_players()) do + local name = player:get_player_name() + local pos = vector.round(player:getpos()) + local areaStrings = {} + + local t,p,c = towny.regions.get_town_at(pos) + + if t then + if towny.nations then + local n = towny.nations.get_town_nation(t) + if n then + table.insert(areaStrings, towny.nations.get_full_name(n)) + end + end + + local town = towny.get_full_name(t) + local tdata = towny.towns[t] + local greeting = "" + if tdata.flags.greeting then + greeting = "- "..tdata.flags.greeting + end + table.insert(areaStrings, ("%s %s"):format(town, greeting)) + + if p then + local plot = tdata.plots[p] + local greeting = ("%s's Plot"):format(plot.owner) + + if plot.flags['greeting'] then + greeting = ("%s (%s)"):format(plot.flags['greeting'], plot.owner) + end + + if plot.flags['claimable'] then + if plot.flags['cost'] and plot.flags['cost'] > 0 then + -- TODO: economy + end + greeting = greeting .. " (For sale: FREE!)" + end + + table.insert(areaStrings, ("%s - %s"):format(town, greeting)) + end + end + + local areaString = "Towns:" + if #areaStrings > 0 then + areaString = areaString.."\n".. + table.concat(areaStrings, "\n") + end + local hud = towny.hud[name] + if not hud then + hud = {} + towny.hud[name] = hud + hud.areasId = player:hud_add({ + hud_elem_type = "text", + name = "Towns", + number = 0xFFFFFF, + position = {x=0, y=1}, + offset = {x=8, y=-8}, + text = areaString, + scale = {x=200, y=60}, + alignment = {x=1, y=-1}, + }) + hud.oldAreas = areaString + return + elseif hud.oldAreas ~= areaString then + player:hud_change(hud.areasId, "text", areaString) + hud.oldAreas = areaString + end + end +end) + +minetest.register_on_leaveplayer(function(player) + towny.hud[player:get_player_name()] = nil +end) diff --git a/towny_nations/commands.lua b/towny_nations/commands.lua new file mode 100644 index 0000000..58548cc --- /dev/null +++ b/towny_nations/commands.lua @@ -0,0 +1,176 @@ + +towny.chat.invites.nation = {} + +-- Send message to all town members who are online +function towny.nations.announce_to_members(nation,message) + local ndata = towny.nations.nations[nation] + if ndata then return end + for town in pairs(ndata.members) do + towny.chat.announce_to_members(town,message) + end +end + +local function join_nation(nation,player,from_invite) + local town = towny.get_player_town(player) + local tdata = towny.towns[town] + local ndata = towny.nations.nations[nation] + if not ndata then return false, "The nation specified does not exist." end + if not tdata then return false, "You are not in a town that could join a nation." end + if towny.nations.get_town_nation(town) then return false, "Your town is already part of a nation." end + if tdata.flags.mayor ~= player then return false, "Only the mayor can join their town into a nation." end + if (not from_invite and not ndata.flags['joinable']) then return false, "You cannot join this nation." end + towny.nations.announce_to_members(town, minetest.colorize("#02aacc", ("%s has joined the nation!"):format(towny.get_full_name(town)))) + minetest.chat_send_player(player, ("Your town has successfully joined %s!"):format(towny.nations.get_full_name(nation))) + ndata.members[town] = {} + ndata.dirty = true + towny.dirty = true + return true +end + +local function invite_respond(player,response) + local utown = towny.get_player_town(player) + if not utown then + return false, "You are not in a town." + end + + local unation = towny.nations.get_town_nation(utown) + if unation then + return false, "Your town is already part of a nation." + end + + for id,data in pairs(towny.chat.invites.nation) do + if data.player == player then + if not data.rejected then + if response == true then + towny.chat.invites.nation[id] = nil + return join_nation(data.nation,player,true) + else + towny.chat.invites.nation[id] = { rejected = true } + return true, "You have rejected the join request." + end + end + end + end + + return false, "You do not have any pending invites." + +end + +local function invite_town(player,town) + local utown = towny.get_player_town(player) + if not utown then + return false, "You are not in a town." + end + + if town == utown then + return false, "You cannot invite yourself!" + end + + local nation = towny.nations.get_town_nation(utown) + if not nation then + return false, "Your town is not part of any nation." + end + + local utdata = towny.towns[utown] + local ndata = towny.nations.nations[nation] + if utdata.flags.mayor ~= player or ndata.flags.capital ~= utown then + return false, "You can only invite towns to your nation if you own said nation!" + end + + if not towny.get_town_by_name(town) then + return false, "Invalid town name." + end + + local target_town = towny.nations.get_town_nation(town) + if target_town then + return false, "This town is already part of a nation!" + end + + if towny.chat.invites.nation[town.."-"..nation] then + return false, "This town has already been invited to join your nation!" + end + + local tdata = towny.towns[town] + local target = tdata.flags['mayor'] + if not minetest.get_player_by_name(target) then + return false, "The mayor of the targeted town is offline, thus you cannot invite this town to your nation!" + end + + minetest.chat_send_player(target, ("Your town has been invited to join %s by %s"):format(towny.nations.get_full_name(nation), player)) + minetest.chat_send_player(target, "You can accept this invite by typing '/nation invite accept' or deny '/nation invite deny'") + + towny.chat.invites[town.."-"..nation] = { rejected = false, nation = nation, town = town, invited = player } + return true, ("Town %s has been invited to join your nation."):format(town) +end + +local function nation_command(name, param) + local player = minetest.get_player_by_name(name) + if not player then return false, "Can't run command on behalf of offline player." end + + local pr1, pr2 = string.match(param, "^([%a%d_-]+) (.+)$") + local town = towny.get_player_town(name) + + if not town then + return false, "You are not currently in any town." + end + + local nation = towny.nations.get_town_nation(town) + local tdata = towny.towns[town] + + -- Pre nation requirement + local nation_info = nil + + if (pr1 == "create" or pr1 == "new") and pr2 then + return towny.nations.create_nation(pr2,name) + elseif (pr1 == "invite" and not towny.get_town_by_name(pr2)) then + return invite_respond(name, (pr2:lower() == "accept" or minetest.is_yes(pr2))) + elseif pr1 == "join" and towny.nations.get_nation_by_name(pr2) and not nation then + return join_nation(pr2,name,false) + elseif pr1 == "show" or pr1 == "info" then + if not towny.get_town_by_name(pr2) then + return false, "No such nation." + end + nation_info = pr2 + elseif param == "" and nation then + nation_info = nation + end + + -- Print nation information + if nation_info then + return false, "Not yet implemented!" + end + + if not nation then + return false, "You are not currently in a nation." + end + + local ndata = towny.nations.nations[nation] + local capital = towny.towns[ndata.flags.capital] + + if param == "leave" or param == "delete" then + return towny.nations.leave_nation(name) + elseif param == "teleport" and capital then + local portal = capital.flags['teleport'] + if not portal then portal = capital.flags['origin'] end + player:set_pos(portal) + return true, "Teleporting you to the nation's capital town.." + elseif param == "flags" then + local flags = towny.nations.get_flags(nation) + if flags then + return towny.chat.send_flags(flags,"Flags of your nation") + end + elseif pl1 == "set" and pl2 then + local flag, value = string.match(pl2, "^([%a%d_-]+) (.+)$") + return towny.nations.set_nation_flags(name,flag,value) + elseif pr1 == "invite" and towny.get_town_by_name(pr2) then + return invite_town(name,towny.get_town_by_name(pr2)) + end + + return false, "Invalid command usage." +end + +minetest.register_chatcommand("nation", { + description = "Manage your nation", + privs = {towny = true}, + func = nation_command +}) diff --git a/towny_nations/init.lua b/towny_nations/init.lua index f50a963..30ed70a 100644 --- a/towny_nations/init.lua +++ b/towny_nations/init.lua @@ -4,6 +4,7 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) towny.nations = { modpath = modpath, + nations = {}, levels = { { king_tag = 'Leader', @@ -44,3 +45,12 @@ towny.nations = { } }, } + +towny.flags.nation = { + ['tax'] = {"number", "how much each town has to pay each day to stay in the nation"}, + ['capital'] = {"member", "nation's capital town"}, + ['bank'] = {"number", "nation's treasury", false}, +} + +dofile(modpath.."/nation.lua") +dofile(modpath.."/commands.lua") diff --git a/towny_nations/nation.lua b/towny_nations/nation.lua new file mode 100644 index 0000000..fc39adc --- /dev/null +++ b/towny_nations/nation.lua @@ -0,0 +1,196 @@ + +local function err_msg(player, msg) + minetest.chat_send_player(player, minetest.colorize("#ff1111", msg)) + return false +end + +local function count(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end + +local function mark_dirty(nation) + towny.dirty = true + towny.nations.nations[nation].dirty = true +end + +function towny.nations.get_nation_by_name(name) + if not name then return nil end + for town,data in pairs(towny.nations.nations) do + if data.name:lower() == name:lower() then + return town + end + end + return nil +end + +function towny.nations.get_town_nation(town) + if not town or not towny.towns[town] then return nil end + for tid,data in pairs(towny.nations.nations) do + if data.flags.capital == town or data.members[town] then + return tid + end + end + return nil +end + +function towny.nations.create_nation(name,player) + local town = towny.get_player_town(player) + if not town then + return err_msg(player, "You're not currently in a town!") + end + + local tdata = towny.towns[town] + if tdata.flags['mayor'] ~= player then + return err_msg(player, "Only the town mayor can create a nation!") + end + + if towny.nations.get_town_nation(town) then + return err_msg(player, "You're already part of a nation!") + end + + if towny.nations.get_nation_by_name(name) then + return err_msg(player, "A nation by that name already exists!") + end + + -- TODO: economy + + local vertpos = {x = math.random(-999,999), y = math.random(-999,999), z = math.random(-999,999)} + local nid = minetest.sha1(minetest.hash_node_position(vertpos)) + + towny.nations.nations[nid] = { + name = name, + members = {[town] = {}}, + flags = {capital = town}, + } + + mark_dirty(nid) + + minetest.chat_send_player(player, "Your nation has successfully been founded!") + minetest.chat_send_all(("%s has started a new nation called '%s'!"):format(player,name)) + + return true +end + +function towny.nations.leave_nation(player) + local town = towny.get_player_town(player) + if not town then + return err_msg(player, "You're not currently in a town!") + end + + local tdata = towny.towns[town] + if tdata.flags['mayor'] ~= player then + return err_msg(player, "Only the town mayor can leave the nation!") + end + + local nation = towny.nations.get_town_nation(town) + local ndata = towny.nations.nations[nation] + if not nation or not ndata then + return err_msg(player, "Your town is currently not part of any nation!") + end + + if ndata.flags['capital'] == town and count(ndata.members) > 1 then + return err_msg(player, "Your nation contains more than one member towns! Please remove the towns or change the capital before deleting your nation.") + end + + if ndata.flags['capital'] == town and count(ndata.members) <= 1 then + -- Single member town, delete nation + towny.storage.delete_all_meta(nation) + towny.nations.nations[nation] = nil + minetest.chat_send_player(player, "Successfully deleted the nation!") + minetest.chat_send_all(("The nation '%s' has fallen."):format(ndata.name)) + else + -- Simply leave + minetest.chat_send_player(player, "Successfully left the nation!") + towny.nations.nations[nation].members[town] = nil + towny.nations.announce_to_members(nation, ("Town '%s' has left the nation."):format(tdata.name)) + mark_dirty(nation) + end + + return true +end + +function towny.nations.set_nation_flags(player,flag,value) + if not flag then return false end + + local town = towny.get_player_town(player) + if not town then + return err_msg(player, "You're not currently in a town!") + end + + local nation = towny.nations.get_nation_by_name(name) + local ndata = towny.nations.nations[name] + local tdata = towny.towns[town] + if not nation or not ndata then + return err_msg(player, "Your town is currently not part of any nation!") + end + + local ndata = towny.nations.nations[t] + if tdata.flags.capital ~= ndata.name or tdata.flags.mayor ~= player then + return err_msg(player, "You do not have permission to modify this nation.") + end + + local val_pass = value + if flag == "capital" then + val_pass = towny.get_town_by_name(value) + end + + local fs,flag,res = towny.flag_validity(flag, 'nation', val_pass, nil, ndata.members) + if not fs then + return err_msg(player, "Invalid flag or invalid or unchangeable flag value.") + end + + -- Announce capital change to all + if flag == "capital" and res ~= town then + towny.nations.announce_to_members(nation, ("The nation's capital has been changed to %s!"):format(towny.get_full_name(res))) + end + + minetest.chat_send_player(player, ("Successfully set the nation flag '%s' to '%s'!"):format(flag,value)) + ndata.flags[flag] = res + mark_dirty(nation) +end + +function towny.nations.get_nation_level(nation, update) + local ndata = towny.nations.nations[nation] + if not ndata then return nil end + if ndata.level and not update then return ndata.level end + local lvl + for _,describe in pairs(towny.nations.levels) do + if count(ndata.members) >= describe.members then + lvl = describe + end + end + ndata.level = lvl + return lvl +end + +function towny.nations.get_full_name(nation) + local ndata = towny.nations.nations[nation] + if not ndata then return nil end + if not ndata.level then return ndata.name end + return ("%s %s %s"):format(ndata.level.prefix, ndata.name, ndata.level.tag) +end + +function towny.nations.get_player_name(nation,player) + local ndata = towny.nations.nations[nation] + if not ndata then return player end + if not ndata.level then return player end + local cap = towny.towns[ndata.flags.capital] + if not cap or not cap.members[player] then return player end + if cap.flags.mayor ~= player then return nil end + return ("%s %s"):format(ndata.level.king_tag, player) +end + +function towny.nations.get_member_count(nation) + local ndata = towny.nations.nations[nation] + if not ndata then return nil end + return count(ndata.members) +end + +function towny.nations.get_flags(nation) + local ndata = towny.nations.nations[nation] + if not ndata then return nil end + ndata.flags.capital = towny.towns[ndata.flags.capital].name + return ndata.flags +end