diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp index 2048da1fe..ad242ae49 100644 --- a/src/mapgen_v7.cpp +++ b/src/mapgen_v7.cpp @@ -202,10 +202,7 @@ void MapgenV7Params::writeParams(Settings *settings) const int MapgenV7::getSpawnLevelAtPoint(v2s16 p) { - // Base terrain calculation - s16 y = baseTerrainLevelAtPoint(p.X, p.Y); - - // If enabled, check if inside a river + // If rivers are enabled, first check if in a river if (spflags & MGV7_RIDGES) { float width = 0.2; float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2; @@ -213,28 +210,41 @@ int MapgenV7::getSpawnLevelAtPoint(v2s16 p) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point } - // If mountains are disabled, terrain level is base terrain level - // Avoids spawn on non-existant mountain terrain + // Terrain noise 'offset' is the average level of that terrain. + // At least 50% of terrain will be below the higher of base and alt terrain + // 'offset's. + // Raising the maximum spawn level above 'water_level + 16' is necessary + // for when terrain 'offset's are set much higher than water_level. + s16 max_spawn_y = MYMAX(MYMAX(noise_terrain_alt->np.offset, + noise_terrain_base->np.offset), + water_level + 16); + // Base terrain calculation + s16 y = baseTerrainLevelAtPoint(p.X, p.Y); + + // If mountains are disabled, terrain level is base terrain level. + // Avoids mid-air spawn where mountain terrain would have been. if (!(spflags & MGV7_MOUNTAINS)) { - if (y <= water_level || y > water_level + 16) + if (y <= water_level || y > max_spawn_y) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point else - return y; + // + 1 to not be half-buried in a potential node-deep biome 'dust' + return y + 1; } - // Mountain terrain calculation - int iters = 128; - while (iters--) { + // Search upwards for first node without mountain terrain + int iters = 256; + while (iters > 0 && y <= max_spawn_y) { if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { // If air above - if (y <= water_level || y > water_level + 16) + if (y <= water_level || y > max_spawn_y) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point else - return y; + return y + 1; } y++; + iters--; } - // Unsuitable spawn point, no mountain surface found + // Unsuitable spawn point return MAX_MAP_GENERATION_LIMIT; }