From e4978a1da7c369cbfdf919472361c3ae336c9fcf Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 25 Oct 2013 12:51:06 +0400 Subject: [PATCH 1/2] Relax 3dveins preconditions to account for soil quirks and volcanoes. --- plugins/3dveins.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index e010ed3d3..432d93cf6 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -377,6 +377,7 @@ struct GeoLayer int16_t material; bool is_soil; + bool is_soil_layer; // World-global origin coordinates in blocks df::coord world_pos; @@ -489,6 +490,7 @@ GeoLayer::GeoLayer(GeoBiome *parent, int index, df::world_geo_layer *info) tiles = unmined_tiles = mineral_tiles = 0; material = info->mat_index; is_soil = isSoilInorganic(material); + is_soil_layer = (info->type == geo_layer_type::SOIL || info->type == geo_layer_type::SOIL_SAND); } const unsigned NUM_INCLUSIONS = 1+(int)ENUM_LAST_ITEM(inclusion_type); @@ -721,14 +723,17 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z) auto &top_solid = col_info.top_solid_z[x][y]; auto &bottom = col_info.bottom_layer[x][y]; - if (top_solid < 0 && isWallTerrain(b->baseTiletypeAt(tile))) + auto ttype = b->baseTiletypeAt(tile); + bool obsidian = (tileMaterial(ttype) == tiletype_material::LAVA_STONE); + + if (top_solid < 0 && !obsidian && isWallTerrain(ttype)) top_solid = z; if (max_level[idx] < 0) { // Do not start the layer stack in open air. // Those tiles can be very weird. - if (bottom < 0 && isOpenTerrain(b->baseTiletypeAt(tile))) + if (bottom < 0 && (isOpenTerrain(ttype) || obsidian)) continue; max_level[idx] = min_level[idx] = z; @@ -777,9 +782,14 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) if (max_defined < 0) continue; + int last_top = min_defined; + // Verify assumptions for (int i = min_defined; i < max_defined; i++) { + if (max_level[i] >= top_solid) + last_top = i; + if (max_level[i+1] < 0 && min_level[i] > top_solid) max_level[i+1] = min_level[i+1] = min_level[i]; @@ -815,6 +825,22 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) continue; } + // If below a thick soil layer, allow thickness to pass from prev to current. + // This accounts for a probable bug in worldgen soil placement code. + if (i > min_defined && i-1 <= last_top) + { + auto prev = biome->layers[i-1]; + + if (size > layer->thickness && + prev->is_soil_layer && prev->thickness > 1 && + size <= layer->thickness+prev->thickness-1) + { + max_level[i] += layer->thickness - size; + layer->setZBias(size - layer->thickness); + continue; + } + } + out.printerr( "Layer height change in layer %d at (%d,%d,%d): %d instead of %d.\n", i, x+column.x*16, y+column.y*16, max_level[i], From 54b45349c57ccf6fc1df2f72d12aedd9963c129b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 25 Oct 2013 14:37:37 +0400 Subject: [PATCH 2/2] Improve pre-embark prospect using new knowledge about soil depth. --- plugins/prospector.cpp | 101 +++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 25 deletions(-) diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index efd457dfd..cec6c3bcb 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -234,11 +234,18 @@ static coord2d biome_delta[] = { struct EmbarkTileLayout { coord2d biome_off, biome_pos; df::region_map_entry *biome; + df::world_geo_biome *geo_biome; int elevation, max_soil_depth; int min_z, base_z; std::map penalty; }; +static df::world_region_details *get_details(df::world_data *data, df::coord2d pos) +{ + int d_idx = linear_index(data->region_details, &df::world_region_details::pos, pos); + return vector_get(data->region_details, d_idx); +} + bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y) { // Find actual biome @@ -251,15 +258,37 @@ bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_ tile.biome_pos = coord2d(bx, by); tile.biome = &data->region_map[bx][by]; + tile.geo_biome = df::world_geo_biome::find(tile.biome->geo_index); + // Compute surface elevation - tile.elevation = ( - details->elevation[x][y] + details->elevation[x][y+1] + - details->elevation[x+1][y] + details->elevation[x+1][y+1] - ) / 4; - tile.max_soil_depth = std::max((154-tile.biome->elevation)/5,0); - tile.base_z = tile.elevation; + tile.elevation = details->elevation[x][y]; + tile.max_soil_depth = std::max((154-tile.elevation)/5,1); tile.penalty.clear(); + // Special biome adjustments + if (!tile.biome->flags.is_set(region_map_entry_flags::is_lake)) + { + // Mountain biome + if (tile.biome->elevation >= 150) + tile.max_soil_depth = 0; + // Ocean biome + else if (tile.biome->elevation < 100) + { + if (tile.elevation == 99) + tile.elevation = 98; + + if (tile.geo_biome && (tile.geo_biome->unk1 == 4 || tile.geo_biome->unk1 == 5)) + { + auto b_details = get_details(data, tile.biome_pos); + + if (b_details && b_details->unk12e8 < 500) + tile.max_soil_depth = 0; + } + } + } + + tile.base_z = tile.elevation-1; + auto &features = details->features[x][y]; // Collect global feature layer depths and apply penalties @@ -301,8 +330,8 @@ bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_ if (!sea_found) { - out.printerr("Could not find magma sea.\n"); - return false; + out.printerr("Could not find magma sea; depth may be incorrect.\n"); + tile.min_z = tile.base_z; } // Scan for big local features and apply their penalties @@ -340,7 +369,7 @@ bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &laye { using namespace geo_layer_type; - df::world_geo_biome *geo_biome = df::world_geo_biome::find(tile.biome->geo_index); + df::world_geo_biome *geo_biome = tile.geo_biome; if (!geo_biome) { @@ -350,35 +379,58 @@ bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &laye } // soil depth increases by 1 every 5 levels below 150 - int top_z_level = tile.elevation - tile.max_soil_depth; + unsigned nlayers = std::min(16, geo_biome->layers.size()); + int soil_size = 0; + + for (unsigned i = 0; i < nlayers; i++) + { + auto layer = geo_biome->layers[i]; + if (layer->type == SOIL || layer->type == SOIL_SAND) + soil_size += layer->top_height - layer->bottom_height + 1; + } - for (unsigned i = 0; i < geo_biome->layers.size(); i++) + // Compute shifts for layers in the stack + int soil_erosion = soil_size - std::min(soil_size,tile.max_soil_depth); + int layer_shift[16]; + int cur_shift = tile.elevation+soil_erosion-1; + + for (unsigned i = 0; i < nlayers; i++) { auto layer = geo_biome->layers[i]; - switch (layer->type) + layer_shift[i] = cur_shift; + + if (layer->type == SOIL || layer->type == SOIL_SAND) { - case SOIL: - case SOIL_OCEAN: - case SOIL_SAND: - top_z_level += layer->top_height - layer->bottom_height + 1; - break; - default:; + int size = layer->top_height - layer->bottom_height + 1; + + // This is to replicate the behavior of a probable bug in the + // map generation code: if a layer is partially eroded, the + // removed levels are in fact transferred to the layer below, + // because unlike the case of removing the whole layer, the code + // does not execute a loop to shift the lower part of the stack up. + if (size > soil_erosion) + cur_shift -= soil_erosion; + + soil_erosion -= std::min(soil_erosion, size); } } - top_z_level = std::max(top_z_level, tile.elevation)-1; + // Estimate amounts + int last_bottom = tile.elevation; - for (unsigned i = 0; i < geo_biome->layers.size(); i++) + for (unsigned i = 0; i < nlayers; i++) { auto layer = geo_biome->layers[i]; - int top_z = std::min(layer->top_height + top_z_level, tile.elevation-1); - int bottom_z = std::max(layer->bottom_height + top_z_level, tile.min_z); - if (i+1 == geo_biome->layers.size()) // stretch layer if needed + int top_z = last_bottom-1; + int bottom_z = std::max(layer->bottom_height + layer_shift[i], tile.min_z); + if (i+1 == nlayers) // stretch layer if needed bottom_z = tile.min_z; if (top_z < bottom_z) continue; + last_bottom = bottom_z; + float layer_size = 48*48; int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 }; @@ -438,8 +490,7 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choos df::world_data *data = world->world_data; coord2d cur_region = screen->region_pos; - int d_idx = linear_index(data->region_details, &df::world_region_details::pos, cur_region); - auto cur_details = vector_get(data->region_details, d_idx); + auto cur_details = get_details(data, cur_region); if (!cur_details) {