#include "util/numeric.h"
#include "filesys.h"
#include "log.h"
+#include "mapgen_carpathian.h"
#include "mapgen_flat.h"
#include "mapgen_fractal.h"
#include "mapgen_v5.h"
{"flat", true},
{"fractal", true},
{"valleys", true},
- {"singlenode", false},
+ {"singlenode", true},
+ {"carpathian", true},
};
STATIC_ASSERT(
Mapgen::Mapgen()
{
- generating = false;
- id = -1;
- seed = 0;
- water_level = 0;
- mapgen_limit = 0;
- flags = 0;
-
- vm = NULL;
- ndef = NULL;
- biomegen = NULL;
- biomemap = NULL;
- heightmap = NULL;
}
Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
{
- generating = false;
id = mapgenid;
water_level = params->water_level;
mapgen_limit = params->mapgen_limit;
*/
seed = (s32)params->seed;
- vm = NULL;
ndef = emerge->ndef;
- biomegen = NULL;
- biomemap = NULL;
- heightmap = NULL;
}
MapgenParams *params, EmergeManager *emerge)
{
switch (mgtype) {
+ case MAPGEN_CARPATHIAN:
+ return new MapgenCarpathian(mgid, (MapgenCarpathianParams *)params, emerge);
case MAPGEN_FLAT:
return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
case MAPGEN_FRACTAL:
MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
{
switch (mgtype) {
+ case MAPGEN_CARPATHIAN:
+ return new MapgenCarpathianParams;
case MAPGEN_FLAT:
return new MapgenFlatParams;
case MAPGEN_FRACTAL:
// Returns Y one under area minimum if not found
s16 Mapgen::findGroundLevelFull(v2s16 p2d)
{
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
s16 y_nodes_max = vm->m_area.MaxEdge.Y;
s16 y_nodes_min = vm->m_area.MinEdge.Y;
u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
// Returns -MAX_MAP_GENERATION_LIMIT if not found
s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
{
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
s16 y;
// Returns -MAX_MAP_GENERATION_LIMIT if not found or if ground is found first
s16 Mapgen::findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax)
{
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
s16 y;
heightmap[index] = y;
}
}
- //printf("updateHeightmap: %dus\n", t.stop());
}
inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
{
bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
//TimeTaker t("propagateSunlight");
VoxelArea a(nmin, nmax);
bool block_is_underground = (water_level >= nmax.Y);
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
// NOTE: Direct access to the low 4 bits of param1 is okay here because,
// by definition, sunlight will never be in the night lightbank.
}
-MgStoneType MapgenBasic::generateBiomes()
+void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
+ content_t *biome_stone, s16 biome_zero_level)
{
// can't generate biomes without a biome generator!
assert(biomegen);
assert(biomemap);
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
u32 index = 0;
- MgStoneType stone_type = MGSTONE_STONE;
+ MgStoneType stone_type = MGSTONE_OTHER;
+ content_t c_biome_stone = c_stone;
noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
(air_above || !biome);
if (is_stone_surface || is_water_surface) {
- biome = biomegen->getBiomeAtIndex(index, y);
+ // Limit to +-MAX MAP GENERATION LIMIT to work with biome y_min / y_max.
+ s32 relative_y = rangelim(y - biome_zero_level,
+ -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
+ biome = biomegen->getBiomeAtIndex(index, relative_y);
if (biomemap[index] == BIOME_NONE && is_stone_surface)
biomemap[index] = biome->index;
depth_riverbed = biome->depth_riverbed;
// Detect stone type for dungeons during every biome calculation.
- // This is more efficient than detecting per-node and will not
- // miss any desert stone or sandstone biomes.
- if (biome->c_stone == c_desert_stone)
+ // If none detected the last selected biome stone is chosen.
+ if (biome->c_stone == c_stone)
+ stone_type = MGSTONE_STONE;
+ else if (biome->c_stone == c_desert_stone)
stone_type = MGSTONE_DESERT_STONE;
else if (biome->c_stone == c_sandstone)
stone_type = MGSTONE_SANDSTONE;
+
+ c_biome_stone = biome->c_stone;
}
if (c == c_stone) {
}
}
- return stone_type;
+ *mgstone_type = stone_type;
+ *biome_stone = c_biome_stone;
}
if (node_max.Y < water_level)
return;
- v3s16 em = vm->m_area.getExtent();
+ const v3s16 &em = vm->m_area.getExtent();
u32 index = 0;
for (s16 z = node_min.Z; z <= node_max.Z; z++)
u32 bruises_count = ps.range(0, 2);
for (u32 i = 0; i < bruises_count; i++) {
CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
- c_water_source, CONTENT_IGNORE);
+ c_water_source, CONTENT_IGNORE, lava_depth);
cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
}
}
-void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
+void MapgenBasic::generateDungeons(s16 max_stone_y,
+ MgStoneType stone_type, content_t biome_stone)
{
if (max_stone_y < node_min.Y)
return;
dp.room_size_large_max = v3s16(18, 16, 18);
dp.notifytype = GENNOTIFY_DUNGEON;
break;
+ case MGSTONE_OTHER:
+ dp.c_wall = biome_stone;
+ dp.c_alt_wall = biome_stone;
+ dp.c_stair = biome_stone;
+
+ dp.diagonal_dirs = false;
+ dp.holesize = v3s16(1, 2, 1);
+ dp.room_size_min = v3s16(4, 4, 4);
+ dp.room_size_max = v3s16(8, 6, 8);
+ dp.room_size_large_min = v3s16(8, 8, 8);
+ dp.room_size_large_max = v3s16(16, 16, 16);
+ dp.notifytype = GENNOTIFY_DUNGEON;
+ break;
}
DungeonGen dgen(ndef, &gennotify, &dp);
GenerateNotifier::GenerateNotifier()
{
- m_notify_on = 0;
}
if (bparams)
bparams->writeParams(settings);
}
+
+// Calculate edges of outermost generated mapchunks (less than
+// 'mapgen_limit'), and corresponding exact limits for SAO entities.
+void MapgenParams::calcMapgenEdges()
+{
+ if (m_mapgen_edges_calculated)
+ return;
+
+ // Central chunk offset, in blocks
+ s16 ccoff_b = -chunksize / 2;
+ // Chunksize, in nodes
+ s32 csize_n = chunksize * MAP_BLOCKSIZE;
+ // Minp/maxp of central chunk, in nodes
+ s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
+ s16 ccmax = ccmin + csize_n - 1;
+ // Fullminp/fullmaxp of central chunk, in nodes
+ s16 ccfmin = ccmin - MAP_BLOCKSIZE;
+ s16 ccfmax = ccmax + MAP_BLOCKSIZE;
+ // Effective mapgen limit, in blocks
+ // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
+ s16 mapgen_limit_b = rangelim(mapgen_limit,
+ 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
+ // Effective mapgen limits, in nodes
+ s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
+ s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
+ // Number of complete chunks from central chunk fullminp/fullmaxp
+ // to effective mapgen limits.
+ s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
+ s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
+ // Mapgen edges, in nodes
+ mapgen_edge_min = ccmin - numcmin * csize_n;
+ mapgen_edge_max = ccmax + numcmax * csize_n;
+ // SAO position limits, in Irrlicht units
+ m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
+ m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
+
+ m_mapgen_edges_calculated = true;
+}
+
+
+bool MapgenParams::saoPosOverLimit(const v3f &p)
+{
+ if (!m_mapgen_edges_calculated)
+ calcMapgenEdges();
+
+ return p.X < m_sao_limit_min ||
+ p.X > m_sao_limit_max ||
+ p.Y < m_sao_limit_min ||
+ p.Y > m_sao_limit_max ||
+ p.Z < m_sao_limit_min ||
+ p.Z > m_sao_limit_max;
+}
+
+
+s32 MapgenParams::getSpawnRangeMax()
+{
+ calcMapgenEdges();
+
+ return MYMIN(-mapgen_edge_min, mapgen_edge_max);
+}