1114 lines
34 KiB
Lua
1114 lines
34 KiB
Lua
-- Squaresville buildings.lua
|
|
-- Copyright Duane Robertson (duane@duanerobertson.com), 2017
|
|
-- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html)
|
|
|
|
|
|
local civ_base = squaresville.civ_base
|
|
local dangerous = squaresville.dangerous_terrain
|
|
local desolation = 0
|
|
local math_abs = math.abs
|
|
local math_floor = math.floor
|
|
local math_random = math.random
|
|
local node = squaresville.node
|
|
local pr = squaresville.pr
|
|
local breaker = squaresville.breaker
|
|
|
|
local node_air = node['air']
|
|
local node_beacon = node['squaresville:beacon_1']
|
|
local node_concrete_stair = node['squaresville:concrete_stair']
|
|
local node_dirt = node['default:dirt']
|
|
local node_door_glass = node['doors:door_glass_b']
|
|
local node_floor_ceiling = node['squaresville:floor_ceiling']
|
|
local node_gargoyle = node['squaresville:gargoyle']
|
|
local node_light_panel = node['squaresville:light_panel']
|
|
local node_plaster = node['squaresville:plaster']
|
|
local node_plate_glass = node['squaresville:plate_glass']
|
|
local node_roof = squaresville.node['squaresville:roof']
|
|
local node_steelblock = node['default:steelblock']
|
|
local node_water = node['default:water_source']
|
|
|
|
|
|
local ores = {}
|
|
ores['oremask:ore'] = true
|
|
ores['default:stone_with_coal'] = true
|
|
ores['default:stone_with_iron'] = true
|
|
ores['default:stone_with_copper'] = true
|
|
ores['default:stone_with_tin'] = true
|
|
|
|
|
|
local drotn = {[0]=3, 0, 1, 2, 19, 16, 17, 18, 15, 12, 13, 14, 7, 4, 5, 6, 11, 8, 9, 10, 21, 22, 23, 20}
|
|
local drotp = {}
|
|
for i = 0, 23 do
|
|
for j = 0, 23 do
|
|
if drotn[j] == i then
|
|
drotp[i] = j
|
|
break
|
|
end
|
|
end
|
|
end
|
|
local drotwn = {[0]=0, 1, 4, 5, 3, 2, 0, 0}
|
|
local drotwp = {}
|
|
for i = 0, 7 do
|
|
for j = 0, 7 do
|
|
if drotwn[j] == i then
|
|
drotwp[i] = j
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
for _, filename in pairs(minetest.get_dir_list(squaresville.path.."/schematics/")) do
|
|
if string.find(filename, "^[%a%d_]+%.house$") then
|
|
local file = io.open(squaresville.path.."/schematics/"..filename, "rb")
|
|
if file then
|
|
local data = file:read("*all")
|
|
file:close()
|
|
local new_data = minetest.deserialize(data)
|
|
local t_data = {}
|
|
|
|
index = 1
|
|
for z = 0, new_data.size.z - 1 do
|
|
for y = 0, new_data.size.y - 1 do
|
|
for x = 0, new_data.size.x - 1 do
|
|
if new_data.data[index].prob == 0 or new_data.data[index].name == 'air' or new_data.data[index].name == 'ignore' then
|
|
-- nop
|
|
else
|
|
t_data[#t_data+1] = {
|
|
name = new_data.data[index].name,
|
|
prob = new_data.data[index].prob,
|
|
param2 = new_data.data[index].param2,
|
|
x = x,
|
|
y = y,
|
|
z = z,
|
|
}
|
|
end
|
|
index = index + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
squaresville.house_schematics[#squaresville.house_schematics+1] = t_data
|
|
|
|
print("Squaresville: loaded "..filename)
|
|
end
|
|
elseif string.find(filename, "^[%a%d_]+%.we$") then
|
|
local file = io.open(squaresville.path.."/schematics/"..filename, "rb")
|
|
if file then
|
|
local data = file:read("*all")
|
|
file:close()
|
|
|
|
v, sep_data = data:match('([0-9]):(.*)')
|
|
local new_data = minetest.deserialize(sep_data)
|
|
|
|
squaresville.house_schematics[#squaresville.house_schematics+1] = new_data
|
|
|
|
print("Squaresville: loaded "..filename)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
minetest.register_privilege('saveplot', {description = 'Allow user to save squaresville plots.'})
|
|
minetest.register_chatcommand("saveplot", {
|
|
params = "[filename]",
|
|
description = "save the plot you're in as a schematic file",
|
|
privs = {saveplot=true}, -- Require the "saveplot" privilege to run
|
|
func = function(name, param)
|
|
local filename = param
|
|
if not filename or filename == "" or string.find(filename, "[^%a%d_]") then
|
|
print("* Squaresville: Specify a simple filename containing digits and letters. The suffix will be added automatically. Paths are not allowed.")
|
|
return
|
|
end
|
|
|
|
local pos = minetest.get_player_by_name(name):getpos()
|
|
local civ = squaresville.get_zone({x=pos.x, z=pos.z})
|
|
local suburb_orient = 0
|
|
local max_schem_height = 20
|
|
local house_size = math_floor(squaresville.block_size / 2)
|
|
local suffix = civ.city and '_floor.we' or '_house.we'
|
|
filename = minetest.get_worldpath().."/"..filename..suffix
|
|
|
|
local p1, p2 = {}, {}
|
|
local px, pz = 0, 0
|
|
|
|
if pos.y >= squaresville.baseline and pos.y <= squaresville.baseline + squaresville.extent_top then
|
|
p1.y = squaresville.baseline + civ_base - 1
|
|
elseif pos.y >= squaresville.baseline_ruin and pos.y <= squaresville.baseline_ruin + squaresville.extent_top_ruin then
|
|
p1.y = squaresville.baseline_ruin + civ_base - 1
|
|
end
|
|
|
|
if pos.y - p1.y < 0 or (pos.y - p1.y > max_schem_height and not civ.city) then
|
|
print("* Squaresville cannot determine coordinates for plotsave.")
|
|
return
|
|
end
|
|
|
|
p1.x = math_floor((pos.x + squaresville.max_height + squaresville.half_road_size) / squaresville.block_plus_road_size) * squaresville.block_plus_road_size - squaresville.max_height - squaresville.half_road_size + squaresville.road_size
|
|
if (not civ.city) and pos.x - p1.x >= house_size then
|
|
p1.x = p1.x + house_size
|
|
px = 1
|
|
end
|
|
p1.z = math_floor((pos.z + squaresville.max_height + squaresville.half_road_size) / squaresville.block_plus_road_size) * squaresville.block_plus_road_size - squaresville.max_height - squaresville.half_road_size + squaresville.road_size + 0
|
|
if (not civ.city) and pos.z - p1.z >= house_size then
|
|
p1.z = p1.z + house_size
|
|
pz = 1
|
|
end
|
|
|
|
if civ.city then
|
|
p1.x = p1.x + 3
|
|
p1.y = math_floor((pos.y - p1.y) / 4) * 4 + p1.y + 1
|
|
p1.z = p1.z + 3
|
|
p2.x = p1.x + squaresville.block_size - 7
|
|
p2.y = p1.y + 3
|
|
p2.z = p1.z + squaresville.block_size - 7
|
|
else
|
|
p2.x = p1.x + house_size - 1
|
|
p2.y = p1.y + max_schem_height
|
|
p2.z = p1.z + house_size - 1
|
|
end
|
|
|
|
local rot
|
|
if civ.city then
|
|
local floor = math_floor((pos.y - p1.y) / 4)
|
|
rot = (floor % 2 == 0) and 0 or 2
|
|
else
|
|
if suburb_orient == 0 then
|
|
rot = pz * 2
|
|
else
|
|
rot = px * 2 + 1
|
|
end
|
|
end
|
|
|
|
local vm = minetest.get_voxel_manip()
|
|
local emin, emax = vm:read_from_map(p1, p2)
|
|
local data = vm:get_data()
|
|
local p2data = vm:get_param2_data()
|
|
local a = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
|
|
|
if (not civ.city) and param ~= 'prep' then
|
|
local height
|
|
for y = emax.y, emin.y, -1 do
|
|
for z = p1.z, p2.z do
|
|
local ivm = a:index(p1.x, y, z)
|
|
for x = p1.x, p2.x do
|
|
if not height and data[ivm] ~= node_air and data[ivm] ~= squaresville.node["ignore"] then
|
|
height = y
|
|
end
|
|
ivm = ivm + 1
|
|
end
|
|
end
|
|
end
|
|
p2.y = height
|
|
end
|
|
|
|
local maxi = vector.add(vector.subtract(p2, p1), 1)
|
|
local t_data = {}
|
|
|
|
for z1 = 0, maxi.z - 1 do
|
|
for x1 = 0, maxi.x - 1 do
|
|
local x, z
|
|
if rot == 0 then
|
|
x, z = x1, z1
|
|
elseif rot == 1 then
|
|
x, z = z1, maxi.x - x1 - 1
|
|
elseif rot == 2 then
|
|
x, z = maxi.x - x1 - 1, maxi.z - z1 - 1
|
|
elseif rot == 3 then
|
|
x, z = maxi.z - z1 - 1, x1
|
|
end
|
|
|
|
local ivm = a:index(p1.x + x1, p1.y, p1.z + z1)
|
|
for y = 0, maxi.y - 1 do
|
|
if civ.city and param == 'prep' then
|
|
if y == 0 then
|
|
data[ivm] = squaresville.node['squaresville:floor_ceiling']
|
|
else
|
|
data[ivm] = node_air
|
|
end
|
|
elseif (not civ.city) and param == 'prep' then
|
|
if y == 0 then
|
|
data[ivm] = squaresville.node['default:dirt']
|
|
elseif y == 1 and (((pz == 1 and z1 >= maxi.z - 2) or (pz == 0 and z1 < 2)) or ((px == 1 and x1 >= maxi.x - 2) or (px == 0 and x1 < 2))) then
|
|
data[ivm] = squaresville.node['squaresville:sidewalk']
|
|
elseif y == 1 then
|
|
data[ivm] = squaresville.node['default:dirt_with_grass']
|
|
elseif y == 2 and (x1 == 0 or x1 == maxi.x - 1) and (z1 == 0 or z1 == maxi.z - 1) then
|
|
data[ivm] = squaresville.node['default:dirt']
|
|
else
|
|
data[ivm] = node_air
|
|
end
|
|
else
|
|
local node = {}
|
|
node.name = minetest.get_name_from_content_id(data[ivm])
|
|
|
|
-- Remove accidental ores (only... I hope).
|
|
if y <= 1 and ores[node.name] then
|
|
node.name = 'default:stone'
|
|
end
|
|
|
|
node.param2 = p2data[ivm]
|
|
if node.name == "air" then
|
|
-- nop
|
|
elseif (not civ.city) and y == 1 and (z < 2 or x < 2 or x >= maxi.x - 2 or z >= maxi.z - 2) and (node.name == 'squaresville:sidewalk' or node.name == 'default:dirt_with_grass') then
|
|
-- nop
|
|
elseif (not civ.city) and y == 2 and (z < 2 or x < 2 or x >= maxi.x - 2 or z >= maxi.z - 2) and node.name == 'squaresville:streetlight' then
|
|
-- nop
|
|
else
|
|
if minetest.registered_items[node.name] then
|
|
local ptype = minetest.registered_items[node.name].paramtype2
|
|
if ptype == 'wallmounted' or ptype == 'colorwallmounted' then
|
|
local dir = (node.param2 or 0) % 8
|
|
local extra = (node.param2 or 0) - dir
|
|
for i = 1, rot do
|
|
dir = drotwn[dir]
|
|
end
|
|
node.param2 = dir + extra
|
|
elseif ptype == 'facedir' then
|
|
local dir = (node.param2 or 0) % 24
|
|
local extra = (node.param2 or 0) - dir
|
|
for i = 1, rot do
|
|
dir = drotn[dir]
|
|
end
|
|
node.param2 = dir + extra
|
|
elseif ptype ~= 'none' then
|
|
--print(node.name, ptype)
|
|
end
|
|
elseif node.name ~= 'ignore' then
|
|
--print(node.name)
|
|
end
|
|
|
|
local pos = {x=p1.x + x1, y=p1.y + y, z=p1.z + z1}
|
|
local meta = minetest.get_meta(pos):to_table()
|
|
if next(meta.inventory) or next(meta.fields) then
|
|
for n, v in pairs(meta.inventory) do
|
|
for i, s in ipairs(v) do
|
|
v[i] = s:to_string()
|
|
end
|
|
end
|
|
|
|
node.meta = meta
|
|
end
|
|
|
|
node.x = x
|
|
node.y = y
|
|
node.z = z
|
|
|
|
t_data[#t_data+1] = node
|
|
end
|
|
end
|
|
|
|
ivm = ivm + a.ystride
|
|
end
|
|
end
|
|
end
|
|
|
|
if param == 'prep' then
|
|
vm:set_data(data)
|
|
vm:calc_lighting()
|
|
vm:update_liquids()
|
|
vm:write_to_map()
|
|
else
|
|
local file = io.open(filename, "wb")
|
|
if file then
|
|
table.sort(t_data, function(a,b)
|
|
if a.z < b.z then
|
|
return true
|
|
elseif a.z > b.z then
|
|
return false
|
|
elseif a.y < b.y then
|
|
return true
|
|
elseif a.y > b.y then
|
|
return false
|
|
elseif a.x < b.x then
|
|
return true
|
|
elseif a.x > b.x then
|
|
return false
|
|
else
|
|
return false
|
|
end
|
|
end)
|
|
local data = '5:'..minetest.serialize(t_data)
|
|
file:write(data)
|
|
file:close()
|
|
end
|
|
print("Squaresville saved a schematic to \""..filename.."\"")
|
|
end
|
|
end,
|
|
})
|
|
|
|
|
|
local function crates(data, pos1, pos2)
|
|
local y = math.min(pos2.y, pos1.y)
|
|
for z = pos1.z,pos2.z do
|
|
for x = pos1.x,pos2.x do
|
|
if (data[x][y][z] == node_air or data[x][y][z] == nil) and math_random(1000) == 1 then
|
|
data[x][y][z] = squaresville.node['squaresville:crate']
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function lights(write, read, pos1, pos2)
|
|
if not squaresville.light_panels then
|
|
return
|
|
end
|
|
|
|
local y = math.max(pos2.y, pos1.y)
|
|
for z = pos1.z,pos2.z do
|
|
for x = pos1.x,pos2.x do
|
|
if (read(x, y, z) == node_air or read(x, y, z) == nil) and (read(x,y+1,z) == node_floor_ceiling or read(x, y+1, z) == node_roof) and (x % 3 == 1 and z % 3 == 1) then
|
|
write(x, y, z, node_light_panel, 20) -- 20-23
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function doors(write, size, tex, off)
|
|
if not off then
|
|
off = 0
|
|
end
|
|
|
|
for z1 = 0+off, size-off, size-(off*2) do
|
|
for x = math_floor(size / 2) - 2, math_floor(size / 2) + 2 do
|
|
for y = 1, 3 do
|
|
if y < 3 and x == math_floor(size / 2) then
|
|
write(x, y, z1, tex)
|
|
elseif y < 3 and math_abs(x - math_floor(size / 2)) < 2 then
|
|
if y == 1 then
|
|
if z1 > 1 then
|
|
write(x, y, z1, node_door_glass, 2)
|
|
else
|
|
write(x, y, z1, node_door_glass, 0)
|
|
end
|
|
else
|
|
write(x, y, z1, node_air)
|
|
end
|
|
else
|
|
write(x, y, z1, tex)
|
|
end
|
|
end
|
|
local z = z1 - 1
|
|
if z > 1 then
|
|
z = z1 + 1
|
|
end
|
|
for y = 1, 3 do
|
|
if off == 1 and (y == 3 or math_abs(x - math_floor(size / 2)) == 2) then
|
|
write(x, y, z, tex)
|
|
else
|
|
write(x, y, z, node_air)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for x1 = 0+off, size-off, size-(off*2) do
|
|
for z = math_floor(size / 2) - 2, math_floor(size / 2) + 2 do
|
|
for y = 1, 3 do
|
|
if y < 3 and z == math_floor(size / 2) then
|
|
write(x1, y, z, tex)
|
|
elseif y < 3 and math_abs(z - math_floor(size / 2)) < 2 then
|
|
if y == 1 then
|
|
if x1 > 1 then
|
|
write(x1, y, z, node_door_glass, 3)
|
|
else
|
|
write(x1, y, z, node_door_glass, 1)
|
|
end
|
|
else
|
|
write(x1, y, z, node_air)
|
|
end
|
|
else
|
|
write(x1, y, z, tex)
|
|
end
|
|
end
|
|
local x = x1 - 1
|
|
if x > 1 then
|
|
x = x1 + 1
|
|
end
|
|
for y = 1, 3 do
|
|
if off == 1 and (y == 3 or math_abs(z - math_floor(size / 2)) == 2) then
|
|
write(x, y, z, tex)
|
|
else
|
|
write(x, y, z, node_air)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function roof_box(write, size, off, sy, tex)
|
|
for z = off,size-off+1 do
|
|
for x = off,size-off+1 do
|
|
for y = sy+1,sy+3 do
|
|
if z == off or z == size-off+1 or x == off or x == size-off+1 then
|
|
if y < sy + 3 and x == size - off + 1 and z == math_floor(size / 2) then
|
|
write(x, y, z, node_air)
|
|
else
|
|
write(x, y, z, tex)
|
|
end
|
|
end
|
|
end
|
|
if z > off and z < size-off+1 and x > off and x < size-off+1 then
|
|
write(x, sy+3, z, node_roof)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function beacons(write, size, floor)
|
|
for z = 2,size-2 do
|
|
for x = 2,size-2 do
|
|
local y = floor * 4 + 1
|
|
if floor > 9 and (z == 2 or z == size - 2) and (x == 2 or x == size - 2) then
|
|
write(x, y, z, node_beacon)
|
|
elseif math_random(400) == 1 then
|
|
write(x, y, z, node_steelblock)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function stairwell(write, pos1, pos2, left)
|
|
local size, px, py, pz
|
|
size = (left and 0 or 2)
|
|
|
|
px = math_floor((pos2.x - pos1.x - 4) / 2)
|
|
py = math.min(pos2.y, pos1.y)
|
|
pz = math_floor((pos2.z - pos1.z - 6) / 2)
|
|
local walls = px > 2 and pz > 2
|
|
|
|
if walls then
|
|
for z = 1+size,6+size do
|
|
for x = 1,4 do
|
|
for y = 1,3 do
|
|
if z == 1+size or z == 6+size or x == 1 or x == 4 then
|
|
if left and x == 2 and z == 1 and y < 3 then
|
|
write(x + px, y + py, z + pz, node_air)
|
|
elseif not left and x == 3 and z == 6+size and y < 3 then
|
|
write(x + px, y + py, z + pz, node_air)
|
|
else
|
|
write(x + px, y + py, z + pz, node_plaster)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if left then
|
|
for i = 1,4 do
|
|
write(2 + px, i + py, 2 + i + pz, node_concrete_stair)
|
|
end
|
|
for i = 1,3 do
|
|
write(2 + px, 4 + py, 2 + i + pz, node_air)
|
|
end
|
|
else
|
|
for i = 1,4 do
|
|
write(3 + px, i + py, 7 - i + pz, node_concrete_stair, 4)
|
|
end
|
|
for i = 1,3 do
|
|
write(3 + px, 4 + py, 7 - i + pz, node_air)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function gotham(write, read, size)
|
|
local develop, wall_x, wall_x_2, wall_z, wall_z_2
|
|
local dir, y, floors, conc
|
|
|
|
local c = pr:next(1,5)
|
|
if c == 1 then
|
|
conc = node['squaresville:concrete']
|
|
else
|
|
conc = node['squaresville:concrete'..c]
|
|
end
|
|
|
|
local ra = pr:next(1, 2) - 1
|
|
floors = pr:next(1, 20) + 1
|
|
|
|
-- all this for gargoyles...
|
|
if pr:next(1, 2) == 1 and floors > 5 then
|
|
for z = -1,size+1 do
|
|
for x = -1,size+1 do
|
|
y = floors * 4
|
|
y = y - (y % 4)
|
|
if (x == -1 or x == size + 1) and z % 5 == 3 and z > -1 then
|
|
dir = (x == -1 and 18 or 12)
|
|
write(x, y, z, node_gargoyle, dir)
|
|
elseif (z == -1 or z == size + 1) and x % 5 == 3 and x > -1 then
|
|
dir = (z == -1 and 9 or 7)
|
|
write(x, y, z, node_gargoyle, dir)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for z = 0,size do
|
|
for x = 0,size do
|
|
develop = x > 0 and x < size and z > 0 and z < size
|
|
wall_x = x == 0 or x == size
|
|
wall_z = z == 0 or z == size
|
|
wall_x_2 = x == 1 or x == size - 1
|
|
wall_z_2 = z == 1 or z == size - 1
|
|
for y = 0,(floors * 4) do
|
|
if y % 4 == 0 and x > 1 and z > 1 and x < size - 1 and z < size - 1 then
|
|
if floors * 4 - y < 4 then
|
|
write(x, y, z, node_roof)
|
|
else
|
|
write(x, y, z, node_floor_ceiling)
|
|
end
|
|
elseif wall_x then
|
|
if y == 0 then
|
|
write(x, y, z, conc)
|
|
elseif z % 5 == 3 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_air)
|
|
end
|
|
elseif wall_x_2 and develop then
|
|
if y == 0 then
|
|
write(x, y, z, conc)
|
|
elseif y % 4 ~= 2 or z % 5 == 3 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_plate_glass)
|
|
end
|
|
elseif wall_z then
|
|
if y == 0 then
|
|
write(x, y, z, conc)
|
|
elseif x % 5 == 3 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_air)
|
|
end
|
|
elseif wall_z_2 and develop then
|
|
if y == 0 then
|
|
write(x, y, z, conc)
|
|
elseif y % 4 ~= 2 or x % 5 == 3 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_plate_glass)
|
|
end
|
|
else
|
|
write(x, y, z, node_air)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for f = 1,floors-ra do
|
|
stairwell(write, {x=2,y=((f-1)*4),z=2}, {x=size-1,y=(f*4-1),z=size-1}, (f / 2 == math_floor(f / 2)))
|
|
lights(write, read, {x=3,y=((f-1)*4),z=3}, {x=size-2,y=(f*4-1),z=size-2})
|
|
--crates(data, {x=3,y=((f-1)*4+1),z=3}, {x=size-2,y=((f-1)*4+1),z=size-2})
|
|
end
|
|
|
|
if ra == 0 then
|
|
roof_box(write, size, 15, floors * 4, conc)
|
|
end
|
|
|
|
beacons(write, size, floors)
|
|
|
|
doors(write, size, conc, 1)
|
|
end
|
|
|
|
|
|
local function glass_and_steel(write, read, size)
|
|
local develop, wall_x, wall_z, floors, conc
|
|
local c = pr:next(1, 5)
|
|
if c == 1 then
|
|
conc = node['squaresville:concrete']
|
|
else
|
|
conc = node['squaresville:concrete'..c]
|
|
end
|
|
|
|
local ra = pr:next(1, 2) - 1
|
|
floors = pr:next(1, 50) + 1
|
|
|
|
for z = 0,size do
|
|
for x = 0,size do
|
|
wall_x = x == 0 or x == size
|
|
wall_z = z == 0 or z == size
|
|
for y = 0,(floors * 4) do
|
|
if y % 4 == 0 and x > 0 and z > 0 and x < size and z < size then
|
|
if floors * 4 - y < 4 then
|
|
write(x, y, z, node_roof)
|
|
else
|
|
write(x, y, z, node_floor_ceiling)
|
|
end
|
|
elseif wall_x then
|
|
if (z - 2) % 5 == 2 then
|
|
write(x, y, z, conc)
|
|
elseif y == 0 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_plate_glass)
|
|
end
|
|
elseif wall_z then
|
|
if (x - 2) % 5 == 2 then
|
|
write(x, y, z, conc)
|
|
elseif y == 0 then
|
|
write(x, y, z, conc)
|
|
else
|
|
write(x, y, z, node_plate_glass)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for f = 1,floors-ra do
|
|
stairwell(write, {x=1,y=((f-1)*4),z=1}, {x=size,y=(f*4-1),z=size}, (f / 2 == math_floor(f / 2)))
|
|
lights(write, read, {x=1,y=((f-1)*4),z=1}, {x=size,y=(f*4-1),z=size})
|
|
--crates(data, {x=1,y=((f-1)*4+1),z=1}, {x=size,y=((f-1)*4+1),z=size})
|
|
end
|
|
|
|
if ra == 0 then
|
|
roof_box(write, size, 15, floors * 4, conc)
|
|
end
|
|
|
|
beacons(write, size, floors)
|
|
|
|
doors(write, size, conc)
|
|
end
|
|
|
|
|
|
local function simple(write, read, size, slit)
|
|
local develop, wall_x, wall_z, floors, conc, c
|
|
|
|
local ra = pr:next(1, 2) - 1
|
|
floors = pr:next(1, 10) + 1
|
|
|
|
if floors < 6 then
|
|
c = pr:next(1, 9)
|
|
else
|
|
c = pr:next(1, 5)
|
|
end
|
|
|
|
if c == 1 then
|
|
conc = node['squaresville:concrete']
|
|
elseif c == 6 then
|
|
conc = node['default:brick']
|
|
elseif c == 7 then
|
|
conc = node['default:sandstonebrick']
|
|
elseif c == 8 then
|
|
conc = node['default:stonebrick']
|
|
elseif c == 9 then
|
|
conc = node['default:desert_stonebrick']
|
|
else
|
|
conc = node['squaresville:concrete'..c]
|
|
end
|
|
|
|
for z = 0,size do
|
|
for x = 0,size do
|
|
wall_x = x == 0 or x == size
|
|
wall_z = z == 0 or z == size
|
|
for y = 0,(floors * 4) do
|
|
if y % 4 == 0 and x > 0 and z > 0 and x < size and z < size then
|
|
if floors * 4 == y then
|
|
write(x, y, z, node_roof)
|
|
else
|
|
write(x, y, z, node_floor_ceiling)
|
|
end
|
|
elseif wall_x then
|
|
if slit and z % 2 == 0 and y % 4 > 1 then
|
|
write(x, y, z, node_plate_glass)
|
|
elseif not slit and math_floor(z / 2) % 2 == 1 and y % 4 > 1 then
|
|
write(x, y, z, node_plate_glass)
|
|
else
|
|
write(x, y, z, conc)
|
|
end
|
|
elseif wall_z then
|
|
if slit and x % 2 == 0 and y % 4 > 1 then
|
|
write(x, y, z, node_plate_glass)
|
|
elseif not slit and math_floor(x / 2) % 2 == 1 and y % 4 > 1 then
|
|
write(x, y, z, node_plate_glass)
|
|
else
|
|
write(x, y, z, conc)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for f = 1,floors-ra do
|
|
stairwell(write, {x=1,y=((f-1)*4),z=1}, {x=size,y=(f*4-1),z=size}, (f / 2 == math_floor(f / 2)))
|
|
lights(write, read, {x=1,y=((f-1)*4),z=1}, {x=size,y=(f*4-1),z=size})
|
|
--crates(data, {x=1,y=((f-1)*4+1),z=1}, {x=size,y=((f-1)*4+1),z=size})
|
|
end
|
|
|
|
beacons(write, size, floors)
|
|
|
|
if ra == 0 then
|
|
roof_box(write, size, 15, floors * 4, conc)
|
|
end
|
|
|
|
doors(write, size, conc)
|
|
end
|
|
|
|
|
|
--squaresville.overgrow = function(write, read, size)
|
|
-- local sr
|
|
-- if squaresville.desolation > 0 then
|
|
-- for z = 0,size do
|
|
-- for x = 0,size do
|
|
-- sr = math_random(10)
|
|
-- if sr < 6 then
|
|
-- write(x, 1, z, "default:grass_"..sr)
|
|
-- elseif sr == 6 then
|
|
-- write(x, 1, z, "default:dry_shrub")
|
|
-- end
|
|
-- end
|
|
-- end
|
|
-- end
|
|
--end
|
|
|
|
|
|
local function shacks(write, read, get_index, size, suburb_orient, danger, biomemap)
|
|
local rot
|
|
local house_type = pr:next(1, #squaresville.house_schematics)
|
|
local plot_size = math_floor(squaresville.block_size / 2)
|
|
local yard = plot_size - 2
|
|
local space = 6
|
|
local floors = 2
|
|
local plot = math_floor((size - 4) / yard)
|
|
|
|
for pz = 0, plot do
|
|
for px = 0, plot do
|
|
if suburb_orient == 0 then
|
|
rot = pz * 2
|
|
else
|
|
rot = px * 2 + 1
|
|
end
|
|
|
|
local house = squaresville.house_schematics[(house_type + pz * 2 + px) % #squaresville.house_schematics + 1]
|
|
local off = {x=0, z=0}
|
|
if house.size then
|
|
off = {x=math_floor(math.max(0, yard - house.size.x + 1) / 2), z=math_floor(math.max(0, yard - house.size.z + 1) / 2)}
|
|
|
|
if px == 0 and house.size.x < plot_size then
|
|
off.x = off.x + 2
|
|
end
|
|
if pz == 0 and house.size.z < plot_size then
|
|
off.z = off.z + 2
|
|
end
|
|
end
|
|
|
|
for z = 0, plot_size - 1 do
|
|
for x = 0, plot_size - 1 do
|
|
local index_2d = get_index(x + px * plot_size - 2, z + pz * plot_size - 2) or 1
|
|
local name, biome
|
|
if index_2d then
|
|
biome = biomemap[index_2d]
|
|
if ((pz == 0 and z < 2) or (pz == 1 and z >= plot_size - 2) or (px == 0 and x < 2) or (px == 1 and x >= plot_size - 2)) then
|
|
name = 'squaresville:sidewalk'
|
|
else
|
|
name = biome.node_top or 'default:dirt'
|
|
end
|
|
end
|
|
|
|
if name then
|
|
write(x + px * plot_size - 2, 0, z + pz * plot_size - 2, node[name])
|
|
write(x + px * plot_size - 2, -1, z + pz * plot_size - 2, node_dirt)
|
|
if desolation > 0 then
|
|
-- *********************************
|
|
-- Fix this.
|
|
-- *********************************
|
|
--local decoration = node[squaresville.get_decoration(biome_name)]
|
|
--if decoration then
|
|
-- write(x + px * plot_size - 2, 1, z + pz * plot_size - 2, decoration)
|
|
--end
|
|
-- *********************************
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for house_node_name, house_node in pairs(house) do
|
|
if house_node_name == 'size' then
|
|
-- nop
|
|
else
|
|
local x, z
|
|
local x1, z1 = house_node.x, house_node.z
|
|
if rot == 0 then
|
|
x, z = x1, z1
|
|
elseif rot == 1 then
|
|
x, z = z1, plot_size - x1 - 1
|
|
elseif rot == 2 then
|
|
x, z = plot_size - x1 - 1, plot_size - z1 - 1
|
|
elseif rot == 3 then
|
|
x, z = plot_size - z1 - 1, x1
|
|
end
|
|
local y = house_node.y
|
|
|
|
local deco = nil
|
|
|
|
local prob = house_node.prob
|
|
if ((prob and prob == 0) or house_node.name == "ignore") then
|
|
-- nop
|
|
elseif (not prob or prob >= math_random(255)) and house_node.name ~= "air" then
|
|
local param2 = house_node.param2 or 0
|
|
|
|
-- This is gonna bite me.
|
|
if house_node.name == 'oremask:ore' then
|
|
house_node.name = 'default:stone'
|
|
end
|
|
|
|
if minetest.registered_items[house_node.name] then
|
|
local ptype = minetest.registered_items[house_node.name].paramtype2
|
|
if ptype == 'wallmounted' or ptype == 'colorwallmounted' then
|
|
local dir = (param2 or 0) % 8
|
|
local extra = (param2 or 0) - dir
|
|
for i = 1, rot do
|
|
dir = drotwp[dir]
|
|
end
|
|
param2 = dir + extra
|
|
elseif ptype == 'facedir' then
|
|
local dir = (param2 or 0) % 24
|
|
local extra = (param2 or 0) - dir
|
|
for i = 1, rot do
|
|
dir = drotp[dir]
|
|
end
|
|
param2 = dir + extra
|
|
end
|
|
|
|
local name = house_node.name
|
|
local meta = house_node.meta
|
|
if name == 'default:dirt_with_grass' then
|
|
local index_2d = get_index(x + px * plot_size - 2, z + pz * plot_size - 2)
|
|
if index_2d then
|
|
local biome = biomemap[index_2d]
|
|
name = biome.node_top or 'default:dirt'
|
|
end
|
|
end
|
|
|
|
write(x + off.x + px * plot_size - 2, y - 1, z + off.z + pz * plot_size - 2, node[name], param2, meta)
|
|
else
|
|
--print('Squaresville: unknown node: '..house_node.name)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-- This is probably a bad idea...
|
|
local function simple_tree(data, px, pz)
|
|
local r
|
|
local h = math_random(4,6)
|
|
for y = 1,h do
|
|
data[px][y][pz] = squaresville.node('default:tree')
|
|
end
|
|
for z = -2,2 do
|
|
for y = -2,2 do
|
|
for x = -2,2 do
|
|
r = math.sqrt(x ^ 2 + y ^ 2 + z ^ 2)
|
|
if data[x + px][y + h][z + pz] ~= squaresville.node('default:tree') and math_random(4,6) > r * 2 then
|
|
data[x + px][y + h][z + pz] = squaresville.node('default:leaves')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-------------------------------------
|
|
-- Fix this
|
|
-------------------------------------
|
|
local function park(data, param, dx, dy, dz)
|
|
local sr
|
|
|
|
for z = 1,dz do
|
|
for x = 1,dx do
|
|
data[x][0][z] = squaresville.node('default:dirt_with_grass')
|
|
if squaresville.desolation > 0 then
|
|
sr = math_random(14)
|
|
if sr < 6 then
|
|
data[x][1][z] = squaresville.node('default:grass_'..sr)
|
|
elseif sr == 6 then
|
|
data[x][1][z] = squaresville.node('default:dry_shrub')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for qz = 1,math_floor(dz / 5) do
|
|
for qx = 1,math_floor(dx / 5) do
|
|
sr = math_random(5)
|
|
if sr == 1 then
|
|
simple_tree(data, qx * 5 - 2, qz * 5 - 2)
|
|
elseif sr == 2 then
|
|
data[qx * 5 - 2][1][qz * 5 - 2] = squaresville.node('squaresville:park_bench')
|
|
pstore(param, qx * 5 - 2, 1, qz * 5 - 2, math_random(4) - 1)
|
|
elseif sr == 3 then
|
|
data[qx * 5 - 2][1][qz * 5 - 2] = squaresville.node('squaresville:swing_set')
|
|
pstore(param, qx * 5 - 2, 1, qz * 5 - 2, math_random(4) - 1)
|
|
else
|
|
sr = math_random(30)
|
|
if sr == 1 then
|
|
data[qx * 5 - 2][1][qz * 5 - 2] = squaresville.node('squaresville:doll')
|
|
pstore(param, qx * 5 - 2, 1, qz * 5 - 2, math_random(4) - 1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function squaresville.build(mg)
|
|
local minp, maxp = mg.minp, mg.maxp
|
|
local data, p2data, area = mg.data, mg.p2data, mg.area
|
|
local heightmap, biomemap = mg.heightmap, mg.biomemap
|
|
local schem, meta_data, vm = mg.schem, mg.meta_data, mg.vm
|
|
local baseline = mg.baseline
|
|
|
|
local suburb_orient = 0
|
|
local danger = 0
|
|
local size = squaresville.block_size - squaresville.road_size + 2
|
|
|
|
if not squaresville.csize then
|
|
squaresville.csize = vector.add(vector.subtract(maxp, minp), 1)
|
|
end
|
|
|
|
for bz = minp.z - 2 * squaresville.block_size + 1, maxp.z + squaresville.block_size - 1 do
|
|
for bx = minp.x - 2 * squaresville.block_size + 1, maxp.x + squaresville.block_size - 1 do
|
|
for non_loop = 1, 1 do
|
|
if ((bx + squaresville.max_height + squaresville.half_road_size) % squaresville.block_plus_road_size ~= squaresville.road_size + 2) or ((bz + squaresville.max_height + squaresville.half_road_size) % squaresville.block_plus_road_size ~= squaresville.road_size + 2) then
|
|
break
|
|
end
|
|
|
|
local civ = squaresville.get_altitude({x=bx, z=bz})
|
|
|
|
if not civ.civ then
|
|
break
|
|
end
|
|
|
|
-- Don't use bx, bz from this point.
|
|
local pos = {x=bx, y=baseline + civ_base, z=bz}
|
|
local seed = minetest.get_mapgen_setting('seed') % 65536
|
|
pr = PcgRandom(pos.z * 10000 + pos.x + seed)
|
|
squaresville.pr = pr
|
|
|
|
desolation = squaresville.get_desolation(baseline, civ.danger)
|
|
|
|
-- This function burns lots of CPU time in order to save the
|
|
-- memory that would be necessary when using buffers.
|
|
local write = function(rx, ry, rz, node_n, p2, meta)
|
|
local x = pos.x + rx
|
|
local y = pos.y + ry
|
|
local z = pos.z + rz
|
|
|
|
if x >= minp.x and x <= maxp.x and y >= minp.y and y <= maxp.y and z >= minp.z and z <= maxp.z and (desolation == 0 or y <= baseline + squaresville.noise['ruin'].map[((z - minp.z) * squaresville.csize.x + (x - minp.x) + 1)]) then
|
|
local ivm = area:index(x, y, z)
|
|
data[ivm] = breaker(node_n, y - baseline, civ.humidity_1, desolation)
|
|
p2data[ivm] = p2 or 0
|
|
|
|
if meta then
|
|
meta_data[#meta_data+1] = {x=x, y=y, z=z, meta=meta}
|
|
end
|
|
end
|
|
end
|
|
|
|
local read = function(rx, ry, rz)
|
|
local x = pos.x + rx
|
|
local y = pos.y + ry
|
|
local z = pos.z + rz
|
|
|
|
if x >= minp.x and x <= maxp.x and y >= minp.y and y <= maxp.y and z >= minp.z and z <= maxp.z then
|
|
local ivm = area:index(x, y, z)
|
|
return data[ivm]
|
|
end
|
|
end
|
|
|
|
local get_index = function(rx, rz)
|
|
local x = pos.x + rx
|
|
local z = pos.z + rz
|
|
|
|
if x >= minp.x and x <= maxp.x and z >= minp.z and z <= maxp.z then
|
|
return (z - minp.z) * squaresville.csize.x + (x - minp.x) + 1
|
|
end
|
|
end
|
|
|
|
local function clear(miny, maxy)
|
|
local i = 1
|
|
while i <= #schem do
|
|
if schem[i].pos.x >= pos.x and schem[i].pos.x <= pos.x + size and schem[i].pos.z >= pos.z and schem[i].pos.z <= pos.z + size then
|
|
table.remove(schem, i)
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
for z = pos.z - 0, pos.z + size + 0 do
|
|
for x = pos.x - 0, pos.x + size + 0 do
|
|
for y = miny, maxy do
|
|
write(x - pos.x, y, z - pos.z, node_air)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local river
|
|
for rz = pos.z, pos.z + size, 5 do
|
|
for rx = pos.x, pos.x + size, 5 do
|
|
local def = squaresville.get_altitude({x=rx, z=rz})
|
|
if def.height < civ_base - 2 then
|
|
river = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if river then
|
|
break
|
|
end
|
|
end
|
|
|
|
if river or (squaresville.vacancies > 0 and pr:next(1, squaresville.vacancies) == 1) then
|
|
local i = 1
|
|
while i <= #schem do
|
|
if schem[i].pos.x >= pos.x + 2 and schem[i].pos.x <= pos.x + size - 2 and schem[i].pos.z >= pos.z + 2 and schem[i].pos.z <= pos.z + size - 2 then
|
|
if math.random(squaresville.town_tree_thinning) ~= 1 then
|
|
table.remove(schem, i)
|
|
else
|
|
i = i + 1
|
|
end
|
|
elseif schem[i].pos.x >= pos.x and schem[i].pos.x <= pos.x + size and schem[i].pos.z >= pos.z and schem[i].pos.z <= pos.z + size then
|
|
table.remove(schem, i)
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
elseif civ.city then
|
|
local sr = pr:next(1, 13)
|
|
if sr <= 3 then
|
|
clear(1, 10)
|
|
gotham(write, read, size)
|
|
elseif sr <= 6 then
|
|
clear(1, 10)
|
|
glass_and_steel(write, read, size)
|
|
elseif sr <= 9 then
|
|
clear(1, 10)
|
|
simple(write, read, size)
|
|
elseif sr <= 12 then
|
|
clear(1, 10)
|
|
simple(write, read, size, true)
|
|
else
|
|
--park(write, dx, dy, dz)
|
|
end
|
|
elseif civ.suburb then
|
|
local sr = pr:next(1, 13)
|
|
if sr <= 13 then
|
|
clear(1, 10)
|
|
shacks(write, read, get_index, size, suburb_orient, civ.danger, biomemap)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|