minetest-mod-squaresville/buildings.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