Initial commit
This commit is contained in:
commit
585cab107b
67
chat.lua
Normal file
67
chat.lua
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
-- Privileges
|
||||||
|
|
||||||
|
minetest.register_privilege("towny", {
|
||||||
|
description = "Can create and join towns",
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_privilege("towny_admin", {
|
||||||
|
description = "Can administrate other people's towns",
|
||||||
|
give_to_singleplayer = false
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Commands
|
||||||
|
|
||||||
|
local function town_command (name, param)
|
||||||
|
if not minetest.get_player_by_name(name) 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)
|
||||||
|
|
||||||
|
-- Pre town requirement
|
||||||
|
|
||||||
|
if (pr1 == "create" or pr1 == "new") and pr2 then
|
||||||
|
return towny:create_town(nil, name, pr2)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not town then
|
||||||
|
return false, "You are not currently in a town."
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Town management commands
|
||||||
|
local tdata = towny.towns[town]
|
||||||
|
|
||||||
|
if param == "extend" or param == "claim" then
|
||||||
|
return towny:extend_town(nil, name)
|
||||||
|
elseif param == "leave" then
|
||||||
|
return towny:leave_town(name)
|
||||||
|
elseif param == "unclaim" then
|
||||||
|
return towny:abridge_town(nil, name)
|
||||||
|
elseif param == "visualize" then
|
||||||
|
towny.regions:visualize_town(town)
|
||||||
|
return true
|
||||||
|
elseif param == "delete" or param == "abandon" then
|
||||||
|
if towny.chat['delete_verify_' .. name] and pr2 == "I WANT TO DELETE MY TOWN" then
|
||||||
|
towny.chat['delete_verify_' .. name] = nil
|
||||||
|
return towny:delete_town(nil, name)
|
||||||
|
else
|
||||||
|
towny.chat['delete_verify_' .. name] = true
|
||||||
|
minetest.chat_send_player(name, minetest.colorize("#f79204",
|
||||||
|
"WARNING! Deleting your town will render ALL of the buildings in it without protection!"))
|
||||||
|
return false, "Please run the command again with 'I WANT TO DELETE MY TOWN' in all caps written after it."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Plot management commands
|
||||||
|
if pr1 == "plot" then
|
||||||
|
local pl1, pl2 = string.match(pr2, "^([%a%d_-]+) (.+)$")
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return false, "Invalid command usage."
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_chatcommand("town", {
|
||||||
|
description = "Manage your town",
|
||||||
|
privs = {towny = true},
|
||||||
|
func = town_command
|
||||||
|
})
|
1
description.txt
Normal file
1
description.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
A township system for Minetest servers.
|
0
flatfile.lua
Normal file
0
flatfile.lua
Normal file
94
init.lua
Normal file
94
init.lua
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
-- 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 = {
|
||||||
|
claimbonus = minetest.settings:get('towny_claim_bonus') or 8,
|
||||||
|
regions = {
|
||||||
|
size = minetest.settings:get('towny_claim_size') or 16,
|
||||||
|
maxclaims = minetest.settings:get('towny_claim_max') or 128,
|
||||||
|
distance = minetest.settings:get('towny_distance') or 80,
|
||||||
|
|
||||||
|
-- Regions loaded into memory cache, see "Town regions data structure"
|
||||||
|
memloaded = {},
|
||||||
|
},
|
||||||
|
-- See "Town data structure"
|
||||||
|
towns = {},
|
||||||
|
chat = {},
|
||||||
|
|
||||||
|
-- Set to true if files need to be updated
|
||||||
|
dirty = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Town data structure
|
||||||
|
--[[
|
||||||
|
town_id = {
|
||||||
|
name = "Town Name",
|
||||||
|
mayor = "Mayor name",
|
||||||
|
members = {<members with flags>},
|
||||||
|
flags = {<town specific flags>},
|
||||||
|
plots = {
|
||||||
|
plot_id = {
|
||||||
|
owner = "Owner name",
|
||||||
|
members = {<members with flags>},
|
||||||
|
flags = {<plot specific flags>}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- Town regions data structure
|
||||||
|
--[[
|
||||||
|
town_id = {
|
||||||
|
origin = <town origin>,
|
||||||
|
blocks = {
|
||||||
|
{
|
||||||
|
x, y, x, -- Origin point for claim block
|
||||||
|
plot = nil -- Plot ID if this claim block is plotted
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- Town-specific flags
|
||||||
|
--[[
|
||||||
|
'town_build' boolean lets everyone build in unplotted town claims
|
||||||
|
'plot_build' boolean lets everyone build in unowned town plots
|
||||||
|
'plot_member_build' boolean if false, plot members don't have build rights to plots by default
|
||||||
|
'teleport' position town teleport point
|
||||||
|
'pvp' boolean players can fight in the town if true, ignores server pvp settings
|
||||||
|
'plot_pvp' boolean default plot pvp setting. defaults to false
|
||||||
|
'joinable' boolean if true, anyone can join this town. defaults to false
|
||||||
|
'greeting' string town's greeting message
|
||||||
|
'plot_tax' float how much each plot costs each day (only with economy)
|
||||||
|
'bank' float town's wealth (only with economy) (unchangeable by owner)
|
||||||
|
'claim_blocks' int town's available claim blocks (unchangeable by owner)
|
||||||
|
'origin' position town's center position, set at town creation (unchangeable by owner)
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- Members with flags
|
||||||
|
--[[
|
||||||
|
'plot_build' boolean if 'plot_member_build' town flag is false,
|
||||||
|
this one must be true for a plot member to be able to build on a plot.
|
||||||
|
If set to true in town flags, this member can build in all plots.
|
||||||
|
'town_build' boolean if true, this member can build in town claims.
|
||||||
|
'claim_create' boolean if true, this member can claim land for the town
|
||||||
|
'claim_delete' boolean if true, this member can abandon claim blocks
|
||||||
|
'plot_create' boolean if true, this member can create plots
|
||||||
|
'plot_delete' boolean if true, this member can delete plots
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- Plot-specific flags
|
||||||
|
--[[
|
||||||
|
'teleport' position plot's teleport point
|
||||||
|
'pvp' boolean players can fight here if true, ignores server pvp settings
|
||||||
|
'cost' float 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")
|
||||||
|
]]
|
||||||
|
|
||||||
|
dofile(modpath.."/flatfile.lua")
|
||||||
|
dofile(modpath.."/visualize.lua")
|
||||||
|
dofile(modpath.."/regions.lua")
|
||||||
|
dofile(modpath.."/town.lua")
|
||||||
|
dofile(modpath.."/chat.lua")
|
2
mod.conf
Normal file
2
mod.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
name = towny
|
||||||
|
description = A township system for Minetest servers.
|
256
regions.lua
Normal file
256
regions.lua
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
|
||||||
|
local main_is_protected = minetest.is_protected
|
||||||
|
|
||||||
|
-- Calculate a region from the center point and radius
|
||||||
|
local function region_from_diameter(center, diameter)
|
||||||
|
local r = {x = diameter / 2, y = diameter / 2, z = diameter / 2}
|
||||||
|
return vector.subtract(center, r), vector.add(center, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test to see if a position is in a region
|
||||||
|
local function pos_in_region(pos, p1, p2)
|
||||||
|
return (pos.x >= p1.x and pos.y >= p1.y and pos.z >= p1.z) and
|
||||||
|
(pos.x <= p2.x and pos.y <= p2.y and pos.z <= p2.z)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function region_equal(v1, v2)
|
||||||
|
return (math.floor(v1.x) == math.floor(v2.x)) and
|
||||||
|
(math.floor(v1.y) == math.floor(v2.y)) and
|
||||||
|
(math.floor(v1.z) == math.floor(v2.z))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function in_table(tbl, str)
|
||||||
|
for _,s in pairs(tbl) do
|
||||||
|
if s == str then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Test to see if there's already a protected node in a region
|
||||||
|
function towny.regions:already_protected(p1, p2, name)
|
||||||
|
local found = false
|
||||||
|
for x = p1.x, p2.x do
|
||||||
|
if found then break end
|
||||||
|
for y = p1.y, p2.y do
|
||||||
|
if found then break end
|
||||||
|
for z = p1.z, p2.z do
|
||||||
|
if main_is_protected({x=x,y=y,z=z}, name) then
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return found
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:build_perms(town, name, plotid)
|
||||||
|
if not towny.towns[town] then return true end -- Can build here, this town doesnt even exist
|
||||||
|
local towndata = towny.towns[town]
|
||||||
|
|
||||||
|
-- Owner of the town can always build where they want in their town
|
||||||
|
if name == towndata.mayor then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Not even a town member, can't build here!
|
||||||
|
if not in_table(towndata.members, name) then return false end
|
||||||
|
|
||||||
|
-- Plot build rights
|
||||||
|
if plotid and towndata.plots[plotid] then
|
||||||
|
-- This flag dictates that this member can build in all town plots, no matter if they own it or not
|
||||||
|
if towndata.members[name]['plot_build'] == true then return true end
|
||||||
|
|
||||||
|
local plot = towndata.plots[plotid]
|
||||||
|
|
||||||
|
-- This flag dictates that all members can build in unowned town plots
|
||||||
|
if not plot.owner and not towndata.flags['plot_build'] == true then return true end
|
||||||
|
|
||||||
|
-- Plot owner can always build in their plot
|
||||||
|
if name == plot.owner then return true end
|
||||||
|
if in_table(plot.members, name) then
|
||||||
|
if towndata.flags['plot_member_build'] == false then
|
||||||
|
return plot.members[name]['plot_build'] == true
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- This flag dictates that all members can build in unplotted town claims
|
||||||
|
if towndata.flags['town_build'] == true then return true end
|
||||||
|
|
||||||
|
-- If this member has access to building in any town claims, let them
|
||||||
|
if towndata.members[name]['town_build'] == true then return true end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function single_range(p)
|
||||||
|
local p1,p2
|
||||||
|
if p.x then
|
||||||
|
p1 = p
|
||||||
|
p2 = vector.subtract(p, {x=towny.regions.size,y=towny.regions.size,z=towny.regions.size})
|
||||||
|
elseif #p == 2 then
|
||||||
|
p1 = p[1]
|
||||||
|
p2 = p[2]
|
||||||
|
end
|
||||||
|
return p1,p2
|
||||||
|
end
|
||||||
|
|
||||||
|
local function intest(town, name, plotid)
|
||||||
|
return not towny.regions:build_perms(town, name, plotid)
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:get_town_at(pos)
|
||||||
|
local in_town, in_plot, in_claim
|
||||||
|
for town,regions in pairs(towny.regions.memloaded) do
|
||||||
|
if in_town ~= nil then break end
|
||||||
|
if vector.distance(pos, regions.origin) <= towny.regions.size * towny.regions.maxclaims then
|
||||||
|
for _,tc in pairs(regions.blocks) do
|
||||||
|
local p1,p2 = single_range(tc)
|
||||||
|
if pos_in_region(pos,p1,p2) then
|
||||||
|
in_town = town
|
||||||
|
in_claim = {p1,p2}
|
||||||
|
if tc.plot then
|
||||||
|
in_plot = tc.plot
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return in_town,in_plot,in_claim
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:get_closest_town(pos,name)
|
||||||
|
local in_town,block
|
||||||
|
local last_distance = 0
|
||||||
|
for town,regions in pairs(towny.regions.memloaded) do
|
||||||
|
local count = true
|
||||||
|
|
||||||
|
if name then
|
||||||
|
count = towny.regions:build_perms(town, name, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
if count and vector.distance(pos, regions.origin) <= towny.regions.size * towny.regions.maxclaims then
|
||||||
|
for _,tc in pairs(regions.blocks) do
|
||||||
|
local p1,p2 = single_range(tc)
|
||||||
|
local dist = vector.distance(pos, p1)
|
||||||
|
if dist < last_distance or last_distance == 0 then
|
||||||
|
last_distance = dist
|
||||||
|
in_town = town
|
||||||
|
block = {p1,p2}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return in_town,block,last_distance
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:town_claim_exists(town,p1)
|
||||||
|
if not towny.regions.memloaded[town] then return false end
|
||||||
|
local blocks = towny.regions.memloaded[town].blocks
|
||||||
|
for _,pos in pairs(blocks) do
|
||||||
|
if region_equal(p1, pos) then return true end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:align_new_claim_block(pos,name)
|
||||||
|
local r = towny.regions.size
|
||||||
|
local closest_town,closest_block,distance = towny.regions:get_closest_town(pos,name)
|
||||||
|
if not closest_town then return nil end
|
||||||
|
if distance > (r * 2) then return nil end -- Too far
|
||||||
|
|
||||||
|
local new_pos
|
||||||
|
local p1,p2 = closest_block[1],closest_block[2]
|
||||||
|
|
||||||
|
-- X
|
||||||
|
if (pos.z <= p1.z and pos.z >= p2.z) and (p1.y >= pos.y and p2.y <= pos.y) then
|
||||||
|
if pos.x > p1.x then
|
||||||
|
new_pos = vector.add(p1, {x=r,y=0,z=0})
|
||||||
|
else
|
||||||
|
new_pos = vector.add(p1, {x=-r,y=0,z=0})
|
||||||
|
end
|
||||||
|
-- Y
|
||||||
|
elseif (pos.x <= p1.x and pos.x >= p2.x) and (pos.z <= p1.z and pos.z >= p2.z) then
|
||||||
|
if pos.y > p1.y then
|
||||||
|
new_pos = vector.add(p1, {x=0,y=r,z=0})
|
||||||
|
else
|
||||||
|
new_pos = vector.add(p1, {x=0,y=-r,z=0})
|
||||||
|
end
|
||||||
|
-- Z
|
||||||
|
elseif (pos.x <= p1.x and pos.x >= p2.x) and (p1.y >= pos.y and p2.y <= pos.y) then
|
||||||
|
if pos.z > p1.z then
|
||||||
|
new_pos = vector.add(p1, {x=0,y=0,z=r})
|
||||||
|
else
|
||||||
|
new_pos = vector.add(p1, {x=0,y=0,z=-r})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if new_pos == nil then return nil end -- Impossible position
|
||||||
|
return new_pos,closest_town
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:remove_claim(p1,town)
|
||||||
|
local blocks = {}
|
||||||
|
if not towny.regions.memloaded[town] then return false, "This town does not exist anymore." end
|
||||||
|
for _,pos in pairs(towny.regions.memloaded[town].blocks) do
|
||||||
|
if pos['plot'] and towny.towns[town].plots[pos['plot']] then
|
||||||
|
return false, "This town claim defines a plot. Please remove the plot before removing the claim!"
|
||||||
|
elseif region_equal(p1, pos) and pos['origin'] == true then
|
||||||
|
return false, "This town claim is the origin of this town!"
|
||||||
|
elseif not region_equal(p1, pos) then
|
||||||
|
table.insert(blocks, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
towny.regions.memloaded[town].blocks = blocks
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:set_plot(pos,town,plot)
|
||||||
|
if not towny.regions.memloaded[town] then return false, "This town does not exist anymore." end
|
||||||
|
for _,block in pairs(towny.regions.memloaded[town].blocks) do
|
||||||
|
if region_equal(block, pos) then
|
||||||
|
block['plot'] = plot
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:visualize_town(town)
|
||||||
|
if not towny.regions.memloaded[town] then return end
|
||||||
|
for _,pos in pairs(towny.regions.memloaded[town].blocks) do
|
||||||
|
towny.regions:visualize_radius(vector.subtract(pos,
|
||||||
|
{x=towny.regions.size/2,y=towny.regions.size/2,z=towny.regions.size/2}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:position_protected_from(pos, name)
|
||||||
|
local town,plot = towny.regions:get_town_at(pos)
|
||||||
|
if not town then return false end
|
||||||
|
|
||||||
|
return intest(town, name, plot)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Finally, override is_protected
|
||||||
|
function minetest.is_protected(pos, name)
|
||||||
|
local bt = towny.regions:position_protected_from(pos, name)
|
||||||
|
if bt ~= false then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return main_is_protected(pos, name)
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[if minetest.settings:get('towny_prevent_protector') == 'true' then
|
||||||
|
minetest.register_on_placenode(function (pos, newnode, placer, oldnode, itemstack, pointed_thing)
|
||||||
|
local town = towny.regions:get_town_at(pos)
|
||||||
|
if not town return end
|
||||||
|
end)
|
||||||
|
end]]
|
40
settingtypes.txt
Normal file
40
settingtypes.txt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
# Claims settings
|
||||||
|
##################
|
||||||
|
|
||||||
|
# Towny claim diameter
|
||||||
|
towny_claim_size (Claim size) int 16
|
||||||
|
|
||||||
|
# Towny max claim blocks
|
||||||
|
towny_claim_max (Max town claims) int 128
|
||||||
|
|
||||||
|
# Towny max claim blocks
|
||||||
|
towny_claim_bonus (Claim blocks added per new member) int 8
|
||||||
|
|
||||||
|
# Minimum distance between towns (in claim blocks)
|
||||||
|
towny_distance (Max town claims) int 80
|
||||||
|
|
||||||
|
# Prevent protectors from being placed in a town
|
||||||
|
# Towns provide their own protection
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Chat settings
|
||||||
|
################
|
||||||
|
|
||||||
|
# Set to false if you have any other mods that alter the way player-sent messages look
|
||||||
|
towny_chat (Allow towny to modify the chat) bool true
|
||||||
|
|
||||||
|
# If true, players must be invited into towns (No direct joining)
|
||||||
|
towny_questionaire (Invite-based membership) bool true
|
||||||
|
|
||||||
|
# Other settings
|
||||||
|
#################
|
||||||
|
|
||||||
|
towny_eco (Enable economy) bool false
|
||||||
|
towny_tax (Enable taxation) bool false
|
||||||
|
|
||||||
|
# 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 upkeep cost, multiplied by member count) int 10
|
BIN
textures/towny_visualize.png
Normal file
BIN
textures/towny_visualize.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 225 B |
393
town.lua
Normal file
393
town.lua
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
|
||||||
|
local tr = towny.regions.size
|
||||||
|
local function in_table(tbl, str)
|
||||||
|
for _,s in pairs(tbl) do
|
||||||
|
if s == str then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
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 in_table(data.members, name) then
|
||||||
|
return town
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny:get_town_by_name(name)
|
||||||
|
for town,data in pairs(towny.towns) do
|
||||||
|
if data.name.lower() == name.lower() then
|
||||||
|
return town
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
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.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.dirty = 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.dirty = 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,t)
|
||||||
|
if not success then
|
||||||
|
return err_msg(player, "Failed to abandon claim block: " .. message)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(towny.regions.memloaded[t].blocks, p1)
|
||||||
|
data.flags["claim_blocks"] = data.flags["claim_blocks"] + 1
|
||||||
|
minetest.chat_send_player(player, "Successfully abandoned this claim block!")
|
||||||
|
towny.dirty = true
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny:leave_town(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 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
|
||||||
|
|
||||||
|
towny.dirty = true
|
||||||
|
minetest.chat_send_player(player, "You successfully left the town.")
|
||||||
|
return 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.dirty = true
|
||||||
|
|
||||||
|
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,t,nil)
|
||||||
|
data.plots[p] = nil
|
||||||
|
towny.dirty = 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.hash_node_position(c)
|
||||||
|
|
||||||
|
local success,message = towny.regions:set_plot(c,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.dirty = true
|
||||||
|
|
||||||
|
minetest.chat_send_player(player, "Successfully created a plot!")
|
||||||
|
towny.regions:visualize_radius(vector.subtract(c, {x=tr/2,y=tr/2,z=tr/2}))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny:set_plot_flags(pos,player,flag,value)
|
||||||
|
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 .. "'!")
|
||||||
|
if type(value) == "string" and minetest.string_to_pos(value) then
|
||||||
|
value = minetest.string_to_pos(value)
|
||||||
|
end
|
||||||
|
plot_data.flags[flag] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny:set_town_flags(pos,player,flag,value)
|
||||||
|
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 .. "'!")
|
||||||
|
if type(value) == "string" and minetest.string_to_pos(value) then
|
||||||
|
value = minetest.string_to_pos(value)
|
||||||
|
end
|
||||||
|
data.flags[flag] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny:get_claims_total(town)
|
||||||
|
if not towny.regions.memloaded[town] then return 0 end
|
||||||
|
return #towny.regions.memloaded[town].blocks
|
||||||
|
end
|
39
visualize.lua
Normal file
39
visualize.lua
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
-- Visualize an area
|
||||||
|
|
||||||
|
local r1 = towny.regions.size + 1
|
||||||
|
local c_obj_props = {
|
||||||
|
hp = 1,
|
||||||
|
glow = 1,
|
||||||
|
physical = false,
|
||||||
|
pointable = true,
|
||||||
|
visual = "cube",
|
||||||
|
visual_size = {x = r1, y = r1},
|
||||||
|
textures = {"towny_visualize.png","towny_visualize.png","towny_visualize.png",
|
||||||
|
"towny_visualize.png","towny_visualize.png","towny_visualize.png"},
|
||||||
|
static_save = false,
|
||||||
|
use_texture_alpha = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
minetest.register_entity("towny:region_visual", {
|
||||||
|
initial_properties = c_obj_props,
|
||||||
|
on_punch = function(self)
|
||||||
|
self.object:remove()
|
||||||
|
end,
|
||||||
|
timer0 = 0,
|
||||||
|
on_step = function (self,dt)
|
||||||
|
self.timer0 = self.timer0 + 1
|
||||||
|
if self.timer0 > 600 then
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
function towny.regions:visualize_radius(pos)
|
||||||
|
local e = minetest.add_entity(pos, "towny:region_visual")
|
||||||
|
end
|
||||||
|
|
||||||
|
function towny.regions:visualize_area(p1,p2)
|
||||||
|
local r = towny.regions.size / 2
|
||||||
|
local center = {x=p2.x + r,y=p2.y + r,z=p2.z + r}
|
||||||
|
local e = minetest.add_entity(center, "towny:region_visual")
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user