Add towns
This commit is contained in:
parent
26ba673220
commit
7c08d3f61a
7 changed files with 456 additions and 29 deletions
|
|
@ -20,10 +20,13 @@ function ns.register_spawner(def)
|
||||||
ns.spawners[def.plot] = def
|
ns.spawners[def.plot] = def
|
||||||
end
|
end
|
||||||
|
|
||||||
function ns.create_spawner(for_plot)
|
function ns.create_spawner(for_plot, owner)
|
||||||
local s = ItemStack("rgt_towns:spawner")
|
local s = ItemStack("rgt_towns:spawner")
|
||||||
local m = s:get_meta()
|
local m = s:get_meta()
|
||||||
m:set_string("plot", for_plot)
|
m:set_string("plot", for_plot)
|
||||||
|
if owner then
|
||||||
|
m:set_string("owner", owner)
|
||||||
|
end
|
||||||
m:set_string("description", ns.spawners[for_plot].label)
|
m:set_string("description", ns.spawners[for_plot].label)
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
@ -37,6 +40,8 @@ end
|
||||||
thumbnail = "", -- Optional; defines the thumbnail shown in the guide.
|
thumbnail = "", -- Optional; defines the thumbnail shown in the guide.
|
||||||
size = <vector>, -- The amount of space taken up by this plot, in grid squares.
|
size = <vector>, -- The amount of space taken up by this plot, in grid squares.
|
||||||
schematic = <schem> or {},
|
schematic = <schem> or {},
|
||||||
|
ground_level = 5, -- The ground level relative to the bottom of the schematic, used by spawners to determine where to place the schematic relative to the player spawning it.
|
||||||
|
constructors = {n = {5}, w = {5}, s = {5}, e = {5}}, -- The offset from the bottom of the plot at which to place each constructor (to allow for constructors at different Y levels). Defaults to one per horizontally adjoining grid space at y=`ground_level`.
|
||||||
recipe = { -- 3x3 crafting recipe for this structure, as a flat list of ItemStack strings.
|
recipe = { -- 3x3 crafting recipe for this structure, as a flat list of ItemStack strings.
|
||||||
"stone 60", "wood 10", "stone 60",
|
"stone 60", "wood 10", "stone 60",
|
||||||
"cobble 25", "diamond 3", "cobble 25",
|
"cobble 25", "diamond 3", "cobble 25",
|
||||||
|
|
@ -69,5 +74,29 @@ function ns.register_plot(def)
|
||||||
warn "A plot was registered without a name!"
|
warn "A plot was registered without a name!"
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if not def.size then
|
||||||
|
def.size = vector.new(1,1,1)
|
||||||
|
end
|
||||||
|
if not def.ground_level then def.ground_level = 5 end
|
||||||
|
for i, x in ipairs(def.recipe) do
|
||||||
|
if x ~= "" and not x:find ":" then
|
||||||
|
def.recipe[i] = "red_glazed_terracotta:"..x
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if def.constructors then
|
||||||
|
local x = def.constructors
|
||||||
|
local out = {}
|
||||||
|
else
|
||||||
|
local out = {}
|
||||||
|
for x = 1, def.size.x do
|
||||||
|
out[#out +1] = vector.new((x -1) *15, def.ground_level,-7)
|
||||||
|
out[#out +1] = vector.new((x -1) *15, def.ground_level, 7)
|
||||||
|
end
|
||||||
|
for y = 1, def.size.z do
|
||||||
|
out[#out +1] = vector.new(-7, def.ground_level, (y -1) *15)
|
||||||
|
out[#out +1] = vector.new( 7, def.ground_level, (y -1) *15)
|
||||||
|
end
|
||||||
|
def.constructors = out
|
||||||
|
end
|
||||||
ns.plots[def.name] = def
|
ns.plots[def.name] = def
|
||||||
end
|
end
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
local ns = rgt_towns
|
local ns = rgt_towns
|
||||||
|
|
||||||
|
ns.directions = {
|
||||||
|
[0] = vector.new(0,0,1),
|
||||||
|
vector.new(1,0,0),
|
||||||
|
vector.new(0,0,-1),
|
||||||
|
vector.new(-1,0,0)
|
||||||
|
}
|
||||||
|
|
||||||
minetest.register_craftitem(":rgt_towns:spawner", {
|
minetest.register_craftitem(":rgt_towns:spawner", {
|
||||||
description = "Blank Plot Spawner (you shouldn't have this)",
|
description = "Blank Plot Spawner (you shouldn't have this)",
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
|
|
@ -15,17 +22,97 @@ minetest.register_craftitem(":rgt_towns:spawner", {
|
||||||
on_place = function(s, p, pt)
|
on_place = function(s, p, pt)
|
||||||
local m = s:get_meta()
|
local m = s:get_meta()
|
||||||
local owner = m:get("owner")
|
local owner = m:get("owner")
|
||||||
if owner and owner ~= p:get_player_name() then
|
if not owner then
|
||||||
|
owner = p:get_player_name()
|
||||||
|
elseif owner ~= p:get_player_name() then
|
||||||
warn("<"..p:get_player_name().."> tried to use <"..owner..">'s '"..(m:get("description") or "Blank Plot Spawner").."' (and failed).")
|
warn("<"..p:get_player_name().."> tried to use <"..owner..">'s '"..(m:get("description") or "Blank Plot Spawner").."' (and failed).")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local plot = m:get("plot")
|
local plot = m:get("plot")
|
||||||
if plot then
|
if plot then
|
||||||
ns.place_plot(plot, p:get_pos())
|
local def = ns.plots[plot]
|
||||||
|
local pos = p:get_pos():round()
|
||||||
|
pos.y = pos.y -ns.plots[plot].ground_level
|
||||||
|
local q = math.random()
|
||||||
|
ns.create_grid(owner..":town"..q, pos:offset(0,def.size.y *7.5,0))
|
||||||
|
if not ns.place_plot(owner..":town"..q, vector.zero(), plot, owner) then
|
||||||
|
ns.delete_grid(owner..":town"..q)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
warn("<"..p:get_player_name().."> tried to use an uninitialized plot spawner.")
|
warn("<"..p:get_player_name().."> tried to use an uninitialized plot spawner.")
|
||||||
end
|
end
|
||||||
|
return ItemStack()
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
--[[
|
||||||
|
+Z
|
||||||
|
^
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
-X <----------+----------> +X
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
v
|
||||||
|
-Z
|
||||||
|
]]
|
||||||
|
|
||||||
|
function ns.check_recipe(inv, plot)
|
||||||
|
local recipe = ns.plots[plot].recipe
|
||||||
|
print(dump(recipe))
|
||||||
|
for i = 1, 9 do
|
||||||
|
print("Evaluating: "..inv:get_stack("main", i):to_string().." vs. "..ItemStack(recipe[i]):to_string())
|
||||||
|
if inv:get_stack("main", i) ~= ItemStack(recipe[i]) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_node(":rgt_towns:constructor", {
|
||||||
|
tiles = {"[fill:16x16:#8af"},
|
||||||
|
on_construct = function(pos)
|
||||||
|
local inv = minetest.get_meta(pos):get_inventory()
|
||||||
|
inv:set_size("main", 9)
|
||||||
|
end,
|
||||||
|
on_rightclick = function(pos, node, p, s)
|
||||||
|
ns.show_constructor_interface(pos, p)
|
||||||
|
end,
|
||||||
|
on_punch = function(pos, node)
|
||||||
|
local m = minetest.get_meta(pos)
|
||||||
|
local grid = m:get_string("grid")
|
||||||
|
local gpos = vector.from_string(m:get_string("build_pos"))
|
||||||
|
local plot = m:get("plot") or "empty_plot"
|
||||||
|
|
||||||
|
local inv = m:get_inventory()
|
||||||
|
|
||||||
|
if not ns.check_recipe(inv, plot) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
ns.place_plot(grid, gpos, plot, tostring(node.param2 *90))
|
||||||
|
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
function ns.show_constructor_interface(pos, p)
|
||||||
|
local name = p:get_player_name()
|
||||||
|
local fs = "\
|
||||||
|
formspec_version[10]\
|
||||||
|
size[12,10]\
|
||||||
|
list[nodemeta:"..pos.x..","..pos.y..","..pos.z..";main;1,1;3.5,3.5]\
|
||||||
|
list[player:"..name..";main;1,5;10,4]\
|
||||||
|
"
|
||||||
|
minetest.show_formspec(name, "constructor:"..pos.x..","..pos.y..","..pos.z, fs)
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_on_player_receive_fields(function(p, form, data)
|
||||||
|
if form:sub(1, string.len("constructor:")) == "constructor:" then
|
||||||
|
local x, y, z = form:match "constructor:(%d+),(%d+),(%d+)"
|
||||||
|
if not (x and y and z) then return end
|
||||||
|
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,288 @@
|
||||||
local ns = rgt_towns
|
local ns = rgt_towns
|
||||||
|
local db = minetest.get_mod_storage()
|
||||||
|
|
||||||
function ns.get_grid()
|
ns.grids = minetest.parse_json(db:get("grids") or "{}")
|
||||||
|
|
||||||
|
-- Calculates the Euclidean distance squared between two points (avoids sqrt for efficiency)
|
||||||
|
local function distance_squared(p1, p2)
|
||||||
|
local dx = p1.x - p2.x
|
||||||
|
local dy = p1.y - p2.y
|
||||||
|
local dz = p1.z - p2.z
|
||||||
|
return dx * dx + dy * dy + dz * dz
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Returns the point in the AABB farthest from the given point
|
||||||
|
-- aabb: table with {min = {x, y, z}, max = {x, y, z}}
|
||||||
|
-- point: table with {x, y, z}
|
||||||
|
-- Returns: table {x, y, z} representing the farthest corner
|
||||||
|
local function get_farthest_point_in_aabb(aabb, point)
|
||||||
|
-- Ensure input validity
|
||||||
|
if not aabb or not aabb.min or not aabb.max or not point then
|
||||||
|
error("Invalid input: aabb or point is missing required fields")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- List all eight corners of the AABB
|
||||||
|
local corners = {
|
||||||
|
{x = aabb.min.x, y = aabb.min.y, z = aabb.min.z},
|
||||||
|
{x = aabb.min.x, y = aabb.min.y, z = aabb.max.z},
|
||||||
|
{x = aabb.min.x, y = aabb.max.y, z = aabb.min.z},
|
||||||
|
{x = aabb.min.x, y = aabb.max.y, z = aabb.max.z},
|
||||||
|
{x = aabb.max.x, y = aabb.min.y, z = aabb.min.z},
|
||||||
|
{x = aabb.max.x, y = aabb.min.y, z = aabb.max.z},
|
||||||
|
{x = aabb.max.x, y = aabb.max.y, z = aabb.min.z},
|
||||||
|
{x = aabb.max.x, y = aabb.max.y, z = aabb.max.z},
|
||||||
|
}
|
||||||
|
|
||||||
|
local max_dist_sq = -1
|
||||||
|
local farthest_point = nil
|
||||||
|
|
||||||
|
-- Iterate through corners to find the one with maximum distance
|
||||||
|
for _, corner in ipairs(corners) do
|
||||||
|
local dist_sq = distance_squared(point, corner)
|
||||||
|
if dist_sq > max_dist_sq then
|
||||||
|
max_dist_sq = dist_sq
|
||||||
|
farthest_point = corner
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return farthest_point
|
||||||
|
end
|
||||||
|
|
||||||
|
function aabb_intersects_sphere(aabb, center, radius)
|
||||||
|
-- Ensure input validity
|
||||||
|
if not aabb or not aabb.min or not aabb.max or not center or not radius or radius < 0 then
|
||||||
|
error("Invalid input: aabb, center, or radius is missing or invalid")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find the closest point in the AABB to the sphere's center
|
||||||
|
local closest = {
|
||||||
|
x = math.max(aabb.min.x, math.min(center.x, aabb.max.x)),
|
||||||
|
y = math.max(aabb.min.y, math.min(center.y, aabb.max.y)),
|
||||||
|
z = math.max(aabb.min.z, math.min(center.z, aabb.max.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Check if the closest point is within the sphere's radius
|
||||||
|
local dist_squared = distance_squared(center, closest)
|
||||||
|
return dist_squared <= radius * radius
|
||||||
|
end
|
||||||
|
|
||||||
|
AABB = setmetatable({
|
||||||
|
intersects = function(a, b, c)
|
||||||
|
if c then
|
||||||
|
return a.min.x < c.x and a.max.x > b.x and
|
||||||
|
a.min.y < c.y and a.max.y > b.y and
|
||||||
|
a.min.z < c.z and a.max.z > b.z
|
||||||
|
end
|
||||||
|
return a.min.x < b.max.x and a.max.x > b.min.x and
|
||||||
|
a.min.y < b.max.y and a.max.y > b.min.y and
|
||||||
|
a.min.z < b.max.z and a.max.z > b.min.z
|
||||||
|
end,
|
||||||
|
intersects_2d = function(a, b, c)
|
||||||
|
if c then
|
||||||
|
return a.min.x < c.x and a.max.x > b.x and
|
||||||
|
a.min.z < c.z and a.max.z > b.z
|
||||||
|
end
|
||||||
|
return a.min.x < b.max.x and a.max.x > b.min.x and
|
||||||
|
a.min.z < b.max.z and a.max.z > b.min.z
|
||||||
|
end
|
||||||
|
}, {
|
||||||
|
__call = function(_, min, max)
|
||||||
|
min, max = vector.sort(min, max)
|
||||||
|
return setmetatable({
|
||||||
|
min = min,
|
||||||
|
max = max
|
||||||
|
}, {__index = AABB})
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
local repl = {
|
local repl = {
|
||||||
-- ["default:dirt"] = "adrift:dirt",
|
-- ["default:dirt"] = "adrift:dirt",
|
||||||
-- ["default:wood"] = "adrift:water"
|
-- ["default:wood"] = "adrift:water"
|
||||||
}
|
}
|
||||||
|
|
||||||
function ns.place_plot(plot, pos)
|
local function get_intersecting_grid_cells(aabb, origin, cell_size)
|
||||||
minetest.place_schematic(pos, ns.plots[plot].schematic, nil, repl, true, {place_center_x = true, place_center_z = true})
|
-- Ensure input validity
|
||||||
|
if not aabb or not aabb.min or not aabb.max or not origin or not cell_size then
|
||||||
|
error("Invalid input: aabb, origin, or cell_size is missing required fields")
|
||||||
|
end
|
||||||
|
if cell_size.x <= 0 or cell_size.y <= 0 or cell_size.z <= 0 then
|
||||||
|
error("Invalid input: cell_size components must be positive")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Convert AABB min and max to cell coordinates (relative to origin)
|
||||||
|
local min_cell = {
|
||||||
|
x = math.floor((aabb.min.x - origin.x) / cell_size.x),
|
||||||
|
y = math.floor((aabb.min.y - origin.y) / cell_size.y),
|
||||||
|
z = math.floor((aabb.min.z - origin.z) / cell_size.z)
|
||||||
|
}
|
||||||
|
local max_cell = {
|
||||||
|
x = math.floor((aabb.max.x - origin.x) / cell_size.x),
|
||||||
|
y = math.floor((aabb.max.y - origin.y) / cell_size.y),
|
||||||
|
z = math.floor((aabb.max.z - origin.z) / cell_size.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Collect all cell positions in the range [min_cell, max_cell]
|
||||||
|
local cells = {}
|
||||||
|
for x = min_cell.x, max_cell.x do
|
||||||
|
for y = min_cell.y, max_cell.y do
|
||||||
|
for z = min_cell.z, max_cell.z do
|
||||||
|
table.insert(cells, {x = x, y = y, z = z})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return cells
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mag_floor(a)
|
||||||
|
return a < 0 and math.ceil(a) or math.floor(a)
|
||||||
|
end
|
||||||
|
local function mag_ceil(a)
|
||||||
|
return a < 0 and math.floor(a) or math.ceil(a)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ns.can_build_plot(box, grid)
|
||||||
|
local w = box.max.x -box.min.x
|
||||||
|
local h = box.max.y -box.min.y
|
||||||
|
local l = box.max.z -box.min.z
|
||||||
|
for name, grid2 in pairs(ns.grids) do
|
||||||
|
local i = aabb_intersects_sphere(box, grid2.origin, grid2.radius)
|
||||||
|
if name == grid or i then
|
||||||
|
ns.add_cube(box.min, box.max, {color = "#fff"})
|
||||||
|
-- Translate box to grid2 local space and compute candidate cell range
|
||||||
|
local min = vector.floor((box.min -grid2.origin) /15)
|
||||||
|
local max = vector.ceil((box.max -grid2.origin) /15)
|
||||||
|
|
||||||
|
ns.add_cube(min *15 +grid2.origin, max *15 +grid2.origin)
|
||||||
|
|
||||||
|
if grid2.type == "3d" then
|
||||||
|
-- TODO: implement
|
||||||
|
else
|
||||||
|
for x = min.x, max.x do
|
||||||
|
for z = min.z, max.z do
|
||||||
|
ns.add_point(vector.new(x,0,z) *15 +grid2.origin)
|
||||||
|
-- print("Box: "..dump(box).."; min: "..min:to_string().."; max: "..max:to_string())
|
||||||
|
local plot = db:get("plot:"..name.."_"..x.."_0_"..z)
|
||||||
|
if plot then
|
||||||
|
plot = minetest.parse_json(plot)
|
||||||
|
if box:intersects_2d(plot.bb_min, plot.bb_max) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
Grid types:
|
||||||
|
* "2d": A two-dimensional grid. Building multiple plots within the same horizontal space is not allowed, but plots may change Y level in any way.
|
||||||
|
* "3d": A three-dimensional grid. Multiple plots can be constructed within the same column, but changes in Y level must be quantized to the size of the grid cells.
|
||||||
|
* "2d_staggered": A staggered 2d grid. This is the same as "2d" except that the center of a given cell's edge will correspond to the top and bottom edges of the two neighboring cells.
|
||||||
|
]]
|
||||||
|
function ns.create_grid(grid, pos, type)
|
||||||
|
ns.grids[grid] = {
|
||||||
|
type = type,
|
||||||
|
origin = pos,
|
||||||
|
radius = 0
|
||||||
|
}
|
||||||
|
db:set_string("grids", minetest.write_json(ns.grids))
|
||||||
|
end
|
||||||
|
|
||||||
|
function ns.delete_grid(grid)
|
||||||
|
ns.grids[grid] = nil
|
||||||
|
db:set_string("grids", minetest.write_json(ns.grids))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param grid: Grid in which to place the plot.
|
||||||
|
--- @param pos: Position within `grid` at which to build the plot.
|
||||||
|
function ns.place_plot(grid, pos, plot, owner, rot)
|
||||||
|
local gpos
|
||||||
|
if ns.grids[grid] then
|
||||||
|
gpos = ns.grids[grid].origin
|
||||||
|
else
|
||||||
|
warn("Failed to place a plot on unknown grid `"..grid.."`.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local def = ns.plots[plot]
|
||||||
|
local dst = (pos *15 +gpos):offset(-7,-def.size.y *7.5,-7)
|
||||||
|
local box = AABB(dst, dst +def.size *15)
|
||||||
|
|
||||||
|
if not ns.can_build_plot(box, grid) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
db:set_string("plot:"..grid.."_"..pos.x.."_0_"..pos.z, minetest.write_json {
|
||||||
|
bb_min = box.min,
|
||||||
|
bb_max = box.max,
|
||||||
|
owner = owner,
|
||||||
|
type = plot,
|
||||||
|
})
|
||||||
|
|
||||||
|
local g = ns.grids[grid]
|
||||||
|
-- Expand the town's radius to include the new plot, if necessary.
|
||||||
|
g.radius = math.max(g.radius, vector.distance(get_farthest_point_in_aabb(box, g.origin), g.origin))
|
||||||
|
|
||||||
|
local def = ns.plots[plot]
|
||||||
|
|
||||||
|
minetest.place_schematic(dst, def.schematic, rot, repl, true, {})
|
||||||
|
|
||||||
|
local p, gp, m
|
||||||
|
|
||||||
|
-- Place constructors along Z axis
|
||||||
|
for x = 0, def.size.x -1 do
|
||||||
|
gp = pos:offset(x, 0,-1)
|
||||||
|
p = dst:offset(x *15 +7, def.ground_level, 0)
|
||||||
|
if db:contains("plot:"..grid.."_"..gp.x.."_"..gp.y.."_"..gp.z) then
|
||||||
|
-- Remove adjacent constructors, and don't place new ones.
|
||||||
|
minetest.remove_node(p:offset(0,0,-1))
|
||||||
|
else
|
||||||
|
minetest.set_node(p, {name = "rgt_towns:constructor"})
|
||||||
|
m = minetest.get_meta(p)
|
||||||
|
m:set_string("grid", grid)
|
||||||
|
m:set_string("build_pos", gp:to_string())
|
||||||
|
end
|
||||||
|
|
||||||
|
gp = pos:offset(x, 0, 1)
|
||||||
|
p = dst:offset(x *15 +7, def.ground_level, def.size.z *15 -1)
|
||||||
|
if db:contains("plot:"..grid.."_"..gp.x.."_"..gp.y.."_"..gp.z) then
|
||||||
|
minetest.remove_node(p:offset(0,0,1))
|
||||||
|
else
|
||||||
|
minetest.set_node(p, {name = "rgt_towns:constructor"})
|
||||||
|
m = minetest.get_meta(p)
|
||||||
|
m:set_string("grid", grid)
|
||||||
|
m:set_string("build_pos", gp:to_string())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Place constructors along X axis
|
||||||
|
for z = 0, def.size.z -1 do
|
||||||
|
gp = pos:offset(-1, 0, z)
|
||||||
|
p = dst:offset(0, def.ground_level, z *15 +7)
|
||||||
|
if db:contains("plot:"..grid.."_"..gp.x.."_"..gp.y.."_"..gp.z) then
|
||||||
|
minetest.remove_node(p:offset(-1,0,0))
|
||||||
|
else
|
||||||
|
minetest.set_node(p, {name = "rgt_towns:constructor"})
|
||||||
|
m = minetest.get_meta(p)
|
||||||
|
m:set_string("grid", grid)
|
||||||
|
m:set_string("build_pos", pos:offset(-1, 0, z):to_string())
|
||||||
|
end
|
||||||
|
|
||||||
|
gp = pos:offset(1, 0, z)
|
||||||
|
p = dst:offset(def.size.x *15 -1, def.ground_level, z *15 +7)
|
||||||
|
if db:contains("plot:"..grid.."_"..gp.x.."_"..gp.y.."_"..gp.z) then
|
||||||
|
minetest.remove_node(p:offset(1,0,0))
|
||||||
|
else
|
||||||
|
minetest.set_node(p, {name = "rgt_towns:constructor"})
|
||||||
|
m = minetest.get_meta(p)
|
||||||
|
m:set_string("grid", grid)
|
||||||
|
m:set_string("build_pos", pos:offset(1, 0, z):to_string())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
@ -1,17 +1,35 @@
|
||||||
local ns = rgt_towns
|
local ns = rgt_towns
|
||||||
|
|
||||||
function ns.add_line(from, to)
|
function ns.add_line(from, to, args)
|
||||||
local dist = vector.distance(from, to)
|
local dist = vector.distance(from, to)
|
||||||
local vel = dist
|
local vel = dist
|
||||||
return minetest.add_particlespawner {
|
local ps = {
|
||||||
pos = from,
|
pos = from,
|
||||||
vel = vector.direction(from, to) *vel,
|
vel = vector.direction(from, to) *vel,
|
||||||
amount = dist *vel,
|
amount = dist *vel,
|
||||||
time = 0,
|
time = 0,
|
||||||
exptime = dist /vel,
|
exptime = dist /vel,
|
||||||
texture = "[fill:1x1:0,0:#35f",
|
texture = "[fill:1x1:0,0:"..(args.color or "#35f"),
|
||||||
glow = 14,
|
glow = 14,
|
||||||
}
|
}
|
||||||
|
if args.attach then
|
||||||
|
ps.attached = args.attach
|
||||||
|
end
|
||||||
|
return minetest.add_particlespawner(ps)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ns.add_point(point, args)
|
||||||
|
minetest.add_particlespawner {
|
||||||
|
pos = point,
|
||||||
|
velocity = {
|
||||||
|
min = vector.new(-1,-1,-1),
|
||||||
|
max = vector.new(1,1,1)
|
||||||
|
},
|
||||||
|
texture = args and args.color or "[fill:1x1:0,0:#faa",
|
||||||
|
time = 10,
|
||||||
|
amount = 50,
|
||||||
|
size = 5
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
|
|
@ -32,7 +50,8 @@ end
|
||||||
|
|
||||||
7 8
|
7 8
|
||||||
]]
|
]]
|
||||||
function ns.add_cube(from, to)
|
function ns.add_cube(from, to, args)
|
||||||
|
if not args then args = {} end
|
||||||
local p1 = from
|
local p1 = from
|
||||||
local p2 = vector.new(to.x, from.y, from.z)
|
local p2 = vector.new(to.x, from.y, from.z)
|
||||||
local p3 = vector.new(from.x, to.y, from.z)
|
local p3 = vector.new(from.x, to.y, from.z)
|
||||||
|
|
@ -42,24 +61,24 @@ function ns.add_cube(from, to)
|
||||||
local p7 = vector.new(from.x, to.y, to.z)
|
local p7 = vector.new(from.x, to.y, to.z)
|
||||||
local p8 = to
|
local p8 = to
|
||||||
return {
|
return {
|
||||||
ns.add_line(p1, p2),
|
ns.add_line(p1, p2, args),
|
||||||
ns.add_line(p1, p3),
|
ns.add_line(p1, p3, args),
|
||||||
ns.add_line(p1, p4),
|
ns.add_line(p1, p4, args),
|
||||||
|
|
||||||
ns.add_line(p4, p6),
|
ns.add_line(p4, p6, args),
|
||||||
ns.add_line(p4, p7),
|
ns.add_line(p4, p7, args),
|
||||||
|
|
||||||
ns.add_line(p2, p6),
|
ns.add_line(p2, p6, args),
|
||||||
|
|
||||||
|
|
||||||
ns.add_line(p8, p5),
|
ns.add_line(p8, p5, args),
|
||||||
ns.add_line(p8, p6),
|
ns.add_line(p8, p6, args),
|
||||||
ns.add_line(p8, p7),
|
ns.add_line(p8, p7, args),
|
||||||
|
|
||||||
ns.add_line(p5, p2),
|
ns.add_line(p5, p2, args),
|
||||||
ns.add_line(p5, p3),
|
ns.add_line(p5, p3, args),
|
||||||
|
|
||||||
ns.add_line(p7, p3),
|
ns.add_line(p7, p3, args),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ function ns.place_workspace(name, pos)
|
||||||
pos = pos:round()
|
pos = pos:round()
|
||||||
ws = {
|
ws = {
|
||||||
pos = pos,
|
pos = pos,
|
||||||
size = vector.new(1,4,1)
|
size = vector.new(1,2,1)
|
||||||
}
|
}
|
||||||
db:set_string("workspace:"..name, minetest.serialize(ws))
|
db:set_string("workspace:"..name, minetest.serialize(ws))
|
||||||
minetest.add_entity(ns.get_workspace_center(pos, ws.size), "rgt_towns_editor:workspace", name)
|
minetest.add_entity(ns.get_workspace_center(pos, ws.size), "rgt_towns_editor:workspace", name)
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,20 @@ rgt_towns.main = {}
|
||||||
ns = rgt_towns.main
|
ns = rgt_towns.main
|
||||||
|
|
||||||
ns.plots = {
|
ns.plots = {
|
||||||
|
"empty_plot"
|
||||||
}
|
}
|
||||||
|
|
||||||
rgt_towns.register_spawner {
|
rgt_towns.register_spawner {
|
||||||
plot = "covered_wagon",
|
plot = "empty_plot",
|
||||||
label = "Town Charter"
|
label = "Town Charter",
|
||||||
|
on_spawn = function(p)
|
||||||
|
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
minetest.register_chatcommand("charter", {
|
minetest.register_chatcommand("charter", {
|
||||||
func = function(name, args)
|
func = function(name, args)
|
||||||
minetest.get_player_by_name(name):get_inventory():add_item("main", rgt_towns.create_spawner("covered_wagon"))
|
minetest.get_player_by_name(name):get_inventory():add_item("main", rgt_towns.create_spawner("empty_plot", name))
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -21,5 +24,20 @@ rgt_towns.register_plot{
|
||||||
label = "Covered Wagon",
|
label = "Covered Wagon",
|
||||||
description = "Hello world",
|
description = "Hello world",
|
||||||
schematic = minetest.get_modpath(minetest.get_current_modname()).."/schems/covered_wagon.mts",
|
schematic = minetest.get_modpath(minetest.get_current_modname()).."/schems/covered_wagon.mts",
|
||||||
|
recipe = {},
|
||||||
|
can_build = ns.plots
|
||||||
|
}
|
||||||
|
|
||||||
|
rgt_towns.register_plot{
|
||||||
|
name = "empty_plot",
|
||||||
|
label = "Empty Plot",
|
||||||
|
description = "Hello world",
|
||||||
|
schematic = minetest.get_modpath(minetest.get_current_modname()).."/schems/empty_plot.mts",
|
||||||
|
recipe = {
|
||||||
|
"", "", "",
|
||||||
|
"dirt_grass 1", "dirt_grass 1", "dirt_grass 1",
|
||||||
|
"dirt 1", "dirt 1", "dirt 1",
|
||||||
|
},
|
||||||
|
ground_level = 5,
|
||||||
can_build = ns.plots
|
can_build = ns.plots
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
mods/rgt_towns/rgt_towns_main/schems/empty_plot.mts
Normal file
BIN
mods/rgt_towns/rgt_towns_main/schems/empty_plot.mts
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue