-- 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