Account for caves and magma sea in pre-embark prospector.

develop
Alexander Gavrilov 2012-08-27 23:03:17 +04:00
parent f1915915b4
commit f73cebff68
1 changed files with 211 additions and 81 deletions

@ -25,8 +25,11 @@ using namespace std;
#include "df/world.h" #include "df/world.h"
#include "df/world_data.h" #include "df/world_data.h"
#include "df/world_region_details.h" #include "df/world_region_details.h"
#include "df/world_region_feature.h"
#include "df/world_geo_biome.h" #include "df/world_geo_biome.h"
#include "df/world_geo_layer.h" #include "df/world_geo_layer.h"
#include "df/world_underground_region.h"
#include "df/feature_init.h"
#include "df/region_map_entry.h" #include "df/region_map_entry.h"
#include "df/inclusion_type.h" #include "df/inclusion_type.h"
#include "df/viewscreen_choose_start_sitest.h" #include "df/viewscreen_choose_start_sitest.h"
@ -109,8 +112,9 @@ struct compare_pair_second
} }
}; };
static void printMatdata(color_ostream &con, const matdata &data) static void printMatdata(color_ostream &con, const matdata &data, bool only_z = false)
{ {
if (!only_z)
con << std::setw(9) << data.count; con << std::setw(9) << data.count;
if(data.lower_z != data.upper_z) if(data.lower_z != data.upper_z)
@ -226,73 +230,144 @@ static coord2d biome_delta[] = {
coord2d(-1,-1), coord2d(0,-1), coord2d(1,-1) coord2d(-1,-1), coord2d(0,-1), coord2d(1,-1)
}; };
static command_result embark_prospector(color_ostream &out, df::viewscreen_choose_start_sitest *screen, struct EmbarkTileLayout {
bool showHidden, bool showValue) int elevation;
int min_z, base_z;
std::map<int, float> penalty;
};
bool estimate_underground(color_ostream &out, EmbarkTileLayout &tile, df::world_region_details *details, int x, int y)
{ {
if (!world || !world->world_data) tile.elevation = (
{ details->elevation[x][y] + details->elevation[x][y+1] +
out.printerr("World data is not available.\n"); details->elevation[x+1][y] + details->elevation[x+1][y+1]
return CR_FAILURE; ) / 4;
} tile.base_z = tile.elevation;
tile.penalty.clear();
df::world_data *data = world->world_data; auto &features = details->features[x][y];
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);
if (!cur_details) // Collect global feature layer depths and apply penalties
std::map<int, int> layer_bottom, layer_top;
bool sea_found = false;
for (size_t i = 0; i < features.size(); i++)
{ {
out.printerr("Current region details are not available.\n"); auto feature = features[i];
return CR_FAILURE; auto layer = df::world_underground_region::find(feature->layer);
} if (!layer || feature->min_z == -30000) continue;
// Compute biomes layer_bottom[layer->layer_depth] = feature->min_z;
std::map<coord2d, int> biomes; layer_top[layer->layer_depth] = feature->max_z;
tile.base_z = std::min(tile.base_z, (int)feature->min_z);
if (screen->biome_highlighted) float penalty = 1.0f;
switch (layer->type) {
case df::world_underground_region::Cavern:
penalty = 0.75f;
break;
case df::world_underground_region::MagmaSea:
sea_found = true;
tile.min_z = feature->min_z;
for (int i = feature->min_z; i <= feature->max_z; i++)
tile.penalty[i] = 0.2 + 0.6f*(i-feature->min_z)/(feature->max_z-feature->min_z+1);
break;
case df::world_underground_region::Underworld:
penalty = 0.0f;
break;
}
if (penalty != 1.0f)
{ {
out.print("Processing one embark tile of biome F%d.\n\n", screen->biome_idx+1); for (int i = feature->min_z; i <= feature->max_z; i++)
biomes[screen->biome_rgn[screen->biome_idx]]++; tile.penalty[i] = penalty;
} }
else }
if (!sea_found)
{ {
for (int x = screen->embark_pos_min.x; x <= screen->embark_pos_max.x; x++) out.printerr("Could not find magma sea.\n");
return false;
}
// Scan for big local features and apply their penalties
for (size_t i = 0; i < features.size(); i++)
{ {
for (int y = screen->embark_pos_min.y; y <= screen->embark_pos_max.y; y++) auto feature = features[i];
auto lfeature = Maps::getLocalInitFeature(details->pos, feature->feature_idx);
if (!lfeature)
continue;
switch (lfeature->getType())
{ {
int bv = clip_range(cur_details->biome[x][y], 1, 9); case feature_type::pit:
biomes[cur_region + biome_delta[bv-1]]++; case feature_type::magma_pool:
} case feature_type::volcano:
for (int i = layer_bottom[lfeature->end_depth];
i <= layer_top[lfeature->start_depth]; i++)
tile.penalty[i] = std::min(0.4f, map_find(tile.penalty, i, 1.0f));
break;
default:
break;
} }
} }
// Compute material maps return true;
MatMap layerMats; }
MatMap veinMats;
for (auto biome_it = biomes.begin(); biome_it != biomes.end(); ++biome_it) void add_materials(EmbarkTileLayout &tile, matdata &data, float amount, int min_z, int max_z)
{ {
int bx = clip_range(biome_it->first.x, 0, data->world_width-1); for (int z = min_z; z <= max_z; z++)
int by = clip_range(biome_it->first.y, 0, data->world_height-1); data.add(z, int(map_find(tile.penalty, z, 1)*amount));
}
bool estimate_materials(color_ostream &out, EmbarkTileLayout &tile, MatMap &layerMats, MatMap &veinMats, df::coord2d biome)
{
using namespace geo_layer_type;
df::world_data *data = world->world_data;
int bx = clip_range(biome.x, 0, data->world_width-1);
int by = clip_range(biome.y, 0, data->world_height-1);
auto &region = data->region_map[bx][by]; auto &region = data->region_map[bx][by];
df::world_geo_biome *geo_biome = df::world_geo_biome::find(region.geo_index); df::world_geo_biome *geo_biome = df::world_geo_biome::find(region.geo_index);
if (!geo_biome) if (!geo_biome)
{ {
out.printerr("Region geo-biome not found: (%d,%d)\n", bx, by); out.printerr("Region geo-biome not found: (%d,%d)\n", bx, by);
return CR_FAILURE; return false;
} }
int cnt = biome_it->second; // soil depth increases by 1 every 5 levels below 150
int top_z_level = tile.elevation - std::max((154-tile.elevation)/5,0);
for (unsigned i = 0; i < geo_biome->layers.size(); i++)
{
auto layer = geo_biome->layers[i];
switch (layer->type)
{
case SOIL:
case SOIL_OCEAN:
case SOIL_SAND:
top_z_level += layer->top_height - layer->bottom_height + 1;
break;
default:;
}
}
top_z_level = std::max(top_z_level, tile.elevation)-1;
for (unsigned i = 0; i < geo_biome->layers.size(); i++) for (unsigned i = 0; i < geo_biome->layers.size(); i++)
{ {
auto layer = geo_biome->layers[i]; auto layer = geo_biome->layers[i];
layerMats[layer->mat_index].add(layer->bottom_height, 0); 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
bottom_z = tile.min_z;
if (top_z < bottom_z)
continue;
int level_cnt = layer->top_height - layer->bottom_height + 1; float layer_size = 48*48;
int layer_size = 48*48*cnt*level_cnt;
int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 }; int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 };
@ -305,7 +380,7 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choos
// TODO: find out how to estimate the real density // TODO: find out how to estimate the real density
// this code assumes that vein_unk_38 is the weight // this code assumes that vein_unk_38 is the weight
// used when choosing the vein material // used when choosing the vein material
int size = layer->vein_unk_38[j]*cnt*level_cnt; float size = float(layer->vein_unk_38[j]);
df::inclusion_type type = layer->vein_type[j]; df::inclusion_type type = layer->vein_type[j];
switch (type) switch (type)
@ -326,16 +401,68 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choos
break; break;
default: default:
// shouldn't actually happen // shouldn't actually happen
size = cnt*level_cnt; size = 1;
} }
veinMats[layer->vein_mat[j]].add(layer->bottom_height, 0);
veinMats[layer->vein_mat[j]].add(layer->top_height, size);
layer_size -= size; layer_size -= size;
add_materials(tile, veinMats[layer->vein_mat[j]], size, bottom_z, top_z);
} }
layerMats[layer->mat_index].add(layer->top_height, std::max(0,layer_size)); add_materials(tile, layerMats[layer->mat_index], layer_size, bottom_z, top_z);
}
return true;
}
static command_result embark_prospector(color_ostream &out, df::viewscreen_choose_start_sitest *screen,
bool showHidden, bool showValue)
{
if (!world || !world->world_data)
{
out.printerr("World data is not available.\n");
return CR_FAILURE;
}
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);
if (!cur_details)
{
out.printerr("Current region details are not available.\n");
return CR_FAILURE;
}
// Compute material maps
MatMap layerMats;
MatMap veinMats;
matdata world_bottom;
// Compute biomes
std::map<coord2d, int> biomes;
/*if (screen->biome_highlighted)
{
out.print("Processing one embark tile of biome F%d.\n\n", screen->biome_idx+1);
biomes[screen->biome_rgn[screen->biome_idx]]++;
}*/
for (int x = screen->embark_pos_min.x; x <= screen->embark_pos_max.x; x++)
{
for (int y = screen->embark_pos_min.y; y <= screen->embark_pos_max.y; y++)
{
int bv = clip_range(cur_details->biome[x][y] & 15, 1, 9);
df::coord2d rgn = cur_region + biome_delta[bv-1];
EmbarkTileLayout tile;
if (!estimate_underground(out, tile, cur_details, x, y) ||
!estimate_materials(out, tile, layerMats, veinMats, rgn))
return CR_FAILURE;
world_bottom.add(tile.base_z, 0);
world_bottom.add(tile.elevation-1, 0);
} }
} }
@ -349,7 +476,10 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choos
mats->Finish(); mats->Finish();
} }
out << "Warning: the above data is only a very rough estimate." << std::endl; out << "Embark depth: " << (world_bottom.upper_z-world_bottom.lower_z+1) << " ";
printMatdata(out, world_bottom, true);
out << std::endl << "Warning: the above data is only a very rough estimate." << std::endl;
return CR_OK; return CR_OK;
} }