diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index c9e15aae5..9802ff5eb 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -661,6 +661,55 @@ GeoLayer *VeinGenerator::mapLayer(Block *pb, df::coord2d tile) return biome->layers[lidx]; } +static bool isTransientMaterial(df::tiletype tile) +{ + using namespace df::enums::tiletype_material; + + switch (tileMaterial(tile)) + { + case AIR: + case LAVA_STONE: + case PLANT: + case ROOT: + case TREE: + case MUSHROOM: + return true; + + default: + return false; + } +} + +static bool isSkyBlock(Block *b) +{ + for (int x = 0; x < 16; x++) + { + for (int y = 0; y < 16; y++) + { + df::coord2d tile(x,y); + auto dsgn = b->DesignationAt(tile); + auto ttype = b->baseTiletypeAt(tile); + + if (dsgn.bits.subterranean || !dsgn.bits.light || !isTransientMaterial(ttype)) + return false; + } + } + + return true; +} + +static int findTopBlock(MapCache &map, int x, int y) +{ + for (int z = map.maxZ(); z >= 0; z--) + { + Block *b = map.BlockAt(df::coord(x,y,z)); + if (b && b->is_valid() && !isSkyBlock(b)) + return z; + } + + return -1; +} + bool VeinGenerator::scan_tiles() { for (int x = 0; x < size.x; x++) @@ -669,8 +718,10 @@ bool VeinGenerator::scan_tiles() { df::coord2d column(x,y); + int top = findTopBlock(map, x, y); + // First find where layers start and end - for (int z = map.maxZ(); z >= 0; z--) + for (int z = top; z >= 0; z--) { Block *b = map.BlockAt(df::coord(x,y,z)); if (!b || !b->is_valid()) @@ -684,7 +735,7 @@ bool VeinGenerator::scan_tiles() return false; // Collect tile data - for (int z = map.maxZ(); z >= 0; z--) + for (int z = top; z >= 0; z--) { Block *b = map.BlockAt(df::coord(x,y,z)); if (!b || !b->is_valid()) @@ -725,7 +776,7 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z) auto &bottom = col_info.bottom_layer[x][y]; auto ttype = b->baseTiletypeAt(tile); - bool obsidian = (tileMaterial(ttype) == tiletype_material::LAVA_STONE); + bool obsidian = isTransientMaterial(ttype); if (top_solid < 0 && !obsidian && isWallTerrain(ttype)) top_solid = z; @@ -974,7 +1025,9 @@ void VeinGenerator::write_tiles() { df::coord2d column(x,y); - for (int z = map.maxZ(); z >= 0; z--) + int top = findTopBlock(map, x, y); + + for (int z = top; z >= 0; z--) { Block *b = map.BlockAt(df::coord(x,y,z)); if (!b || !b->is_valid())