depth_riverbed = 2,
-- Node placed under river water and thickness of this layer
- node_cave_liquid = "default:water_source",
- -- Nodes placed as a blob of liquid in 50% of large caves.
- -- If absent, cave liquids fall back to classic behaviour of lava or
- -- water distributed according to a hardcoded 3D noise.
+ node_cave_liquid = "default:lava_source",
+ node_cave_liquid = {"default:water_source", "default:lava_source"},
+ -- Nodes placed inside 50% of the medium size caves.
+ -- Multiple nodes can be specified, each cave will use a randomly
+ -- chosen node from the list.
+ -- If this field is left out or 'nil', cave liquids fall back to
+ -- classic behaviour of lava and water distributed using 3D noise.
+ -- For no cave liquid, specify "air".
node_dungeon = "default:cobble",
-- Node used for primary dungeon structure.
this->ystride = nmax.X - nmin.X + 1;
+ flooded = ps->range(1, 2) == 2;
+
+ // If flooded:
+ // Get biome at mapchunk midpoint. If cave liquid defined for biome, use it.
+ // If defined liquid is "air", disable 'flooded' to avoid placing "air".
+ use_biome_liquid = false;
+ if (flooded && bmgn) {
+ v3s16 midp = node_min + (node_max - node_min) / v3s16(2, 2, 2);
+ Biome *biome = (Biome *)bmgn->getBiomeAtPoint(midp);
+ if (biome->c_cave_liquid[0] != CONTENT_IGNORE) {
+ use_biome_liquid = true;
+ c_biome_liquid =
+ biome->c_cave_liquid[ps->range(0, biome->c_cave_liquid.size() - 1)];
+ if (c_biome_liquid == CONTENT_AIR)
+ flooded = false;
+ }
+ }
+
// Set initial parameters from randomness
int dswitchint = ps->range(1, 14);
- flooded = ps->range(1, 2) == 2;
if (large_cave) {
part_max_length_rs = ps->range(2, 4);
fp.Z += 0.1f * ps->range(-10, 10);
v3s16 cp(fp.X, fp.Y, fp.Z);
- // Get biome at 'cp + of', the absolute centre point of this route
- v3s16 cpabs = cp + of;
+ // Choose cave liquid
MapNode liquidnode = CONTENT_IGNORE;
- if (bmgn) {
- Biome *biome = nullptr;
- if (cpabs.X < node_min.X || cpabs.X > node_max.X ||
- cpabs.Z < node_min.Z || cpabs.Z > node_max.Z)
- // Point is outside heat and humidity noise maps so use point noise
- // calculations.
- biome = (Biome *)bmgn->calcBiomeAtPoint(cpabs);
- else
- // Point is inside heat and humidity noise maps so use them
- biome = (Biome *)bmgn->getBiomeAtPoint(cpabs);
-
- if (biome->c_cave_liquid != CONTENT_IGNORE)
- liquidnode = biome->c_cave_liquid;
- }
-
- if (liquidnode == CONTENT_IGNORE) {
- // Fallback to classic behaviour using point 'startp'
- float nval = NoisePerlin3D(np_caveliquids, startp.X,
- startp.Y, startp.Z, seed);
- liquidnode = (nval < 0.40f && node_max.Y < lava_depth) ?
- lavanode : waternode;
+ if (flooded) {
+ if (use_biome_liquid) {
+ liquidnode = c_biome_liquid;
+ } else {
+ // If cave liquid not defined by biome, fallback to old hardcoded behaviour
+ float nval = NoisePerlin3D(np_caveliquids, startp.X,
+ startp.Y, startp.Z, seed);
+ liquidnode = (nval < 0.40f && node_max.Y < lava_depth) ?
+ lavanode : waternode;
+ }
}
s16 d0 = -rs / 2;
bool large_cave;
bool large_cave_is_flat;
bool flooded;
+ bool use_biome_liquid;
v3s16 node_min;
v3s16 node_max;
content_t c_water_source;
content_t c_lava_source;
+ content_t c_biome_liquid;
// ndef is a mandatory parameter.
// If gennotify is NULL, generation events are not logged.
b->m_nodenames.emplace_back("mapgen_stone");
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
+ b->m_nnlistsizes.push_back(1);
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
b->m_nodenames.emplace_back("ignore");
getIdFromNrBacklog(&c_river_water, "mapgen_river_water_source", CONTENT_AIR, false);
getIdFromNrBacklog(&c_riverbed, "mapgen_stone", CONTENT_AIR, false);
getIdFromNrBacklog(&c_dust, "ignore", CONTENT_IGNORE, false);
- getIdFromNrBacklog(&c_cave_liquid, "ignore", CONTENT_IGNORE, false);
+ getIdsFromNrBacklog(&c_cave_liquid);
getIdFromNrBacklog(&c_dungeon, "ignore", CONTENT_IGNORE, false);
getIdFromNrBacklog(&c_dungeon_alt, "ignore", CONTENT_IGNORE, false);
getIdFromNrBacklog(&c_dungeon_stair, "ignore", CONTENT_IGNORE, false);
content_t c_river_water;
content_t c_riverbed;
content_t c_dust;
- content_t c_cave_liquid;
+ std::vector<content_t> c_cave_liquid;
content_t c_dungeon;
content_t c_dungeon_alt;
content_t c_dungeon_stair;
nn.push_back(getstringfield_default(L, index, "node_river_water", ""));
nn.push_back(getstringfield_default(L, index, "node_riverbed", ""));
nn.push_back(getstringfield_default(L, index, "node_dust", ""));
- nn.push_back(getstringfield_default(L, index, "node_cave_liquid", ""));
+
+ size_t nnames = getstringlistfield(L, index, "node_cave_liquid", &nn);
+ // If no cave liquids defined, set list to "ignore" to trigger old hardcoded
+ // cave liquid behaviour.
+ if (nnames == 0) {
+ nn.push_back("ignore");
+ nnames = 1;
+ }
+ b->m_nnlistsizes.push_back(nnames);
+
nn.push_back(getstringfield_default(L, index, "node_dungeon", ""));
nn.push_back(getstringfield_default(L, index, "node_dungeon_alt", ""));
nn.push_back(getstringfield_default(L, index, "node_dungeon_stair", ""));