summaryrefslogtreecommitdiff
path: root/plugins/prospector.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-08-27 23:03:17 +0400
committerAlexander Gavrilov2012-08-27 23:03:17 +0400
commitf73cebff68922801e4eaeffbd2b0487d868a3b56 (patch)
treea55b70a2b38b98410d35efaffd9f41198d69b1dc /plugins/prospector.cpp
parentf1915915b48395e9180c03dc8bf26f303eff877f (diff)
downloaddfhack-f73cebff68922801e4eaeffbd2b0487d868a3b56.tar.gz
dfhack-f73cebff68922801e4eaeffbd2b0487d868a3b56.tar.bz2
dfhack-f73cebff68922801e4eaeffbd2b0487d868a3b56.tar.xz
Account for caves and magma sea in pre-embark prospector.
Diffstat (limited to 'plugins/prospector.cpp')
-rw-r--r--plugins/prospector.cpp292
1 files changed, 211 insertions, 81 deletions
diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp
index 6836b38c..dce44e35 100644
--- a/plugins/prospector.cpp
+++ b/plugins/prospector.cpp
@@ -25,8 +25,11 @@ using namespace std;
#include "df/world.h"
#include "df/world_data.h"
#include "df/world_region_details.h"
+#include "df/world_region_feature.h"
#include "df/world_geo_biome.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/inclusion_type.h"
#include "df/viewscreen_choose_start_sitest.h"
@@ -109,9 +112,10 @@ 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)
{
- con << std::setw(9) << data.count;
+ if (!only_z)
+ con << std::setw(9) << data.count;
if(data.lower_z != data.upper_z)
con <<" Z:" << std::setw(4) << data.lower_z << ".." << data.upper_z << std::endl;
@@ -226,116 +230,239 @@ static coord2d biome_delta[] = {
coord2d(-1,-1), coord2d(0,-1), coord2d(1,-1)
};
-static command_result embark_prospector(color_ostream &out, df::viewscreen_choose_start_sitest *screen,
- bool showHidden, bool showValue)
+struct EmbarkTileLayout {
+ 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] +
+ details->elevation[x+1][y] + details->elevation[x+1][y+1]
+ ) / 4;
+ tile.base_z = tile.elevation;
+ tile.penalty.clear();
+
+ auto &features = details->features[x][y];
+
+ // 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("World data is not available.\n");
- return CR_FAILURE;
+ auto feature = features[i];
+ auto layer = df::world_underground_region::find(feature->layer);
+ if (!layer || feature->min_z == -30000) continue;
+
+ layer_bottom[layer->layer_depth] = feature->min_z;
+ layer_top[layer->layer_depth] = feature->max_z;
+ tile.base_z = std::min(tile.base_z, (int)feature->min_z);
+
+ 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)
+ {
+ for (int i = feature->min_z; i <= feature->max_z; i++)
+ tile.penalty[i] = penalty;
+ }
}
- 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 (!sea_found)
+ {
+ out.printerr("Could not find magma sea.\n");
+ return false;
+ }
- if (!cur_details)
+ // Scan for big local features and apply their penalties
+ for (size_t i = 0; i < features.size(); i++)
{
- out.printerr("Current region details are not available.\n");
- return CR_FAILURE;
+ auto feature = features[i];
+ auto lfeature = Maps::getLocalInitFeature(details->pos, feature->feature_idx);
+ if (!lfeature)
+ continue;
+
+ switch (lfeature->getType())
+ {
+ case feature_type::pit:
+ 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 biomes
- std::map<coord2d, int> biomes;
+ return true;
+}
+
+void add_materials(EmbarkTileLayout &tile, matdata &data, float amount, int min_z, int max_z)
+{
+ for (int z = min_z; z <= max_z; z++)
+ 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;
- if (screen->biome_highlighted)
+ 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];
+ df::world_geo_biome *geo_biome = df::world_geo_biome::find(region.geo_index);
+
+ if (!geo_biome)
{
- out.print("Processing one embark tile of biome F%d.\n\n", screen->biome_idx+1);
- biomes[screen->biome_rgn[screen->biome_idx]]++;
+ out.printerr("Region geo-biome not found: (%d,%d)\n", bx, by);
+ return false;
}
- else
+
+ // 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++)
{
- for (int x = screen->embark_pos_min.x; x <= screen->embark_pos_max.x; x++)
+ auto layer = geo_biome->layers[i];
+ switch (layer->type)
{
- for (int y = screen->embark_pos_min.y; y <= screen->embark_pos_max.y; y++)
- {
- int bv = clip_range(cur_details->biome[x][y], 1, 9);
- biomes[cur_region + biome_delta[bv-1]]++;
- }
+ case SOIL:
+ case SOIL_OCEAN:
+ case SOIL_SAND:
+ top_z_level += layer->top_height - layer->bottom_height + 1;
+ break;
+ default:;
}
}
- // Compute material maps
- MatMap layerMats;
- MatMap veinMats;
+ top_z_level = std::max(top_z_level, tile.elevation)-1;
- for (auto biome_it = biomes.begin(); biome_it != biomes.end(); ++biome_it)
+ for (unsigned i = 0; i < geo_biome->layers.size(); i++)
{
- int bx = clip_range(biome_it->first.x, 0, data->world_width-1);
- int by = clip_range(biome_it->first.y, 0, data->world_height-1);
- auto &region = data->region_map[bx][by];
- df::world_geo_biome *geo_biome = df::world_geo_biome::find(region.geo_index);
+ 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
+ bottom_z = tile.min_z;
+ if (top_z < bottom_z)
+ continue;
+
+ float layer_size = 48*48;
+
+ int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 };
+
+ for (unsigned j = 0; j < layer->vein_mat.size(); j++)
+ if (is_valid_enum_item<df::inclusion_type>(layer->vein_type[j]))
+ sums[layer->vein_type[j]] += layer->vein_unk_38[j];
- if (!geo_biome)
+ for (unsigned j = 0; j < layer->vein_mat.size(); j++)
{
- out.printerr("Region geo-biome not found: (%d,%d)\n", bx, by);
- return CR_FAILURE;
+ // TODO: find out how to estimate the real density
+ // this code assumes that vein_unk_38 is the weight
+ // used when choosing the vein material
+ float size = float(layer->vein_unk_38[j]);
+ df::inclusion_type type = layer->vein_type[j];
+
+ switch (type)
+ {
+ case inclusion_type::VEIN:
+ // 3 veins of 80 tiles avg
+ size = size * 80 * 3 / sums[type];
+ break;
+ case inclusion_type::CLUSTER:
+ // 1 cluster of 700 tiles avg
+ size = size * 700 * 1 / sums[type];
+ break;
+ case inclusion_type::CLUSTER_SMALL:
+ size = size * 6 * 7 / sums[type];
+ break;
+ case inclusion_type::CLUSTER_ONE:
+ size = size * 1 * 5 / sums[type];
+ break;
+ default:
+ // shouldn't actually happen
+ size = 1;
+ }
+
+ layer_size -= size;
+
+ add_materials(tile, veinMats[layer->vein_mat[j]], size, bottom_z, top_z);
}
- int cnt = biome_it->second;
+ add_materials(tile, layerMats[layer->mat_index], layer_size, bottom_z, top_z);
+ }
- for (unsigned i = 0; i < geo_biome->layers.size(); i++)
- {
- auto layer = geo_biome->layers[i];
+ return true;
+}
- layerMats[layer->mat_index].add(layer->bottom_height, 0);
+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;
+ }
- int level_cnt = layer->top_height - layer->bottom_height + 1;
- int layer_size = 48*48*cnt*level_cnt;
+ 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);
- int sums[ENUM_LAST_ITEM(inclusion_type)+1] = { 0 };
+ if (!cur_details)
+ {
+ out.printerr("Current region details are not available.\n");
+ return CR_FAILURE;
+ }
- for (unsigned j = 0; j < layer->vein_mat.size(); j++)
- if (is_valid_enum_item<df::inclusion_type>(layer->vein_type[j]))
- sums[layer->vein_type[j]] += layer->vein_unk_38[j];
+ // Compute material maps
+ MatMap layerMats;
+ MatMap veinMats;
+ matdata world_bottom;
- for (unsigned j = 0; j < layer->vein_mat.size(); j++)
- {
- // TODO: find out how to estimate the real density
- // this code assumes that vein_unk_38 is the weight
- // used when choosing the vein material
- int size = layer->vein_unk_38[j]*cnt*level_cnt;
- df::inclusion_type type = layer->vein_type[j];
+ // Compute biomes
+ std::map<coord2d, int> biomes;
- switch (type)
- {
- case inclusion_type::VEIN:
- // 3 veins of 80 tiles avg
- size = size * 80 * 3 / sums[type];
- break;
- case inclusion_type::CLUSTER:
- // 1 cluster of 700 tiles avg
- size = size * 700 * 1 / sums[type];
- break;
- case inclusion_type::CLUSTER_SMALL:
- size = size * 6 * 7 / sums[type];
- break;
- case inclusion_type::CLUSTER_ONE:
- size = size * 1 * 5 / sums[type];
- break;
- default:
- // shouldn't actually happen
- size = cnt*level_cnt;
- }
+ /*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]]++;
+ }*/
- veinMats[layer->vein_mat[j]].add(layer->bottom_height, 0);
- veinMats[layer->vein_mat[j]].add(layer->top_height, size);
+ 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];
- layer_size -= size;
- }
+ EmbarkTileLayout tile;
+ if (!estimate_underground(out, tile, cur_details, x, y) ||
+ !estimate_materials(out, tile, layerMats, veinMats, rgn))
+ return CR_FAILURE;
- layerMats[layer->mat_index].add(layer->top_height, std::max(0,layer_size));
+ 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();
}
- 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;
}