local tr = towny.regions.size local function err_msg(player, msg) minetest.chat_send_player(player, minetest.colorize("#ff1111", msg)) return false end function towny:get_player_town(name) for town,data in pairs(towny.towns) do if data.mayor == name then return town elseif data.members[name] then return town end end return nil end function towny:get_town_by_name(name) if not name then return nil end for town,data in pairs(towny.towns) do if data.name:lower() == name:lower() then return town end end return nil end function towny:mark_dirty(town, areas) towny.dirty = true towny.towns[town].dirty = true if areas and towny.regions.memloaded[town] then towny.regions.memloaded[town].dirty = true end end function towny:create_town(pos, player, name) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end if towny:get_player_town(player) then return err_msg(player, "You're already in a town! Please leave your current town before founding a new one!") end local _,__,distance = towny.regions:get_closest_town(pos) if distance > towny.regions.distance * towny.regions.size and not towny_admin then return err_msg(player, "This location is too close to another town!") end if towny:get_town_by_name(name) and not towny_admin then return err_msg(player, "A town by this name already exists!") end -- TODO: Economy -- New town information local p1 = vector.add(pos, {x=tr / 2,y=tr - 1,z=tr / 2}) local p2 = vector.subtract(pos, {x=tr / 2,y=1,z=tr / 2}) local id = minetest.sha1(minetest.hash_node_position(pos)) local data = { name = name, mayor = player, members = { [player] = {["town_build"] = true, ["plot_build"] = true} }, plots = {}, flags = { origin = pos, claim_blocks = towny.claimbonus, plot_member_build = true, } } local regions = { origin = pos, blocks = { { x=p1.x, y=p1.y, z=p1.z, origin = true } } } towny.towns[id] = data towny.regions.memloaded[id] = regions towny:mark_dirty(id, true) minetest.chat_send_player(player, "Your town has successfully been founded!") minetest.chat_send_all(player .. " has started a new town called '" .. name .. "'!") towny.regions:visualize_area(p1,p2) return true end function towny:extend_town(pos,player) if not pos then pos = minetest.get_player_by_name(player):get_pos() 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 data = towny.towns[town] if data.mayor ~= player and data.members[player]['claim_create'] ~= true then return err_msg(player, "You do not have permission to spend claim blocks in your town.") end if data.flags["claim_blocks"] < 1 then return err_msg(player, "You do not have enough remaining claim blocks!") end local p1,closest_town = towny.regions:align_new_claim_block(pos, player) if not p1 then return err_msg(player, "You cannot claim this area! Town blocks must be aligned side-by-side.") end if towny.regions:town_claim_exists(town,p1) then return err_msg(player, "This area is already claimed.") end if closest_town ~= town then return err_msg(player, "Something went wrong!") end table.insert(towny.regions.memloaded[town].blocks, p1) data.flags["claim_blocks"] = data.flags["claim_blocks"] - 1 minetest.chat_send_player(player, "Successfully claimed this block!") towny:mark_dirty(town, true) towny.regions:visualize_radius(vector.subtract(p1, {x=tr/2,y=tr/2,z=tr/2})) return true end function towny:abridge_town(pos,player) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local data = towny.towns[town] if data.mayor ~= player and data.members[player]['claim_delete'] ~= true and not towny_admin then return err_msg(player, "You do not have permission to delete claim blocks in your town.") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end local success,message = towny.regions:remove_claim(c[1],t) if not success then return err_msg(player, "Failed to abandon claim block: " .. message) end data.flags["claim_blocks"] = data.flags["claim_blocks"] + 1 minetest.chat_send_player(player, "Successfully abandoned this claim block!") towny:mark_dirty(t, true) return true end function towny:leave_town(player,kick) local town = towny:get_player_town(player) if not town then return err_msg(player, "You're not currently in a town!") end local data = towny.towns[town] if data.mayor == player then return err_msg(player, "You cannot abandon a town that you own! Either delete the town or transfer mayorship.") end -- Update town members local members = {} for member,mdata in pairs(data.members) do if member ~= player then members[member] = mdata end end data.members = members -- Update plot members for plotid,pdata in pairs(data.plots) do local members = {} if pdata.owner == player then pdata.owner = nil if pdata.flags["greeting"] ~= nil then pdata.flags["greeting"] = nil end end for mem,dat in pairs(pdata.members) do if mem ~= player then -- Transfer ownership to the first other member if pdata.owner == nil then pdata.owner = mem end members[mem] = dat end end pdata.members = members end local msg = "You successfully left the town." if kick then msg = "You were kicked form town." end towny:mark_dirty(town, false) minetest.chat_send_player(player, msg) return true end function towny:kick_member(town,player,member) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) local data = towny.towns[town] if data.mayor ~= player and not towny_admin then return err_msg(player, "You do not have permission to kick people from this town.") end if not data.members[member] then return err_msg(player, "User "..member.." is not in this town.") end if member == data.mayor then return err_msg(player, "You cannot kick the town mayor.") end if player == member then return err_msg(player, "You cannot kick yourself from town.") end return towny:leave_town(member,true) end function towny:delete_town(pos,player) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end local data = towny.towns[t] if data.mayor ~= player and not towny_admin then return err_msg(player, "You do not have permission to delete this town.") end local name = data.name .. "" -- Wipe the town towny.towns[t] = nil towny.regions.memloaded[t] = nil towny.flatfile:delete_all_meta(t) minetest.chat_send_player(player, "Successfully deleted the town!") minetest.chat_send_all("The town '" .. name .. "' has fell into ruin.") return true end function towny:delete_plot(pos,player) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town or not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end local data = towny.towns[t] local plot_data = data.plots[p] if (data.mayor ~= player and data.members[player]['plot_delete'] ~= true) and (plot_data.owner ~= player) and not towny_admin then return err_msg(player, "You do not have permission to delete this plot.") end towny.regions:set_plot(c[1],t,nil) data.plots[p] = nil towny:mark_dirty(t, true) minetest.chat_send_player(player, "Successfully removed the plot.") return true end function towny:create_plot(pos,player) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end if p ~= nil then return err_msg(player, "You cannot create a plot here!") end local data = towny.towns[t] if data.mayor ~= player and data.members[player]['plot_create'] ~= true and not towny_admin then return err_msg(player, "You do not have permission to create plots in this town.") end local pid = minetest.sha1(minetest.hash_node_position(c[1])) local success,message = towny.regions:set_plot(c[1],t,pid) if not success then minetest.chat_send_player(player, "Failed to create a plot here: " .. message) return false end data.plots[pid] = { owner = player, members = {[player] = {}}, flags = {}, } towny:mark_dirty(t, true) minetest.chat_send_player(player, "Successfully created a plot!") towny.regions:visualize_radius(vector.subtract(c[1], {x=tr/2,y=tr/2,z=tr/2})) return true end function towny:claim_plot(pos,player) if not pos then pos = minetest.get_player_by_name(player):get_pos() 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 t,p,c = towny.regions:get_town_at(pos) if not t or t ~= town then return err_msg(player, "You are not in any town you can modify.") end local tdata = towny.towns[t] if p ~= nil then local plot_data = tdata.plots[p] if plot_data.flags['claimable'] or player == tdata.mayor then if plot_data.owner == player or plot_data.members[player] then return err_msg(player, "You are already a member of this plot.") end -- TODO: enconomy tdata.plots[p] = { owner = player, members = {[player] = {}}, flags = {}, } towny:mark_dirty(t, false) minetest.chat_send_player(player, "Successfully claimed the plot!") towny.regions:visualize_radius(vector.subtract(c[1], {x=tr/2,y=tr/2,z=tr/2})) return true else return err_msg(player, "This plot is not for sale.") end end return towny:create_plot(pos,player) end function towny:abandon_plot(pos,player) if not pos then pos = minetest.get_player_by_name(player):get_pos() 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 t,p,c = towny.regions:get_town_at(pos) if not t or t ~= town then return err_msg(player, "You are not in any town you can modify.") end if p == nil then return err_msg(player, "There is no plot here.") end local tdata = towny.towns[t] local pdata = tdata.plots[p] if not pdata.members[player] then return err_msg(player, "You are not a member of this plot.") end -- Update plot members local members = {} if pdata.owner == player then pdata.owner = nil if pdata.flags["greeting"] ~= nil then pdata.flags["greeting"] = nil end end for mem,dat in pairs(pdata.members) do if mem ~= player then -- Transfer ownership to the first other member if pdata.owner == nil then pdata.owner = mem end members[mem] = dat end end pdata.members = members towny:mark_dirty(t, false) minetest.chat_send_player(player, "Successfully abandoned the plot!") return true end function towny:plot_member(pos,player,member,action) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() 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 t,p,c = towny.regions:get_town_at(pos) if not t or t ~= town then return err_msg(player, "You are not in any town you can modify.") end if p == nil then return err_msg(player, "There is no plot here.") end local tdata = towny.towns[t] local pdata = tdata.plots[p] if pdata.owner ~= player and player ~= tdata.mayor and not towny_admin then return err_msg(player, "You do not have permission to modify this plot.") end if not tdata.members[member] then return err_msg(player, "User '"..member.."' is not part of this town.") end -- Update plot members local members = {} local action_desc = "add yourself to" if action == 0 then action_desc = "remove yourself from" end if member == pdata.owner then return err_msg(player, "You cannot "..action_desc.." from this plot.") end if action == 0 then action_desc = "removed "..member.." from" for mem,dat in pairs(pdata.members) do if mem ~= member then -- Transfer ownership to the first other member members[mem] = dat end end else action_desc = "added "..member.." to" members = pdata.members members[member] = {} end pdata.members = members towny:mark_dirty(t, false) minetest.chat_send_player(player, "Successfully "..action_desc.." plot!") return true end local function flag_typeify(value,pos) if type(value) == "string" then if value == "true" then value = true elseif value == "false" then value = false elseif value == "here" then value = pos elseif value == "none" or value == "null" or value == "nil" then value = nil elseif tonumber(value) ~= nil then value = tonumber(value) elseif minetest.string_to_pos(value) ~= nil then value = minetest.string_to_pos(value) end end return value end -- Set flags function towny:set_plot_flags(pos,player,flag,value) if not flag then return false end local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end if p == nil then return err_msg(player, "There is no plot here! Please stand in the plot you wish to modify.") end local data = towny.towns[t] local plot_data = data.plots[p] if data.mayor ~= player and plot_data.owner ~= player and not towny_admin then return err_msg(player, "You do not have permission to modify this plot.") end minetest.chat_send_player(player, "Successfully set the plot flag '" .. flag .."' to '" .. value .. "'!") plot_data.flags[flag] = flag_typeify(value,pos) towny:mark_dirty(t, false) end function towny:set_plot_member_flags(pos,player,member,flag,value) if not member or not flag then return false end local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end if p == nil then return err_msg(player, "There is no plot here! Please stand in the plot you wish to modify.") end local data = towny.towns[t] local plot_data = data.plots[p] if data.mayor ~= player and plot_data.owner ~= player and not towny_admin then return err_msg(player, "You do not have permission to modify this plot.") end if not plot_data.members[member] then return err_msg(player, "There is no such member in this plot.") end if flag == "build" then flag = "plot_build" end minetest.chat_send_player(player, "Successfully set the plot member "..member.."'s flag '" .. flag .."' to '" .. value .. "'!") plot_data.members[member][flag] = flag_typeify(value,pos) towny:mark_dirty(t, false) end function towny:set_town_flags(pos,player,flag,value) if not flag then return false end local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos then pos = minetest.get_player_by_name(player):get_pos() end local town = towny:get_player_town(player) if not town and not towny_admin then return err_msg(player, "You're not currently in a town!") end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can modify.") end local data = towny.towns[t] if data.mayor ~= player and not towny_admin then return err_msg(player, "You do not have permission to modify this town.") end if (flag == 'bank' or flag == 'claim_blocks' or flag == 'origin') and not towny_admin then return err_msg(player, "You cannot change this flag.") end minetest.chat_send_player(player, "Successfully set the town flag '" .. flag .."' to '" .. value .. "'!") data.flags[flag] = flag_typeify(value,pos) towny:mark_dirty(t, false) end -- Get flags function towny:get_flags(town,plot) local tdata = towny.towns[town] if not tdata then return nil end if not plot then return tdata.flags end if not tdata.plots[plot] then return nil end return tdata.plots[plot].flags end function towny:get_plot_flags(town,pos,player) local towny_admin = minetest.check_player_privs(player, { towny_admin = true }) if not pos and player then pos = minetest.get_player_by_name(player):get_pos() end local t,p,c = towny.regions:get_town_at(pos) if not t or (t ~= town and not towny_admin) then return err_msg(player, "You are not in any town you can access.") end if not t or not p then return nil end return towny:get_flags(t,p) end function towny:get_claims_total(town) if not towny.regions.memloaded[town] then return 0 end return #towny.regions.memloaded[town].blocks end