write something there

This commit is contained in:
N-Nachtigal 2025-05-04 16:01:41 +02:00
commit b4b6c08f4f
8546 changed files with 309825 additions and 0 deletions

View file

@ -0,0 +1,9 @@
MIT License
Copyright © 2024 EmptyStar <https://github.com/EmptyStar>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,38 @@
minetest.set_mapgen_setting("mgv7_cave_width",0.0415,true)
minetest.set_mapgen_setting("mgv7_cavern_limit",-48,true)
minetest.set_mapgen_setting("mgv7_cavern_taper",64,true)
minetest.set_mapgen_setting("mgv7_cavern_threshold",0.5,true)
minetest.set_mapgen_setting("mgv7_large_cave_depth",0,true)
minetest.set_mapgen_setting("mgv7_large_cave_flooded",0,true)
minetest.set_mapgen_setting("mgv7_large_cave_num_min",0,true)
minetest.set_mapgen_setting("mgv7_large_cave_num_max",0,true)
minetest.set_mapgen_setting("mgv7_small_cave_num_min",0,true)
minetest.set_mapgen_setting("mgv7_small_cave_num_max",0,true)
minetest.set_mapgen_setting_noiseparams("mgv7_np_cave1",{
offset = 0.96,
scale = 11.45,
seed = 3141592653,
spread = {
x = 62,
y = 32.75,
z = 62,
},
octaves = 4,
persistence = 0.44,
lacunarity = 1.698,
},true)
minetest.set_mapgen_setting_noiseparams("mgv7_np_cave2",{
offset = 0,
scale = 11.25,
seed = 2718281828,
spread = {
x = 180,
y = 32.75,
z = 180,
},
octaves = 4,
persistence = 0.675,
lacunarity = 1.5,
},true)

View file

@ -0,0 +1,100 @@
--[[
Biome API noise settings
]]
-- Set heat noise params
minetest.set_mapgen_setting_noiseparams("mg_biome_np_heat",{
flags = "default",
lacunarity = 1,
persistence = 0.925,
seed = 5349,
spread = {
x = 2000,
y = 2000,
z = 2000,
},
scale = 42,
octaves = 2,
offset = 50,
},true)
-- Set humidity noise params
minetest.set_mapgen_setting_noiseparams("mg_biome_np_humidity",{
flags = "default",
lacunarity = 1,
persistence = 0.925,
seed = 842,
spread = {
x = 2000,
y = 2000,
z = 2000,
},
scale = 42,
octaves = 2,
offset = 50,
},true)
-- Set heat blend noise params
minetest.set_mapgen_setting_noiseparams("mg_biome_np_heat_blend",{
flags = "default",
lacunarity = 1.678,
persistence = 0.625,
seed = 13,
spread = {
x = 24,
y = 24,
z = 24,
},
scale = 0.525,
octaves = 2,
offset = 0,
},true)
-- Set humidity blend noise params
minetest.set_mapgen_setting_noiseparams("mg_biome_np_humidity_blend",{
flags = "default",
lacunarity = 1.678,
persistence = 0.625,
seed = 90003,
spread = {
x = 24,
y = 24,
z = 24,
},
scale = 0.525,
octaves = 2,
offset = 0,
},true)
--[[
Climate analysis command
]]
-- Register climate analysis privilege
minetest.register_privilege("climate",{
description = "Privilege required to use the /climate command",
give_to_singleplayer = false,
give_to_admin = true,
})
-- Register climate analysis command
minetest.register_chatcommand("climate",{
params = "",
description = "analyze climate at current position",
privs = { climate = true },
func = function(name)
local player = minetest.get_player_by_name(name)
if not minetest.check_player_privs("climate") then
return false, "You do not have the 'climate' privilege necessary to use this command."
end
local pos = player:get_pos()
local data = minetest.get_biome_data(pos)
if data then
return true, "(" .. math.floor(pos.x) .. "," .. math.floor(pos.y) .. "," .. math.floor(pos.z) .. "): biome = " .. minetest.get_biome_name(data.biome) .. ", heat = " .. data.heat .. ", humidity = " .. data.humidity
else
return false, "No biome data for your current position!"
end
end
})

View file

@ -0,0 +1,816 @@
asuna.decor = {}
--[[
Flowers
]]
-- Group flowers by color
local flower_colors = {
black = {
"flowers:tulip_black",
},
white = {
"beautiflowers:carla",
"beautiflowers:cloe",
"beautiflowers:genesis",
"beautiflowers:gloria",
"beautiflowers:hadassa",
"beautiflowers:ingrid",
"beautiflowers:irene",
"beautiflowers:iris",
"beautiflowers:ivette",
"beautiflowers:michelle",
"beautiflowers:suri",
"flowers:dandelion_white",
"herbs:achillea_white",
"herbs:leontopodium_white",
"herbs:leucanthemum_white",
"herbs:trifolium_white",
},
blue = {
"beautiflowers:beatriz",
"beautiflowers:berta",
"flowers:geranium",
"herbs:centaurea",
"herbs:campanula_blue",
"herbs:digitalis_blue",
"herbs:iris",
"bakedclay:delphinium",
},
cyan = {
"beautiflowers:thais",
"beautiflowers:valentina",
"beautiflowers:valeria",
"beautiflowers:vera",
"beautiflowers:victoria",
"beautiflowers:virginia",
"beautiflowers:xenia",
"beautiflowers:zaida",
},
orange = {
"beautiflowers:dafne",
"beautiflowers:dana",
"beautiflowers:delia",
"beautiflowers:elena",
"beautiflowers:erica",
"beautiflowers:estela",
"beautiflowers:eva",
"beautiflowers:fabiola",
"beautiflowers:fiona",
"beautiflowers:gala",
"flowers:tulip",
},
yellow = {
"beautiflowers:ada",
"beautiflowers:agnes",
"beautiflowers:alicia",
"beautiflowers:alma",
"beautiflowers:amaia",
"beautiflowers:anastasia",
"beautiflowers:any",
"flowers:dandelion_yellow",
"farming:sunflower_8",
"herbs:digitalis_yellow",
"herbs:plantago",
},
purple = {
"beautiflowers:arleth",
"beautiflowers:astrid",
"beautiflowers:belen",
"beautiflowers:blanca",
"beautiflowers:casandra",
"beautiflowers:clara",
"beautiflowers:claudia",
"beautiflowers:minerva",
"beautiflowers:miriam",
"beautiflowers:nazareth",
"beautiflowers:noemi",
"beautiflowers:olga",
"beautiflowers:paula",
"beautiflowers:regina",
"beautiflowers:rocio",
"beautiflowers:sabrina",
"beautiflowers:vanesa",
"flowers:viola",
"beautiflowers:xena",
},
red = {
"beautiflowers:arcoiris",
"beautiflowers:jennifer",
"beautiflowers:lara",
"beautiflowers:laura",
"beautiflowers:lidia",
"beautiflowers:lucia",
"beautiflowers:mara",
"beautiflowers:martina",
"beautiflowers:melania",
"beautiflowers:mireia",
"beautiflowers:nadia",
"beautiflowers:nerea",
"beautiflowers:noelia",
"flowers:rose",
"herbs:dosera",
"herbs:papaver_red",
},
pink = {
"beautiflowers:caroline",
"beautiflowers:cristina",
"beautiflowers:diana",
"beautiflowers:gisela",
"beautiflowers:olimpia",
"beautiflowers:oriana",
"beautiflowers:pia",
"beautiflowers:raquel",
"beautiflowers:ruth",
"beautiflowers:sandra",
"beautiflowers:sara",
"beautiflowers:silvia",
"beautiflowers:sofia",
"beautiflowers:sonia",
"beautiflowers:talia",
"herbs:antirrhinum",
"herbs:trifolium_red",
"bakedclay:thistle",
"bakedclay:lazarus",
"ethereal:lilac",
},
green = {
"flowers:chrysanthemum_green",
"beautiflowers:pasto_1",
"beautiflowers:pasto_2",
"beautiflowers:pasto_3",
"beautiflowers:pasto_4",
"beautiflowers:pasto_5",
"beautiflowers:pasto_6",
"beautiflowers:pasto_7",
"beautiflowers:pasto_8",
"beautiflowers:pasto_9",
"beautiflowers:pasto_10",
"bakedclay:mannagrass",
},
red_mushroom = {
"flowers:mushroom_red",
},
brown_mushroom = {
"flowers:mushroom_brown",
"herbs:mushroom_boletus",
"herbs:mushroom_cantharellus",
"herbs:mushroom_macrolepiota",
},
odd_mushroom = {
"herbs:mushroom_amanita_green",
"herbs:mushroom_gyromitra",
"herbs:mushroom_galerina",
}
}
-- Register flower decorations per biome
local function cf(biome)
local decor = {
flowers = {},
mushrooms = {},
}
-- Generate list of flowers
for _,flower in ipairs(biome.flowers or {}) do
for _,flower in ipairs(flower_colors[flower]) do
table.insert(decor.flowers,flower)
end
end
-- Generate list of mushrooms
for _,mushroom in ipairs(biome.mushrooms or {}) do
for _,mushroom in ipairs(flower_colors[mushroom .. "_mushroom"]) do
table.insert(decor.mushrooms,mushroom)
end
end
return decor
end
-- Do actual decoration registration after other mods are finished
minetest.register_on_mods_loaded(function()
-- Register shore grass
local sandy_biomes = {}
local desert_biomes = {
desert = true,
sandstone_desert = true,
desert_shore = true,
sandstone_desert_shore = true,
desert_below = true,
sandstone_desert_below = true,
}
for biome,def in pairs(asuna.biomes) do
if def.shore == "default:sand" and
(def.ocean == "temperate" or def.ocean == "tropical" or def.ocean == "cold") and
not desert_biomes[biome]
then
table.insert(sandy_biomes,biome)
end
end
minetest.register_decoration(asuna.biome_groups.shore.inject_decoration({
deco_type = "simple",
place_on = "default:sand",
decoration = {"default:marram_grass_1","default:marram_grass_2","default:marram_grass_3"},
y_min = 2,
y_max = 2,
sidelen = 16,
noise_params = {
offset = 0.004,
scale = 0.0195,
spread = {x = 11, y = 11, z = 11},
seed = 69420,
octaves = 1,
},
biomes = sandy_biomes,
}))
minetest.register_decoration(asuna.biome_groups.shore.inject_decoration({
deco_type = "simple",
place_on = "default:sand",
decoration = {"default:marram_grass_1","default:marram_grass_2","default:marram_grass_3"},
y_min = 3,
y_max = 4,
sidelen = 16,
noise_params = {
offset = 0.075,
scale = 0.175,
spread = {x = 10, y = 10, z = 10},
seed = 42069,
octaves = 1,
},
biomes = sandy_biomes,
}))
-- Register flowers and mushrooms
for name,biome in pairs(asuna.biomes) do
-- Get node groups for biome
local decor = cf(biome)
-- Register flowers
if #biome.flowers > 0 then
minetest.register_decoration({
name = "asuna_core:flowers_" .. name,
deco_type = "simple",
sidelen = 80,
place_on = biome.nodes.extra and {biome.nodes[1],unpack(biome.nodes.extra)} or biome.nodes[1],
noise_params = {
offset = 0.006786,
scale = 0.004175,
spread = {x = 8, y = 8, z = 8},
seed = 1999,
octaves = 2,
persist = 0.44,
lacunarity = 0.75,
},
biomes = {name},
y_max = 31000,
y_min = 1,
decoration = decor.flowers,
})
end
-- Register mushrooms
if #biome.mushrooms > 0 then
minetest.register_decoration({
name = "asuna_core:mushrooms_" .. name,
deco_type = "simple",
sidelen = 8,
place_on = biome.nodes.extra and {biome.nodes[1],unpack(biome.nodes.extra)} or biome.nodes[1],
noise_params = {
offset = -0.0069,
scale = 0.027525,
spread = {x = 8, y = 8, z = 8},
seed = 60659,
octaves = 2,
persist = 0.7625,
lacunarity = 0.6,
},
biomes = {name},
y_max = 31000,
y_min = 1,
decoration = decor.mushrooms,
})
end
end
-- Special sunflower decor for the Plains biome
minetest.register_decoration({
name = "asuna_core:plains_special_sunflower",
deco_type = "simple",
place_on = {"default:dry_dirt_with_dry_grass"},
sidelen = 80,
fill_ratio = 0.075,
biomes = {"plains"},
y_max = 31000,
y_min = 1,
decoration = "farming:sunflower_8",
})
-- Special dense flower decor for the Prairie biome
minetest.register_decoration({
name = "asuna_core:prairie_special_flowers",
deco_type = "simple",
place_on = "prairie:prairie_dirt_with_grass",
sidelen = 80,
fill_ratio = 0.265,
biomes = {"prairie"},
y_max = 31000,
y_min = 1,
decoration = cf({ flowers = {"blue","cyan","white","orange","yellow"} }).flowers,
})
-- Special mushroom decor for the Mushroom biome
minetest.register_decoration({
name = "asuna_core:mushroom_special_mushrooms",
deco_type = "simple",
place_on = "ethereal:mushroom_dirt",
sidelen = 80,
fill_ratio = 0.075,
biomes = {"mushroom"},
y_max = 31000,
y_min = 1,
decoration = cf({ mushrooms = {"odd","brown"} }).mushrooms,
})
-- Bushes for certain grassy biomes
minetest.register_decoration({
name = "bushes:default_replacement",
deco_type = "schematic",
place_on = "default:dirt_with_grass",
sidelen = 80,
fill_ratio = 0.00025,
y_min = 2,
y_max = 31000,
biomes = {
"grassland",
"deciduous_forest",
"grassytwo",
"jumble",
"marsh",
},
schematic = minetest.get_modpath("default") .. "/schematics/bush.mts",
flags = "place_center_x,place_center_z",
})
--[[
Butterflies
]]
if minetest.get_modpath("butterflies") then
minetest.register_decoration({
name = "butterflies:butterfly",
deco_type = "simple",
place_on = "group:soil",
place_offset_y = 1,
sidelen = 80,
fill_ratio = 0.005,
biomes = {
"grassland",
"deciduous_forest",
"grassytwo",
"prairie",
"dorwinion",
"jumble",
"bamboo",
"naturalbiomes:heath",
"naturalbiomes:alpine",
"everness:bamboo_forest",
},
y_max = 31000,
y_min = 1,
decoration = {
"butterflies:butterfly_white",
"butterflies:butterfly_red",
"butterflies:butterfly_violet",
},
spawn_by = "group:flower",
num_spawn_by = 1,
})
end
--[[
Fireflies
]]
if minetest.get_modpath("fireflies") then
minetest.register_decoration({
name = "fireflies:firefly_low",
deco_type = "simple",
place_on = "group:soil",
place_offset_y = 2,
sidelen = 16,
noise_params = {
offset = -0.005,
scale = 0.015,
spread = {x = 60, y = 20, z = 60},
seed = 2112,
octaves = 1,
persistence = 0.75,
flags = "eased"
},
biomes = {
"deciduous_forest",
"grassland",
"grassytwo",
"prairie",
"dorwinion",
"jumble",
"swamp",
"marsh",
"naturalbiomes:alderswamp",
"naturalbiomes:alpine",
"naturalbiomes:bushland",
"everness:bamboo_forest",
},
y_max = 31000,
y_min = -1,
place_offset_y = 2,
decoration = "fireflies:hidden_firefly",
})
minetest.register_decoration({
name = "fireflies:firefly_low_bamboo_cave",
deco_type = "simple",
place_on = "everness:moss_block",
place_offset_y = 2,
sidelen = 16,
fill_ratio = 0.0065,
biomes = asuna.features.cave.bamboo,
y_max = 0,
y_min = -31000,
place_offset_y = 1,
decoration = "fireflies:hidden_firefly",
})
minetest.register_decoration({
name = "fireflies:firefly_low_dorwinion_cave",
deco_type = "simple",
place_on = "dorwinion:dorwinion_grass",
place_offset_y = 2,
sidelen = 16,
fill_ratio = 0.0065,
biomes = asuna.features.cave.dorwinion,
y_max = 0,
y_min = -31000,
place_offset_y = 1,
decoration = "fireflies:hidden_firefly",
})
end
--[[
Large jungle trees
]]
local chunksize = tonumber(minetest.get_mapgen_setting("chunksize"))
if chunksize >= 5 then
minetest.register_decoration({
name = "default:emergent_jungle_tree",
deco_type = "schematic",
place_on = {
"default:dirt_with_rainforest_litter",
},
sidelen = 80,
noise_params = {
offset = 0.0,
scale = 0.0025,
spread = {x = 200, y = 200, z = 200},
seed = 2685,
octaves = 3,
persist = 0.7
},
biomes = {"rainforest"},
y_max = 30000,
y_min = 1,
schematic = minetest.get_modpath("default") .. "/schematics/emergent_jungle_tree.mts",
flags = "place_center_x, place_center_z",
rotation = "random",
place_offset_y = -4,
})
end
--[[
Hanging vines
]]
local soil_nodes = {}
for _,soil_node in ipairs({
"default:dirt",
"default:dirt_with_grass",
"default:dirt_with_rainforest_litter",
"livingjungle:jungleground",
"livingjungle:leafyjungleground",
"naturalbiomes:alderswamp_litter",
"naturalbiomes:alderswamp_dirt",
"default:tree",
"default:jungletree",
"default:jungleleaves",
}) do
soil_nodes[minetest.get_content_id(soil_node)] = true
end
local cids = {
air = minetest.get_content_id("air"),
vine = minetest.get_content_id("ethereal:vine"),
water = minetest.get_content_id("default:water_source"), -- used for waterfalls below; unrelated to vines
water_flowing = minetest.get_content_id("default:water_flowing"), -- used for cave liquids below; unrelated to vines
lava = minetest.get_content_id("default:lava_source"), -- used for cave liquids below; unrelated to vines
lava_flowing = minetest.get_content_id("default:lava_flowing"), -- used for cave liquids below; unrelated to vines
stone = minetest.get_content_id("default:stone"),
jungleleaves = minetest.get_content_id("default:jungleleaves"),
}
local asuna_hanging_vines_fn = function(mapgen)
-- Get provided values
local pos = mapgen.pos
local va = mapgen.voxelarea
local vdata = mapgen.data
local vparam2 = mapgen.param2
-- Get stride values and set position
local ystride = va.ystride
local zstride = va.zstride
pos = va:index(pos.x,pos.y,pos.z)
-- Scan for dirt or surface nodes for a short distance above the position
for above = 1, 2 do
above = pos + above * ystride
if soil_nodes[vdata[above]] then
pos = above
break
end
end
-- List of cardinal directions relative to the current position
local cardinal = {
pos - 1,
pos + 1,
pos - zstride,
pos + zstride,
}
-- Iterate over cardinal positions and place vines at and below those positions
for i = 1, 4 do
local dir = cardinal[i]
if vdata[dir] == cids.air then
for below = 0, ((dir ^ 2 + (dir + pos) % 3) % 4 + 2) do
below = dir - below * ystride
if vdata[below] == cids.air then
vdata[below] = cids.vine
vparam2[below] = i + 1
else
break
end
end
end
end
end
abdecor.register_advanced_decoration("asuna_hanging_vines_jungletree",{
target = {
place_on = {
"default:jungletree",
},
sidelen = 80,
fill_ratio = 0.3,
biomes = {
"rainforest",
},
y_max = 31000,
y_min = 1,
flags = "all_ceilings",
},
fn = function(mapgen)
-- Get provided values
local pos = mapgen.pos
local va = mapgen.voxelarea
local vdata = mapgen.data
local vparam2 = mapgen.param2
-- Get stride values and set position
local ystride = va.ystride
local zstride = va.zstride
pos = va:index(pos.x,pos.y,pos.z)
-- Check surrounding nodes for jungle leaves
for x = -1, 1 do
for z = -zstride, zstride, zstride do
local lpos = pos + x + z
if vdata[lpos] == cids.jungleleaves and (pos * x + z) % 3 > 0 then
mapgen.pos = va:position(lpos)
asuna_hanging_vines_fn(mapgen)
end
end
end
end,
flags = {
param2 = true,
}
})
abdecor.register_advanced_decoration("asuna_hanging_vines",{
target = {
place_on = {
"group:stone",
"default:dirt",
"default:jungletree",
},
spawn_by = "air",
num_spawn_by = 5,
sidelen = 80,
fill_ratio = 0.3,
biomes = {
"swamp",
"naturalbiomes:alderswamp",
"marsh",
"rainforest",
"jumble",
"livingjungle:jungle",
},
y_max = 31000,
y_min = 1,
flags = "all_ceilings",
},
fn = asuna_hanging_vines_fn,
flags = {
param2 = true,
},
})
--[[
Ocean waterfalls
]]
local wall_stones = {
"default:stone_with_coal",
"default:stone_with_iron",
"default:stone_with_tin",
"default:stone_with_copper",
"default:stone_with_gold",
"default:stone_with_diamond",
"default:stone_with_mese",
}
for node,def in pairs(minetest.registered_nodes) do
if def.groups and def.groups.stone and def.groups.stone > 0 then
table.insert(wall_stones,node)
end
end
local valid_wall_stones = {}
for _,node in ipairs(wall_stones) do
valid_wall_stones[minetest.get_content_id(node)] = true
end
abdecor.register_advanced_decoration("asuna_waterfalls",{
target = {
place_on = "default:water_source",
spawn_by = wall_stones,
num_spawn_by = 3,
sidelen = 80,
fill_ratio = 0.11,
biomes = asuna.biome_groups.shore,
y_max = 1,
y_min = 1,
flags = "liquid_surface",
},
fn = function(mapgen)
-- Get provided values
local pos = mapgen.pos
local va = mapgen.voxelarea
local vdata = mapgen.data
-- Get stride values and adjust position
local ystride = va.ystride
local zstride = va.zstride
pos = va:index(pos.x,pos.y + 1,pos.z)
local too_low_pos = 0
-- Get stone wall direction
local cardinal = {
-1,
-zstride,
1,
zstride,
}
local found_stone = false
local check_wall = nil
for i = 1, 4 do
local wallpos = pos + cardinal[i]
local wallleft = cardinal[i % 4 + 1]
local wallright = cardinal[(i + 2) % 4 + 1]
check_wall = function(pos) -- is the entire row of wall nodes made of stone?
return valid_wall_stones[vdata[pos]] and valid_wall_stones[vdata[pos + wallleft]] and valid_wall_stones[vdata[pos + wallright]] and true or false
end
if check_wall(wallpos) then
pos = wallpos
too_low_pos = pos
found_stone = true
break
end
end
-- Do nothing if no stone wall found
if not found_stone then
return
end
-- Iterate above 'rows' of stone wall until we find something that isn't stone
repeat
pos = pos + ystride
until not check_wall(pos)
-- Set two below stone position to water if higher than one node
local placepos = pos - 2 * ystride
if placepos > too_low_pos then
vdata[placepos] = cids.water
end
end,
flags = {
liquid = true,
},
})
--[[
Cave ceiling liquids
]]
local enclosing_nodes = valid_wall_stones
abdecor.register_advanced_decoration("asuna_cave_liquids",{
target = {
place_on = {
"group:stone",
},
sidelen = 80,
spawn_by = {
"group:stone",
},
num_spawn_by = 8,
fill_ratio = 0.000015,
y_max = -30,
y_min = -31000,
flags = "all_ceilings",
},
fn = function(mapgen)
-- Get provided values
local va = mapgen.voxelarea
local vdata = mapgen.data
local vparam2 = mapgen.param2
local pos = mapgen.pos
-- Get stride values and set position
local ystride = va.ystride
local zstride = va.zstride
local pos = va:index(pos.x,pos.y,pos.z)
-- Liquid must be enclosed to its sides and above
for _,adjacent in ipairs({
ystride,
1,
-1,
zstride,
-zstride,
}) do
if not enclosing_nodes[vdata[pos + adjacent]] then
return -- liquid is not fully enclosed
end
end
-- Liquid must have sufficient clearance below
-- Scanning from bottom up should typically fail faster than top down
for below = pos - ystride * 8, pos - ystride, ystride do
if vdata[below] ~= minetest.CONTENT_AIR then
return -- not enough space between ceiling and ground
end
end
-- Fill the position and all air below with liquid based on climate + bias
-- Dry/hot climates are more likely to be lava, vice-versa with water
local liquid = (function()
local heatmap = minetest.get_mapgen_object("heatmap") or {}
local humiditymap = minetest.get_mapgen_object("humiditymap") or {}
local pos2d = mapgen.index2d(mapgen.pos)
local heat = heatmap[pos2d] or 50
local humidity = humiditymap[pos2d] or 50
local climate = 50 + (heat / 2 - 25) - (humidity / 2 - 25)
local pos_random = (pos ^ 2 + pos) % 38 * (pos % 2 == 0 and 1 or -1) + climate -- not actually random but good enough
return pos_random > 56 and {cids.lava,cids.lava_flowing} or {cids.water,cids.water_flowing} -- bias in favor of water
end)()
vdata[pos] = liquid[1]
pos = pos - ystride
while vdata[pos] == minetest.CONTENT_AIR do
vdata[pos] = liquid[2]
vparam2[pos] = 15
pos = pos - ystride
end
end,
flags = {
liquid = true,
param2 = true,
},
})
end)

View file

@ -0,0 +1,46 @@
asuna = {
modpath = core.get_modpath("asuna_core"),
content = {
nutrition = {
enabled = core.settings:get_bool("asuna.content.nutrition.enabled",true),
exhaustion_level = core.settings:get_bool("asuna.content.nutrition.enabled",true) and tonumber(core.settings:get("asuna.content.nutrition.exhaustion_level",160) or 160),
starvation = core.settings:get_bool("asuna.content.nutrition.enabled",true) and core.settings:get_bool("asuna.content.nutrition.starvation",false),
},
wayfarer = {
enabled = core.settings:get_bool("asuna.content.wayfarer.enabled",true),
awards = core.settings:get_bool("asuna.content.wayfarer.enabled",true) and core.settings:get_bool("asuna.content.wayfarer.awards",true),
loot_chests = core.settings:get_bool("asuna.content.wayfarer.enabled",true) and core.settings:get_bool("asuna.content.wayfarer.loot_chests",true),
worldgate = core.settings:get_bool("asuna.content.wayfarer.enabled",true) and core.settings:get_bool("asuna.content.wayfarer.worldgate",true),
},
menagerie = {
enabled = core.settings:get_bool("asuna.content.menagerie.enabled",true),
animals = core.settings:get_bool("asuna.content.menagerie.enabled",true) and core.settings:get_bool("asuna.content.menagerie.animals",true),
slimes = core.settings:get_bool("asuna.content.menagerie.enabled",true) and core.settings:get_bool("asuna.content.menagerie.slimes",true),
},
research = {
enabled = core.settings:get_bool("asuna.content.research.enabled",true),
},
},
settings = {
particles = {
amount = core.settings:get("asuna.settings.particles.amount","less") or "less",
},
mod_override_warnings = {
enabled = core.settings:get_bool("asuna.settings.mod_override_warnings.enabled",true),
},
},
}
local function runfile(file,condition)
if condition == nil or condition then
dofile(asuna.modpath .. "/" .. file .. ".lua")
end
end
runfile("biomes")
runfile("terrain")
runfile("climate")
runfile("caves")
runfile("decor")
runfile("music")
runfile("mod_override_warnings",asuna.settings.mod_override_warnings.enabled)

View file

@ -0,0 +1,6 @@
name = asuna_core
title = Asuna Core
description = The core mod that defines functionality specific to Asuna and its content
author = EmptyStar
depends = music_api
# ephemeral_depends = abdecor, default, flowers, beautiflowers, herbs, bakedclay, fireflies, ethereal, badland, dorwinion, prairie, naturalbiomes, livingjungle, bambooforest, frost_land, japaneseforest, nightshade, terracotta, too_many_stones

View file

@ -0,0 +1,46 @@
local asuna_mod_path = core.get_game_info().path .. "/mods"
local bundled_mods = core.get_dir_list(asuna_mod_path,true)
local warn
if asuna.settings.mod_override_warnings.enabled then
local messages = {}
warn = function(mod)
local message = "MOD OVERRIDE WARNING: Mod '" .. mod .. "' is enabled externally which overrides Asuna's version of this mod. This may cause issues."
core.log("warning",message)
table.insert(messages,core.colorize("#eeee00",message))
end
core.register_on_joinplayer(function(player)
local name = player:get_player_name()
local privs = core.get_player_privs(name)
if privs.server or privs.debug or name == "singleplayer" then
for _,message in ipairs(messages) do
core.chat_send_player(name,message)
end
end
end)
else
warn = function(mod)
core.log("warning","MOD OVERRIDE WARNING: Mod '" .. mod .. "' is enabled externally which overrides Asuna's version of this mod. This may cause issues.")
end
end
for _,mod in ipairs(bundled_mods) do
local mods = { mod }
local mpath = asuna_mod_path .. "/" .. mod
local mfiles = core.get_dir_list(mpath,false)
for _,mfile in ipairs(mfiles) do
if mfile:find("^modpack\\.") then
mods = core.get_dir_list(mpath,true)
break
end
end
for _,mpath in ipairs(mods) do
mod = mpath
mpath = core.get_modpath(mpath)
if mpath and not mpath:find("[\\/]games[\\/][^\\/]+[\\/]mods[\\/]") then
warn(mod)
end
end
end

View file

@ -0,0 +1,105 @@
--[[
Day or night
]]
music.register_track({
name = "reparateur",
length = 200 + 30,
gain = 1.25,
day = true,
night = true,
ymin = -12,
ymax = 31000,
})
music.register_track({
name = "blood",
length = 89 + 30,
gain = 1,
day = true,
night = true,
ymin = -12,
ymax = 31000,
})
--[[
Daytime only
]]
for track,length in pairs({
castlesinthesky = 107,
firefly = 152,
bathedinthelight = 166,
roquefortprolog = 85,
meditatingbeat = 132,
pond = 142,
onefineday = 51,
antarctica = 65,
simplicity = 122,
endtitles = 135,
imagefilm033 = 121,
}) do
music.register_track({
name = track,
length = length + 30,
gain = 1,
day = true,
night = false,
ymin = -12,
ymax = 31000,
})
end
--[[
Nighttime only
]]
for track,length in pairs({
jul = 204,
skyward = 149,
thelongwayhome = 171,
--moonlight = 176,
--walkingstars = 172,
hymn = 73,
reverie = 136,
atemubungen = 177,
breezyreflections = 91,
dreamsphere1 = 177,
dreamsphere2 = 109,
dreamsphere4 = 104,
lonelyfish = 107,
}) do
music.register_track({
name = track,
length = length + 30,
gain = 1,
day = false,
night = true,
ymin = -12,
ymax = 31000,
})
end
--[[
Underground
]]
for track,length in pairs({
machina = 192,
tearsinrain = 172,
screensaver = 113,
cobalt = 176,
infinitepeace = 73,
thevisitors = 160,
sunriseonmars = 129,
}) do
music.register_track({
name = track,
length = length + 30,
gain = 1,
day = true,
night = true,
ymin = -31000,
ymax = -12,
})
end

View file

@ -0,0 +1,39 @@
All of the music in this mod is listed/credited below by author, license, and source. Each track followed by an asterisk (`*`) has been edited from its original form, often to trim and fade the end of the track.
- **Scott Buckley** -- [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/), <https://www.scottbuckley.com.au/>
- Blood (blood.ogg)*
- Castles In The Sky (castlesinthesky.ogg)*
- Firefly (firefly.ogg)
- Jul (jul.ogg)*
- Machina (machina.ogg)*
- Reparateur (reparateur.ogg)*
- Skyward (skyward.ogg)*
- Tears In Rain (tearsinrain.ogg)*
- The Long Way Home (thelongwayhome.ogg)*
- Cobalt (cobalt.ogg)*
- Hymn (hymn.ogg)*
- Reverie (reverie.ogg)*
- Simplicity (simplicity.ogg)*
- **Kevin MacLeod** -- [CC-BY 3.0](https://creativecommons.org/licenses/by/3.0/), <https://incompetech.com/>
- Bathed in the Light (bathedinthelight.ogg)
- **Kevin MacLeod** -- [CC0](https://creativecommons.org/publicdomain/zero/1.0/), <https://www.freepd.com/>
- Screen Saver (screensaver.ogg)*
- Roquefort Prolog (roquefortprolog.ogg)*
- Infinite Peace (infinitepeace.ogg)*
- Meditating Beat (meditatingbeat.ogg)*
- **Rafael Krux** -- [CC0](https://creativecommons.org/publicdomain/zero/1.0/), <https://www.freepd.com/>
- Pond (pond.ogg)*
- **Jason Shaw** -- [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode), <https://audionautix.com/>
- Antarctica (antarctica.ogg)*
- One Fine Day (onefineday.ogg)*
- The Visitors (thevisitors.ogg)*
- Sunrise on Mars (sunriseonmars.ogg)*
- **Sascha Ende** -- [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode), <https://filmmusic.io/>
- Atemubüngen (atemubungen.ogg)*
- Breezy Reflections (breezyreflections.ogg)*
- Dreamsphere 1 (dreamsphere1.ogg)*
- Dreamsphere 2 (dreamsphere2.ogg)*
- Dreamsphere 4 (dreamsphere4.ogg)*
- End Titles (endtitles.ogg)*
- Image Film 033 (imagefilm033.ogg)*
- Lonely Fish (lonelyfish.ogg)*

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,715 @@
--[[
Boulders
- Should be registered before surface/terrain overrides
]]
local function boulder(name,seed,nodes)
minetest.register_decoration({
deco_type = "schematic",
place_on = nodes,
fill_ratio = 0.00000000000000001,
y_min = 2,
y_max = 31000,
flags = "force_placement,place_center_x,place_center_z",
schematic = asuna.modpath .. "/schematics/boulders/" .. name .. ".mts",
rotation = "random",
place_offset_y = 0
})
end
local seed = 90210
for _,name in ipairs({
"cobblestone_boulder_small",
"cobblestone_boulder_medium",
}) do
boulder(name,seed,{
"default:dirt_with_dry_grass",
"default:dry_dirt_with_dry_grass",
"default:dirt_with_snow",
"naturalbiomes:savannalitter",
})
seed = seed + 13
end
for _,name in ipairs({
"mossy_cobblestone_boulder_small",
"mossy_cobblestone_boulder_medium",
}) do
boulder(name,seed,{
"default:dirt_with_grass",
"default:dirt_with_coniferous_litter",
"ethereal:grove_dirt",
"naturalbiomes:alpine_litter",
"naturalbiomes:heath_litter",
"naturalbiomes:heath_litter2",
"naturalbiomes:heath_litter3",
})
seed = seed + 17
end
for _,name in ipairs({
"desert_boulder_small",
"desert_boulder_medium",
}) do
boulder(name,seed,{
"default:desert_sand",
"default:sandstone",
})
seed = seed + 19
end
--[[
Terrain changes
- Sweeping terrain changes that must be made before decorations are placed
]]
-- Special decoration handling
local mtrd = minetest.register_decoration
minetest.register_decoration = function(def)
-- Set all_floors for all surface decorations
local flags = def.flags or ""
if not (flags:find("all_") or flags:find("liquid_")) then
def.flags = #flags > 0 and (flags .. ",all_floors") or "all_floors"
end
-- Set negative y_min for select surface decorations
if def.y_min == 1 and def.y_max and def.y_max > 1 and def.deco_type == "simple" then
def.y_min = -20
end
-- Ensure spawning in water for underwater decorations
if def.y_max and def.y_max < 1 and not def.spawn_by and (def.place_on == "default:sand" or def.place_on[1] == "default:sand") then
def.spawn_by = "default:water_source"
def.num_spawn_by = 1
end
-- Return original register_decoration call
return mtrd(def)
end
-- Surface nodes that should be propagated through surface stone
local surface_spread = {
"default:dirt_with_grass",
"default:dry_dirt_with_dry_grass",
"default:dirt_with_dry_grass",
"default:dirt_with_rainforest_litter",
"default:dirt_with_coniferous_litter",
"naturalbiomes:savannalitter",
"naturalbiomes:alpine_litter",
"naturalbiomes:mediterran_litter",
"naturalbiomes:alderswamp_litter",
"naturalbiomes:outback_litter",
"ethereal:grove_dirt",
"ethereal:bamboo_dirt",
"livingjungle:jungleground",
"livingjungle:leafyjungleground",
"ethereal:mushroom_dirt",
"nightshade:nightshade_dirt_with_grass",
"japaneseforest:japanese_dirt_with_grass",
"bambooforest:dirt_with_bamboo",
"dorwinion:dorwinion_grass",
"badland:badland_grass",
"frost_land:frost_land_grass",
"prairie:prairie_dirt_with_grass",
"everness:dirt_with_crystal_grass",
"everness:dirt_with_cursed_grass",
"everness:dirt_with_coral_grass",
"ethereal:gray_dirt",
"naturalbiomes:heath_litter",
"naturalbiomes:bushland_bushlandlitter",
"naturalbiomes:bushland_bushlandlitter2",
"naturalbiomes:bushland_bushlandlitter3",
}
-- Replace some surface stone with grass; also causes some biome ingress into caves
for _,node in ipairs(surface_spread) do
minetest.register_decoration({
deco_type = "simple",
place_on = {
"group:stone",
"default:stone_with_coal",
"default:dirt",
"default:silver_sand",
"default:gravel",
"everness:coral_desert_stone_with_coal",
"everness:cursed_stone_carved_with_coal",
"everness:crystal_stone_with_coal",
},
spawn_by = node,
num_spawn_by = 1,
sidelen = 4,
y_min = 3,
y_max = 31000,
place_offset_y = -1,
fill_ratio = 10,
decoration = node,
flags = "force_placement",
})
end
-- Ocean floor nodes that should be replaced with proper ocean floor
local ocean_floor_replace = {
"group:stone",
"default:stone_with_coal",
"everness:quartz_ore",
"default:dirt",
"default:dry_dirt",
"default:gravel",
"default:silver_sand",
"default:dirt_with_grass",
"default:dry_dirt_with_dry_grass",
"default:dirt_with_dry_grass",
"default:dirt_with_rainforest_litter",
"default:dirt_with_coniferous_litter",
"naturalbiomes:savannalitter",
"naturalbiomes:alpine_litter",
"naturalbiomes:mediterran_litter",
"naturalbiomes:alderswamp_litter",
"naturalbiomes:outback_litter",
"ethereal:grove_dirt",
"ethereal:bamboo_dirt",
"livingjungle:jungleground",
"livingjungle:leafyjungleground",
"ethereal:mushroom_dirt",
"nightshade:nightshade_dirt_with_grass",
"japaneseforest:japanese_dirt_with_grass",
"bambooforest:dirt_with_bamboo",
"dorwinion:dorwinion_grass",
"badland:badland_grass",
"frost_land:frost_land_grass",
"prairie:prairie_dirt_with_grass",
"everness:dirt_with_crystal_grass",
"everness:dirt_with_cursed_grass",
"everness:coral_desert_stone_with_coal",
"everness:cursed_stone_carved_with_coal",
"everness:cursed_stone",
"everness:crystal_stone_with_coal",
}
-- Ocean floor generation function
local function register_ocean_floor(name)
-- Get above and shore biome names
local above = name:sub(1,-7) -- to trim "_below" from the end of the biome name
local shore = above .. "_shore"
-- Get biome
local biome = asuna.biomes[name]
-- Register shore ocean floor terrain
minetest.register_decoration({
deco_type = "schematic",
place_on = ocean_floor_replace,
sidelen = 80,
fill_ratio = 10, -- fill all
biomes = {name,shore,above},
y_max = 0,
y_min = 0,
decoration = "default:stone",
spawn_by = "default:water_source",
num_spawn_by = 1,
place_offset_y = -1,
flags = "all_floors,force_placement",
schematic = {
size = {
x = 1,
y = 2,
z = 1,
},
data = {
{ name = "default:stone" , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
},
},
})
-- Register ocean floor terrain
minetest.register_decoration({
deco_type = "schematic",
place_on = ocean_floor_replace,
sidelen = 80,
fill_ratio = 10, -- fill all
biomes = {name,shore,above},
y_max = -1,
y_min = -10,
decoration = "default:stone",
spawn_by = "default:water_source",
num_spawn_by = 1,
place_offset_y = -3,
flags = "all_floors,force_placement",
schematic = {
size = {
x = 1,
y = 4,
z = 1,
},
data = {
{ name = "default:stone" , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
},
},
})
-- Register deep ocean floor terrain
minetest.register_decoration({
deco_type = "schematic",
place_on = ocean_floor_replace,
sidelen = 80,
fill_ratio = 10, -- fill all
biomes = {name,shore,above},
y_max = -11,
y_min = -36,
decoration = "default:stone",
spawn_by = "default:water_source",
num_spawn_by = 1,
place_offset_y = -3,
flags = "all_floors,force_placement",
schematic = {
size = {
x = 1,
y = 4,
z = 1,
},
data = {
{ name = "default:stone" , param1 = 255 , param2 = 0 },
{ name = biome.deep_seabed , param1 = 255 , param2 = 0 },
{ name = biome.deep_seabed , param1 = 255 , param2 = 0 },
{ name = biome.deep_seabed , param1 = 255 , param2 = 0 },
},
},
})
-- Replace underwater surface nodes below sea level
minetest.register_decoration({
deco_type = "schematic",
place_on = surface_spread,
spawn_by = {
"default:sand",
"default:water_source",
},
num_spawn_by = 1,
sidelen = 4,
y_max = 0,
y_min = -10,
place_offset_y = -3,
fill_ratio = 10,
biomes = {name,shore,above},
schematic = {
size = {
x = 1,
y = 4,
z = 1,
},
data = {
{ name = "default:stone" , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
{ name = biome.seabed , param1 = 255 , param2 = 0 },
},
},
flags = "all_floors,force_placement",
})
end
-- Generate ocean floor terrain
local seed = 124
for _,biome in ipairs(asuna.biome_groups.below) do
register_ocean_floor(biome)
end
-- Maximum pool limits
local limits = {
MAX_SCAN_DISTANCE = 3,
MAX_DEPTH = 2,
MAX_AREA = 89,
}
-- Relevant content IDs
local cids = nil
minetest.register_on_mods_loaded(function() -- load after mapgen aliases are defined
cids = {
lava = minetest.get_content_id("mapgen_lava_source"),
water = minetest.get_content_id("mapgen_water_source"),
air = minetest.CONTENT_AIR,
ignore = minetest.CONTENT_IGNORE,
}
end)
-- Array of flammable nodes to be avoided when placing lava along with invalid
-- pool edge nodes
local is_flammable = {}
local is_invalid = {
[minetest.CONTENT_AIR] = true
}
minetest.register_on_mods_loaded(function()
for node,def in pairs(minetest.registered_nodes) do
if def.groups and def.groups.flammable and def.groups.flammable > 0 then
is_flammable[minetest.get_content_id(node)] = true
is_invalid[minetest.get_content_id(node)] = true
elseif def.floodable
or def.drawtype == "airlike"
or def.drawtype == "liquid"
or def.drawtype == "flowingliquid"
or def.buildable_to
or def.walkable == false
or (def.groups and def.groups.not_in_creative_inventory and def.groups.not_in_creative_inventory > 0)
or node:find("_marker") -- mapgen marker names used by some mods
then
is_invalid[minetest.get_content_id(node)] = true
end
end
end)
-- States that liquid pool nodes can be in
local nodestate = {
-- Invalid states
OUT_OF_BOUNDS = 128, -- outside of voxelarea or ignore nodes
INVALID = 64, -- nodes that cannot be part of a pool or pool borders
UNSATISFIABLE = 32, -- pool nodes that cannot be filled with liquid
MASK_INVALID = 128 + 64 + 32, -- combination of invalid states
-- Single nodes above the pool to be replaced with air
ERASE = 16, -- surface nodes that have been flagged for erasure of nodes above
MASK_ERASURE = 16 + 64, -- nodes that will be erased if the pool is generated
-- Directions
POSITIVE_Z = 8,
POSITIVE_X = 4,
NEGATIVE_Z = 2,
NEGATIVE_X = 1,
MASK_SATISFIED = 8 + 4 + 2 + 1, -- combination of all directions
-- Blank state
NONE = 0,
}
-- Monotonic map-like pool 'class' to track nodes and node states
local function Pool()
local nodemap = {}
local node_iterator = {} -- for fast, ordered, deterministic iteration
local size = 0
local scan_queue = {} -- for collecting non-terminated nodes to be scanned
return {
add = function(node,state)
nodemap[node] = state
table.insert(node_iterator,node)
size = size + 1
return state
end,
put = function(node,state)
nodemap[node] = state
return state
end,
get = function(node)
return nodemap[node]
end,
foreach = function(start,fn)
for i = start, size do
if not fn(node_iterator[i]) then
return false
end
end
return true
end,
size = function()
return size
end,
}
end
-- Register advanced decoration
abdecor.register_advanced_decoration("asuna_cave_pools",{
target = {
sidelen = 80,
fill_ratio = 0.0000925,
place_on = {
"group:stone",
"group:soil",
"default:clay",
"default:stone_with_coal_ore",
"default:stone_with_iron_ore",
"default:sand",
"default:silver_sand",
"default:desert_sand",
"default:gravel",
"default:coalblock",
"caverealms:coal_dust",
"everness:moss_block",
"everness:forsaken_desert_sand",
"everness:crystal_moss_block",
"everness:emerald_ice",
"everness:ancient_emerald_ice",
"everness:dense_emerald_ice",
"everness:frosted_ice",
"everness:frosted_ice_translucent",
"caverealms:stone_with_moss",
"caverealms:stone_with_lichen",
"caverealms:stone_with_algae",
"caverealms:stone_with_salt",
"caverealms:hot_cobble",
},
y_max = -36,
y_min = -31000,
flags = "all_floors",
},
fn = function(mapgen)
-- Get provided values
local va = mapgen.voxelarea
local vdata = mapgen.data
local pos = mapgen.pos
-- Get stride values and set position
local ystride = va.ystride
local zstride = va.zstride
local pos = va:index(pos.x,pos.y,pos.z)
-- Determine pool liquid based on climate
-- Dry/hot climates are more likely to be lava, vice-versa with water
local liquid = (function()
local heatmap = minetest.get_mapgen_object("heatmap") or {}
local humiditymap = minetest.get_mapgen_object("humiditymap") or {}
local pos2d = mapgen.index2d(mapgen.pos)
local heat = heatmap[pos2d] or 50
local humidity = humiditymap[pos2d] or 50
local climate = 50 + (heat / 2 - 25) - (humidity / 2 - 25)
local pos_random = PcgRandom(mapgen.seed):next(-29,29) + climate
return pos_random > 50 and cids.lava or cids.water
end)()
-- Create new pool for nodes
local pool = Pool()
-- VoxelManip offset lookup by direction
local adjacent = {
[nodestate.POSITIVE_X] = 1,
[nodestate.POSITIVE_Z] = zstride,
[nodestate.NEGATIVE_X] = -1,
[nodestate.NEGATIVE_Z] = -zstride,
}
-- Recursive scanning function
local function scan(node,direction,distance,depth)
-- Get the node's state if it exists, else initialize it based on depth
-- and pool size limit
local state = pool.get(node) or pool.add(node,(function()
if depth == 1 and pool.size() > limits.MAX_AREA then
if is_invalid[vdata[node]] then
return nodestate.INVALID
else
return nodestate.UNSATISFIABLE
end
else
return nodestate.NONE
end
end)())
-- Return if this node is already in an invalid state
if state > 31 then
return bit.band(state,nodestate.MASK_INVALID)
end
-- Return if this node is already satisfied in the given direction
if bit.band(state,direction) ~= 0 then
return direction
end
-- Check if this node is out of bounds
local content = vdata[node]
if content == nil or content == cids.ignore then
return nodestate.OUT_OF_BOUNDS
end
-- Check the validity of this node
if is_invalid[content] then
return pool.put(node,nodestate.INVALID)
end
-- Return unsatisfiable if the node below is invalid
if is_invalid[vdata[node - ystride]] then
return pool.put(node,nodestate.UNSATISFIABLE)
end
-- Return solution if this node is beyond the max scan distance
if distance > limits.MAX_SCAN_DISTANCE then
return direction
end
-- Checks based on depth
local above = node + ystride
if depth == 1 then
-- Flag nodes above for erasure if the node above is solid and the node
-- above that is air, but this node is unsatisfiable if both the node
-- above and the node above that are solid
if bit.band(state,nodestate.ERASE) == 0 and vdata[above] ~= cids.air then
local above2 = above + ystride
if vdata[above2] == cids.air then
pool.add(above,nodestate.MASK_ERASURE)
else
-- Do not generate lava pools around flammable nodes that won't be
-- erased
if liquid == cids.lava and (is_flammable[vdata[above]] or is_flammable[vdata[above2]]) then
return nodestate.OUT_OF_BOUNDS
else
return pool.put(node,nodestate.UNSATISFIABLE)
end
end
state = bit.bor(state,nodestate.ERASE) -- flag this node as already having been checked for erasure
end
else
-- At non-surface depths, the node above must have been fully satisfied
-- in a previous scan
if bit.band(pool.get(above) or nodestate.NONE,nodestate.MASK_SATISFIED) ~= nodestate.MASK_SATISFIED then
return pool.put(node,nodestate.INVALID)
end
end
-- Scan neighbor in the given direction
local neighbor = node + adjacent[direction]
local nstate = scan(neighbor,direction,distance + 1,depth)
-- Return the direction if the neighbor is satisfied in the given direction
if nstate == direction or nstate == nodestate.UNSATISFIABLE then
pool.put(node,bit.bor(state,direction))
return direction
end
-- If neighbor is out of bounds, then the entire pool is invalid
if nstate == nodestate.OUT_OF_BOUNDS then
return nodestate.OUT_OF_BOUNDS
end
-- If neighbor is invalid, then this node is unsatisfiable
if nstate == nodestate.INVALID then
return pool.put(node,nodestate.UNSATISFIABLE)
end
end
-- Initialize pool with the target position and perform the scan
for depth = 1, limits.MAX_DEPTH do
pool.add(pos - (depth - 1) * ystride,nodestate.NONE)
local scan_count = 4 -- each of four -/+ x/z directions
local i = 0
local scan_start = pool.size() -- optimization to skip nodes from prior scans
while i < scan_count do
local previous_size = pool.size()
local direction = bit.lshift(1,i % 4) -- cycle through directions
if not pool.foreach(scan_start,function(node)
return scan(node,direction,1,depth) ~= nodestate.OUT_OF_BOUNDS -- stop scanning immediately if out of bounds
end) then
return -- cannot render out of bounds pools
end
if pool.size() > previous_size then
scan_count = scan_count + 1 -- new nodes need additional scans
end
i = i + 1
end
end
-- Fill the pool and erase nodes above
pool.foreach(1,function(node)
local state = pool.get(node)
if bit.band(state,nodestate.MASK_SATISFIED) == nodestate.MASK_SATISFIED then
vdata[node] = liquid
elseif state == nodestate.MASK_ERASURE then
vdata[node] = cids.air
end
return true
end)
end,
})
--[[
Schematics
- Placed before other biome mods in order to mitigate interference from trees, etc.
]]
local mpath = minetest.get_modpath("asuna_core")
-- Haunted house
minetest.register_decoration({
name = "asuna_core:everness_haunted_house_badland",
deco_type = 'schematic',
place_on = "badland:badland_grass",
spawn_by = "badland:badland_grass",
num_spawn_by = 8,
sidelen = 80,
fill_ratio = 0.0000175,
biomes = "badland",
y_max = 31000,
y_min = 7,
place_offset_y = -1,
schematic = mpath .. '/schematics/everness/everness_haunted_house_badland.mts',
rotation = "random",
flags = 'place_center_x,place_center_z,force_placement',
})
-- Jungle temple
minetest.register_decoration({
name = "asuna_core:everness_jungle_temple_new",
deco_type = 'schematic',
place_on = "group:soil",
spawn_by = "group:soil",
num_spawn_by = 8,
sidelen = 80,
fill_ratio = 0.0000275,
biomes = {
"rainforest",
"livingjungle:jungle",
},
y_max = 31000,
y_min = 8,
place_offset_y = -3,
schematic = mpath .. '/schematics/everness/everness_jungle_temple_new.mts',
rotation = "random",
flags = 'place_center_x,place_center_z,force_placement',
})
-- Japanese shrine
minetest.register_decoration({
name = "asuna_core:everness_japanese_shrine_new",
deco_type = 'schematic',
place_on = "group:soil",
spawn_by = "group:soil",
num_spawn_by = 7,
sidelen = 80,
fill_ratio = 0.0000175,
biomes = {
"bamboo",
"japaneseforest",
},
y_max = 31000,
y_min = 8,
place_offset_y = -1,
schematic = mpath .. '/schematics/everness/everness_japanese_shrine_new.mts',
rotation = "random",
flags = 'place_center_x,place_center_z,force_placement',
})
-- Populate chests with loot
local asuna_core_everness_dids = {}
for _,decoration in ipairs({
"asuna_core:everness_haunted_house_badland",
"asuna_core:everness_jungle_temple_new",
"asuna_core:everness_japanese_shrine_new",
}) do
local did = minetest.get_decoration_id(decoration)
minetest.set_gen_notify({decoration = true},{did})
asuna_core_everness_dids["decoration#" .. did] = true
end
minetest.register_on_generated(function(minp,maxp)
if maxp.y > 4 then
local gennotify = minetest.get_mapgen_object("gennotify")
for decoration_id,decorations in pairs(gennotify) do
if asuna_core_everness_dids[decoration_id] then
local chest_positions = minetest.find_nodes_in_area(minp,maxp,{ 'everness:chest' })
if #chest_positions > 0 then
Everness:populate_loot_chests(chest_positions)
end
return
end
end
end
end)