minetest-mod-squaresville/deco.lua

544 lines
15 KiB
Lua

-- Squaresville deco.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 dangerous = squaresville.dangerous_terrain
squaresville.decorations = {}
squaresville.decorations_schem = {}
local math_abs = math.abs
local math_floor = math.floor
for i = 2, 4 do
minetest.register_decoration({
deco_type = "schematic",
place_on = {"default:dirt_with_snow", "default:dirt_with_grass"},
sidelen = 16,
noise_params = {
offset = 0.012,
scale = 0.022,
spread = {x = 250, y = 250, z = 250},
seed = (84 - 7 * i),
octaves = 3,
persist = 0.66
},
biomes = {"taiga", "coniferous_forest", "floatland_coniferous_forest"},
y_min = 2,
y_max = 31000,
schematic = squaresville.path .. "/schematics/pine_tree"..i..".mts",
flags = "place_center_x, place_center_z",
})
minetest.register_decoration({
deco_type = "schematic",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
noise_params = {
offset = 0.012,
scale = 0.022,
spread = {x = 250, y = 250, z = 250},
seed = (139 - 7 * i),
octaves = 3,
persist = 0.66
},
biomes = {"deciduous_forest", 'desertstone_grassland'},
y_min = 1,
y_max = 31000,
schematic = squaresville.path .. "/schematics/apple_tree"..i..".mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
end
minetest.register_decoration({
deco_type = "schematic",
place_on = {"default:dirt_with_grass"},
sidelen = 16,
noise_params = {
offset = 0,
scale = 0.022,
spread = {x = 250, y = 250, z = 250},
seed = 119,
octaves = 3,
persist = 0.66
},
biomes = {"deciduous_forest"},
y_min = 1,
y_max = 31000,
schematic = squaresville.path .. "/schematics/cherry_tree.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
minetest.register_decoration({
deco_type = "schematic",
place_on = {"default:polluted_dirt"},
sidelen = 16,
noise_params = {
offset = 0.036,
scale = 0.022,
spread = {x = 250, y = 250, z = 250},
seed = 666,
octaves = 3,
persist = 0.66
},
biomes = {"toxic_forest"},
y_min = 1,
y_max = 31000,
schematic = squaresville.path .. "/schematics/decaying_tree.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
})
do
for _, odeco in pairs(minetest.registered_decorations) do
local deco = table.copy(odeco)
deco.place_on = table.copy(odeco.place_on)
deco.flags = {}
if odeco.biomes then
deco.biomes = {}
for _, b in pairs(odeco.biomes) do
deco.biomes[b] = true
end
end
if odeco.flags then
for f in odeco.flags:gmatch('[%w_]+') do
deco.flags[f] = true
end
end
local nod = minetest.registered_nodes[deco.decoration]
if nod and nod.groups and nod.groups.flower then
deco.flower = true
end
if odeco.schematic then
deco.name = odeco.schematic:match('([%w_]+)%.mts') or odeco.schematic
elseif odeco.decoration and type(odeco.decoration) == 'string' then
deco.name = odeco.decoration:match('.*:([%w_]+)') or odeco.decoration
end
if deco.name == 'apple_tree' or deco.name == 'pine_tree' then
deco.noise_params.offset = 0.012
if deco.name == 'apple_tree' then
deco.biomes['desertstone_grassland'] = true
end
elseif deco.name == 'junglegrass' then
deco.biomes['desertstone_grassland'] = true
deco.place_on[#deco.place_on+1] = 'default:dirt_with_grass'
elseif deco.name == 'jungle_tree' then
deco.schematic = squaresville.path..'/schematics/jungle_tree_with_orchids.mts'
end
squaresville.decorations[#squaresville.decorations+1] = deco
end
end
squaresville.biomes = {}
local biomes = squaresville.biomes
local biome_names = {}
do
local biome_mod = {
tundra = { node_top = 'default:snowblock', depth_top = 1 },
rainforest = { civ = 'desertstone_grassland' },
}
for i, obiome in pairs(minetest.registered_biomes) do
local biome = table.copy(obiome)
biomes[biome.name] = biome
biome_names[#biome_names+1] = biome.name
-- Make changes to biome values from biome_mod.
for n, bi in pairs(biome_mod) do
for i, rbi in pairs(biomes) do
if rbi.name == n then
for j, prop in pairs(bi) do
biomes[i][j] = prop
end
end
end
end
end
biomes["desertstone_grassland"] = {
name = "desertstone_grassland",
--node_dust = "",
node_top = "default:dirt_with_grass",
depth_top = 1,
node_filler = "default:dirt",
depth_filler = 1,
node_stone = "default:desert_stone",
node_riverbed = "default:sand",
depth_riverbed = 2,
--node_water_top = "",
--depth_water_top = ,
--node_water = "",
--node_river_water = "",
y_min = squaresville.max_height,
y_max = squaresville.max_height,
heat_point = 86,
humidity_point = 50,
}
if dangerous then
biomes["toxic_forest"] = {
name = "toxic_forest",
node_top = "squaresville:polluted_dirt",
danger = 3,
depth_top = 1,
node_filler = "squaresville:polluted_dirt",
depth_filler = 1,
node_riverbed = "squaresville:polluted_dirt",
depth_riverbed = 1,
node_water = "squaresville:water_poison_source",
node_river_water = "squaresville:water_poison_source",
special_trees = {"decaying_tree"},
y_min = 1,
y_max = squaresville.max_height,
heat_point = 20,
humidity_point = 50,
}
biomes["toxic_forest_ocean"] = {
name = "toxic_forest_ocean",
node_top = "squaresville:polluted_dirt",
danger = 3,
depth_top = 1,
node_filler = "squaresville:polluted_dirt",
depth_filler = 1,
node_riverbed = "squaresville:polluted_dirt",
depth_riverbed = 1,
node_water = "squaresville:water_poison_source",
node_river_water = "squaresville:water_poison_source",
y_min = -10,
y_max = 0,
heat_point = 20,
humidity_point = 50,
}
biomes["draconic"] = {
name = "draconic",
--node_dust = "",
node_top = "squaresville:cracked_stone",
depth_top = 1,
node_filler = "squaresville:granite",
depth_filler = 1,
node_stone = "squaresville:granite",
--node_water_top = "",
--depth_water_top = ,
--node_water = "",
node_river_water = "squaresville:basalt",
node_riverbed = "squaresville:basalt",
depth_riverbed = 2,
danger = 3,
y_min = 1,
y_max = squaresville.max_height,
heat_point = 80,
humidity_point = 20,
}
biomes["draconic_ocean"] = {
name = "draconic_ocean",
--node_dust = "",
node_top = "squaresville:granite",
depth_top = 1,
danger = 3,
node_filler = "squaresville:granite",
depth_filler = 3,
node_stone = "squaresville:granite",
y_min = -20,
y_max = 0,
heat_point = 80,
humidity_point = 20,
}
biomes["bizarre"] = {
name = "bizarre",
--node_dust = "",
node_top = "squaresville:dirt_with_odd_grass",
depth_top = 1,
node_filler = "default:dirt",
depth_filler = 1,
node_stone = "squaresville:basalt",
--node_water_top = "",
--depth_water_top = ,
--node_water = "",
--node_river_water = "squaresville:basalt",
--node_riverbed = "squaresville:basalt",
--depth_riverbed = 2,
special_trees = {'fur_tree'},
danger = 3,
y_min = 1,
y_max = squaresville.max_height,
heat_point = 60,
humidity_point = 70,
}
biomes["bizarre_ocean"] = {
name = "bizarre_ocean",
--node_dust = "",
node_top = "default:sand",
depth_top = 1,
danger = 3,
node_filler = "default:sand",
depth_filler = 3,
node_stone = "squaresville:basalt",
y_min = -20,
y_max = 0,
heat_point = 60,
humidity_point = 70,
}
end
end
local function register_flower(name, desc, biomes, seed)
local groups = {}
groups.snappy = 3
groups.flammable = 2
groups.flower = 1
groups.flora = 1
groups.attached_node = 1
minetest.register_node("squaresville:" .. name, {
description = desc,
drawtype = "plantlike",
waving = 1,
tiles = {"squaresville_" .. name .. ".png"},
inventory_image = "squaresville_" .. name .. ".png",
wield_image = "squaresville_" .. name .. ".png",
sunlight_propagates = true,
paramtype = "light",
walkable = false,
buildable_to = true,
stack_max = 99,
groups = groups,
sounds = default.node_sound_leaves_defaults(),
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -5/16, 0.5},
}
})
local bi = {}
if biomes then
bi = {}
for _, b in pairs(biomes) do
bi[b] = true
end
end
local def = {
deco_type = "simple",
place_on = {"default:dirt_with_grass", 'default:dirt_with_rainforest_litter'},
sidelen = 16,
noise_params = {
offset = -0.015,
scale = 0.025,
spread = {x = 200, y = 200, z = 200},
seed = seed,
octaves = 3,
persist = 0.6
},
biomes = bi,
y_min = 1,
y_max = 31000,
decoration = "squaresville:"..name,
name = name,
flower = true,
}
squaresville.decorations[#squaresville.decorations+1] = def
if bi['rainforest'] then
def = table.copy(def)
def.noise_params = table.copy(def.noise_params)
def.noise_params.offset = 0.015
def.place_on = {'default:dirt_with_rainforest_litter'}
def.biomes = {['rainforest'] = true, ['rainforest_swamp'] = true}
squaresville.decorations[#squaresville.decorations+1] = def
end
end
register_flower("orchid", "Orchid", {"rainforest", "rainforest_swamp"}, 783)
register_flower("bird_of_paradise", "Bird of Paradise", {"rainforest", "desertstone_grassland"}, 798)
register_flower("gerbera", "Gerbera", {"savanna", "rainforest", "desertstone_grassland"}, 911)
local function register_decoration(deco, place_on, biomes, chance)
local bi = {}
if biomes then
bi = {}
for _, b in pairs(biomes) do
bi[b] = true
end
end
squaresville.decorations[#squaresville.decorations+1] = {
deco_type = "simple",
place_on = place_on,
sidelen = 16,
biomes = bi,
fill_ratio = chance,
y_min = 1,
y_max = 31000,
decoration = deco,
name = deco:match('[^:]+$'),
}
end
if dangerous then
--register_decoration('default:lava_source', 'squaresville:cracked_stone', {'draconic'}, 0.0005)
register_decoration('squaresville:blackened_shrub', 'squaresville:polluted_dirt', {'toxic_forest'}, 0.05)
register_decoration('flowers:mushroom_red', 'squaresville:polluted_dirt', {'toxic_forest'}, 0.05)
register_decoration('squaresville:strange_plant_1', 'squaresville:dirt_with_odd_grass', {'bizarre'}, 0.05)
register_decoration('squaresville:strange_plant_2', 'squaresville:dirt_with_odd_grass', {'bizarre'}, 0.05)
for i = 1, 4 do
register_decoration('squaresville:stone_spike_'..i, 'squaresville:cracked_stone', {'draconic'}, 0.02 / i)
end
end
local function place_deco(mg, ps, deco)
local data, a = mg.data, mg.area
local minp, maxp = mg.minp, mg.maxp
local heightmap, biomemap, schem = mg.heightmap, mg.biomemap, mg.schem
local csize = mg.csize
local sidelen = deco.sidelen or csize.x
local node = squaresville.node
local max_height = squaresville.max_height
local node_air = node['air']
local node_ignore = node['ignore']
local node_water = node['default:water_source']
if csize.x % sidelen ~= 0 then
sidelen = csize.x
end
local divlen = csize.x / sidelen
local area = sidelen * sidelen
for z0 = 0, divlen-1 do
for x0 = 0, divlen-1 do
local center = {
x=math_floor(minp.x + sidelen / 2 + sidelen * x0),
z=math_floor(minp.z + sidelen / 2 + sidelen * z0),
}
local min = {
x=minp.x + sidelen * x0,
z=minp.z + sidelen * z0,
}
local max = {
x=minp.x + sidelen + sidelen * x0 - 1,
z=minp.z + sidelen + sidelen * z0 - 1,
}
local nval = deco.noise_params and minetest.get_perlin(deco.noise_params):get2d({x=center.x, y=center.z}) or deco.fill_ratio
local deco_count = area * nval
if deco_count > 1 then
deco_count = math_floor(deco_count)
elseif deco_count > 0 then
if ps:next(1, 1000) <= deco_count * 1000 then
deco_count = 1
else
deco_count = 0
end
end
for i = 1, deco_count do
local x = ps:next(min.x, max.x)
local z = ps:next(min.z, max.z)
local mapindex = csize.x * (z - minp.z) + (x - minp.x) + 1
local y = -squaresville.max_height
if deco.liquid_surface then
print('Squaresville: Invalid liquid_surface parameter')
--y = find_liquid_surface()
elseif heightmap then
y = heightmap[mapindex]
else
print('Squaresville: Cannot generate heightmap')
--y = find_ground()
end
if y > -max_height and y < max_height and y >= minp.y and y <= maxp.y and y - mg.baseline >= (deco.y_min or -max_height) and y - mg.baseline <= (deco.y_max or max_height) then
local biome
if biomemap then
biome = biomemap[mapindex]
end
if not deco.biomes or deco.biomes[biome.name] then
local ivm = a:index(x, y, z)
if (not deco.place_on) or deco.place_on[data[ivm]] then
ivm = ivm + a.ystride
if deco.deco_type == 'schematic' then
local too_close
local size_s = deco.size_offset and ((deco.size_offset.x + 1) * (deco.size_offset.z + 1)) or 9
for _, s in ipairs(schem) do
local dx, dz = s.pos.x - x, s.pos.z - z
if dx * dx + dz * dz <= size_s then
too_close = true
break
end
end
if not too_close then
schem[#schem+1] = {def=deco, pos={x=x,y=y,z=z}}
end
elseif data[ivm] == node_air then
data[ivm] = node[deco.decoration]
end
end
end
end
end
end
end
end
local first_check = true
function squaresville.place_all_decorations(mg)
local ps = PcgRandom(mg.seed + 53)
for i, deco in pairs(squaresville.decorations) do
if first_check and deco.place_on then
local new_p = {}
if type(deco.place_on) ~= 'table' then
deco.place_on = {deco.place_on}
end
for i, d in ipairs(deco.place_on) do
if type(d) == 'string' then
new_p[squaresville.node[d]] = squaresville.node[d]
end
end
deco.place_on = new_p
end
place_deco(mg, ps, deco)
end
first_check = nil
end
-- This lets rarer spawns overwrite the more common.
table.sort(squaresville.decorations, function(a, b)
if a.fill_ratio and b.fill_ratio and a.fill_ratio < b.fill_ratio then
return true
elseif a.fill_ratio and not b.fill_ratio then
return true
elseif b.fill_ratio and not a.fill_ratio then
return false
elseif not (a.fill_ratio or b.fill_ratio) and a.noise_params and b.noise_params and a.noise_params.scale + a.noise_params.offset > b.noise_params.scale + b.noise_params.offset then
return true
else
return false
end
end)