Added detection and use of incursions into embark tiles

develop
PatrikLundell 2019-07-12 22:09:03 +02:00
parent 53cf1136fb
commit 8248832cbc
10 changed files with 2141 additions and 305 deletions

@ -1,4 +1,4 @@
call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
call "D:\Program (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
cd VC2015
msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo INSTALL.vcxproj
cd ..

@ -44,8 +44,10 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Misc Improvements
- `embark-assistant`:
- Changed Flat detection to allow search for verified flat terrain by checking surrounding Mid Level Tiles or just mostly/probably flat terrain by checking embark tiles only.
- Changed Waterfall detection to look for level drop rather than just presence.
- Changed matching to take incursions, i.e. parts of other biomes, into consideration when evaluating tiles. This allows for e.g. finding multiple biomes on single tile embarks.
- Changed overlay display to show when incursion surveying is incomplete.
- Changed overlay display to show Evil Weather.
## Internals
- Fixed some OpenGL build issues with `stonesense`

@ -3,6 +3,7 @@
#include <array>
#include <string>
#include <vector>
#include "df/world_region_type.h"
using namespace std;
using std::array;
@ -23,12 +24,6 @@ namespace embark_assist {
Major
};
enum class flatnesses {
Flat_Verified,
Mostly_Flat,
Uneven
};
struct mid_level_tile {
bool aquifer = false;
bool clay = false;
@ -88,6 +83,16 @@ namespace embark_assist {
std::vector<bool> metals;
std::vector<bool> economics;
std::vector<bool> minerals;
mid_level_tile north_row[16];
mid_level_tile south_row[16];
mid_level_tile west_column[16];
mid_level_tile east_column[16];
uint8_t north_corner_selection[16]; // 0 - 3. For some reason DF stores everything needed for incursion
uint8_t west_corner_selection[16]; // detection in 17:th row/colum data in the region details except
// this info, so we have to go to neighboring world tiles to fetch it.
df::world_region_type region_type[16][16]; // Required for incursion override detection. We could store only the
// edges, but storing it for every tile allows for a unified fetching
// logic.
};
struct geo_datum {
@ -113,16 +118,22 @@ namespace embark_assist {
};
struct site_infos {
bool incursions_processed;
bool aquifer;
bool aquifer_full;
uint8_t min_soil;
uint8_t max_soil;
flatnesses flatness;
bool flat;
uint8_t max_waterfall;
bool clay;
bool sand;
bool flux;
bool coal;
bool blood_rain;
bool permanent_syndrome_rain;
bool temporary_syndrome_rain;
bool reanimating;
bool thralling;
std::vector<uint16_t> metals;
std::vector<uint16_t> economics;
std::vector<uint16_t> minerals;
@ -180,13 +191,6 @@ namespace embark_assist {
Major
};
enum class flatness_ranges : int8_t {
NA = -1,
Flat_Verified,
Mostly_Flat,
Uneven
};
// For possible future use. That's the level of data actually collected.
// enum class adamantine_ranges : int8_t {
// NA = -1,
@ -266,7 +270,7 @@ namespace embark_assist {
river_ranges min_river;
river_ranges max_river;
int8_t min_waterfall; // N/A(-1), Absent, 1-9
flatness_ranges flatness;
yes_no_ranges flat;
present_absent_ranges clay;
present_absent_ranges sand;
present_absent_ranges flux;

@ -62,7 +62,10 @@ namespace embark_assist {
&state->survey_results,
&mlt);
embark_assist::survey::survey_embark(&mlt, &state->site_info, false);
embark_assist::survey::survey_embark(&mlt,
&state->survey_results,
&state->site_info,
false);
embark_assist::overlay::set_embark(&state->site_info);
embark_assist::survey::survey_region_sites(&state->region_sites);
@ -291,7 +294,7 @@ command_result embark_assistant(color_ostream &out, std::vector <std::string> &
embark_assist::defs::mid_level_tiles mlt;
embark_assist::survey::survey_mid_level_tile(&embark_assist::main::state->geo_summary, &embark_assist::main::state->survey_results, &mlt);
embark_assist::survey::survey_embark(&mlt, &embark_assist::main::state->site_info, false);
embark_assist::survey::survey_embark(&mlt, &embark_assist::main::state->survey_results, &embark_assist::main::state->site_info, false);
embark_assist::overlay::set_embark(&embark_assist::main::state->site_info);
return CR_OK;

@ -40,7 +40,7 @@ namespace embark_assist {
min_river,
max_river,
min_waterfall,
flatness,
flat,
clay,
sand,
flux,
@ -468,6 +468,7 @@ namespace embark_assist {
break;
case fields::blood_rain:
case fields::flat:
{
embark_assist::defs::yes_no_ranges k = embark_assist::defs::yes_no_ranges::NA;
while (true) {
@ -495,38 +496,6 @@ namespace embark_assist {
break;
case fields::flatness:
{
embark_assist::defs::flatness_ranges k = embark_assist::defs::flatness_ranges::NA;
while (true) {
switch (k) {
case embark_assist::defs::flatness_ranges::NA:
element->list.push_back({ "N/A", static_cast<int8_t>(k) });
break;
case embark_assist::defs::flatness_ranges::Flat_Verified:
element->list.push_back({ "Flat Verified", static_cast<int8_t>(k) });
break;
case embark_assist::defs::flatness_ranges::Mostly_Flat:
element->list.push_back({ "Mostly Flat", static_cast<int8_t>(k) });
break;
case embark_assist::defs::flatness_ranges::Uneven:
element->list.push_back({ "Uneven", static_cast<int8_t>(k) });
break;
}
if (k == embark_assist::defs::flatness_ranges::Uneven) {
break;
}
k = static_cast <embark_assist::defs::flatness_ranges>(static_cast<int8_t>(k) + 1);
}
}
break;
case fields::soil_min_everywhere:
{
embark_assist::defs::all_present_ranges k = embark_assist::defs::all_present_ranges::All;
@ -1004,8 +973,8 @@ namespace embark_assist {
state->finder_list.push_back({ "Min Waterfall Drop", static_cast<int8_t>(i) });
break;
case fields::flatness:
state->finder_list.push_back({ "Flatness", static_cast<int8_t>(i) });
case fields::flat:
state->finder_list.push_back({ "Flat", static_cast<int8_t>(i) });
break;
case fields::soil_min_everywhere:
@ -1233,9 +1202,9 @@ namespace embark_assist {
finder.min_waterfall = state->ui[static_cast<uint8_t>(i)]->current_value;
break;
case fields::flatness:
finder.flatness =
static_cast<embark_assist::defs::flatness_ranges>(state->ui[static_cast<uint8_t>(i)]->current_value);
case fields::flat:
finder.flat =
static_cast<embark_assist::defs::yes_no_ranges>(state->ui[static_cast<uint8_t>(i)]->current_value);
break;
case fields::soil_min_everywhere:

@ -18,7 +18,8 @@ namespace embark_assist{
Intro,
General,
Finder,
Caveats
Caveats_1,
Caveats_2
};
class ViewscreenHelpUi : public dfhack_viewscreen
@ -56,10 +57,14 @@ namespace embark_assist{
break;
case pages::Finder:
current_page = pages::Caveats;
current_page = pages::Caveats_1;
break;
case pages::Caveats:
case pages::Caveats_1:
current_page = pages::Caveats_2;
break;
case pages::Caveats_2:
current_page = pages::Intro;
break;
}
@ -67,7 +72,7 @@ namespace embark_assist{
else if (input->count(df::interface_key::SEC_CHANGETAB)) {
switch (current_page) {
case pages::Intro:
current_page = pages::Caveats;
current_page = pages::Caveats_2;
break;
case pages::General:
@ -78,8 +83,12 @@ namespace embark_assist{
current_page = pages::General;
break;
case pages::Caveats:
current_page = pages::Intro;
case pages::Caveats_1:
current_page = pages::Finder;
break;
case pages::Caveats_2:
current_page = pages::Caveats_1;
break;
}
}
@ -135,6 +144,8 @@ namespace embark_assist{
help_text.push_back(" embarking.");
help_text.push_back("Below this a Matching World Tiles count is displayed. It shows the number");
help_text.push_back("of World Tiles that have at least one embark matching the Find criteria.");
help_text.push_back("Note that World Tiles are the ones shown on the 'Region' map: the 'World'");
help_text.push_back("typically merges several World Tiles into each of its tiles.");
break;
@ -156,23 +167,25 @@ namespace embark_assist{
help_text.push_back("DF's display of resources in the region DF currently displays. Secondly, the");
help_text.push_back("DF display doesn't take elevation based soil erosion or the magma sea depth");
help_text.push_back("into consideration, so it can display resources that actually are cut away.");
help_text.push_back("(It can be noted that the DFHack Sand indicator does take these elements into");
help_text.push_back("account).");
help_text.push_back("Thirdly, it takes 'intrusions', i.e. small sections of neighboring tiles'");
help_text.push_back("biomes into consideration for many fields.");
help_text.push_back("(It can be noted that the DFHack Sand indicator does take the first two");
help_text.push_back("elements into account).");
help_text.push_back("The info the Embark Assistant displays is:");
help_text.push_back("Sand, if present");
help_text.push_back("Clay, if present");
help_text.push_back("Min and Max soil depth in the embark rectangle.");
help_text.push_back("Flat indicator if all the tiles in the embark have the same elevation.");
help_text.push_back(" 'Mostly Flat' = Condition above met. 'Flat Verified' = All surrounding tiles");
help_text.push_back(" also satisfy condition so no biome spill over may result in an");
help_text.push_back(" elevation difference.");
help_text.push_back("Aquifer indicator, color coded as blue if all tiles have an aquifer and light");
help_text.push_back("blue if some, but not all, tiles have one.");
help_text.push_back("Waterfall, if the embark has river elevation differences.");
help_text.push_back("Flux, if present");
help_text.push_back("A list of all metals present in the embark.");
help_text.push_back("Incompl. Survey if all intrusions couldn't be examined because that requires");
help_text.push_back("info from neighboring world tiles that haven't been surveyed.");
help_text.push_back("Sand, if present, including through intrusions.");
help_text.push_back("Clay, if present, including thorugh intrusions.");
help_text.push_back("Min and Max soil depth in the embark rectangle, including intrusions.");
help_text.push_back("Flat indicator if all the tiles and intrusions have the same elevation.");
help_text.push_back("Aquifer indicator: Part(ial) or Full, when present, including intrusions.");
help_text.push_back("Waterfall and largest Z level drop if the river has elevation differences");
help_text.push_back("Evil weather, when present: BR = Blood Rain, TS = Temporary Syndrome");
help_text.push_back("PS = Permanent Syndrome, Re = Reanimating, and Th = Thralling. Intrusions.");
help_text.push_back("Flux, if present. NOT allowing for small intrusion bits.");
help_text.push_back("A list of all metals present in the embark. Not intrusions.");
help_text.push_back("A list of all economic minerals present in the embark. Both clays and flux");
help_text.push_back("stones are economic, so they show up here as well.");
help_text.push_back("stones are economic, so they show up here as well. Not intrusions.");
help_text.push_back("In addition to the above, the Find functionality can also produce blinking");
help_text.push_back("overlays over the Local, Region, and World maps to indicate where");
help_text.push_back("matching embarks are found. The Local display marks the top left corner of");
@ -208,15 +221,17 @@ namespace embark_assist{
help_text.push_back("as long as at least one tile doesn't have one, but it doesn't have to have");
help_text.push_back("any at all.");
help_text.push_back("Min/Max rivers should be self explanatory. The Yes and No values of");
help_text.push_back("Waterfall, Flat, etc. means one has to be Present and Absent respectivey.");
help_text.push_back("Clay, etc. means one has to be Present and Absent respectivey.");
help_text.push_back("Min Waterfall Drop finds embarks with drops of at least that number");
help_text.push_back("of Z levels, but Absent = no waterfall at all.");
help_text.push_back("Min/Max soil uses the same terminology as DF for 1-4. The Min Soil");
help_text.push_back("Everywhere toggles the Min Soil parameter between acting as All and");
help_text.push_back("and Present.");
help_text.push_back("Present.");
help_text.push_back("Freezing allows you to select embarks to select/avoid various freezing");
help_text.push_back("conditions. Note that the minimum temperature is held for only 10 ticks");
help_text.push_back("in many embarks.");
help_text.push_back("Syndrome Rain allows you to search for Permanent and Temporary syndromes,");
help_text.push_back("where Permanent allows for Temporary ones as well, but not the reverse, as");
help_text.push_back("where Permanent allows for Temporary ones as well, but not the reverse, and");
help_text.push_back("Not Permanent matches everything except Permanent syndromes.");
help_text.push_back("Reanimation packages thralling and reanimation into a single search");
help_text.push_back("criterion. Not Tralling means nothing and just reanimation is matched.");
@ -227,16 +242,28 @@ namespace embark_assist{
help_text.push_back("list. Note that Find is a fairly time consuming task (as it is in vanilla).");
break;
case pages::Caveats:
Screen::drawBorder(" Embark Assistant Help/Info Caveats Page ");
case pages::Caveats_1:
Screen::drawBorder(" Embark Assistant Help/Info Caveats 1 Page ");
help_text.push_back("Find searching first does a sanity check (e.g. max < min) and then a rough");
help_text.push_back("The plugin surveys world tiles through two actions: using the 'f'ind");
help_text.push_back("function and through manual movement of the embark rectangle between world");
help_text.push_back("tiles. In both cases the whole world tile is surveyed, regardless of which");
help_text.push_back("tiles the embark rectangle covers.");
help_text.push_back("'Find' searching first does a sanity check (e.g. max < min) and then a rough");
help_text.push_back("world tile match to find tiles that may have matching embarks. This results");
help_text.push_back("in an overlay of inverted yellow X on top of the middle world map. Then");
help_text.push_back("in overlays of inverted yellow X on top of the Region and World maps. Then");
help_text.push_back("those tiles are scanned in detail, one feature shell (16*16 world tile");
help_text.push_back("block) at a time, and the results are displayed as green inverted X on");
help_text.push_back("the same map (replacing or erasing the yellow ones). region map overlay");
help_text.push_back("the same map (replacing or erasing the yellow ones). Local map overlay");
help_text.push_back("data is generated as well.");
help_text.push_back("Since 'intrusion' processing requires that the neighboring tiles that may");
help_text.push_back("provide them are surveyed before the current tile and tiles have to be");
help_text.push_back("surveyed in some order, the find function can not perform a complete");
help_text.push_back("survey of prospective embarks that border world tiles yet to be surveyed");
help_text.push_back("so the very first 'find' will fail to mark such embarks that actually do");
help_text.push_back("match, while the second and following 'find' operations will locate them");
help_text.push_back("because critical information from the first scan is kept for subsequent");
help_text.push_back("ones.");
help_text.push_back("");
help_text.push_back("Caveats & technical stuff:");
help_text.push_back("- The Find searching uses simulated cursor movement input to DF to get it");
@ -245,8 +272,8 @@ namespace embark_assist{
help_text.push_back("- The search strategy causes detailed region data to update surveyed");
help_text.push_back(" world info, and this can cause a subsequent search to generate a smaller");
help_text.push_back(" set of preliminary matches (yellow tiles) than a previous search.");
help_text.push_back(" However, this is a bug only if it causes the search to fail to find");
help_text.push_back(" actual existing matches.");
help_text.push_back(" Note that the first search can miss a fair number of matches for");
help_text.push_back(" technical reasons discussed above and below.");
help_text.push_back("- The site info is deduced by the author, so there may be errors and");
help_text.push_back(" there are probably site types that end up not being identified.");
help_text.push_back("- Aquifer indications are based on the author's belief that they occur");
@ -258,7 +285,7 @@ namespace embark_assist{
help_text.push_back("- Thralling is determined by whether material interactions causes");
help_text.push_back(" blinking, which the author believes is one of 4 thralling changes.");
help_text.push_back("- The geo information is gathered by code which is essentially a");
help_text.push_back(" copy of parts of prospector's code adapted for this plugin.");
help_text.push_back(" copy of parts of Prospector's code adapted for this plugin.");
help_text.push_back("- Clay determination is made by finding the reaction MAKE_CLAY_BRICKS.");
help_text.push_back("- Flux determination is made by finding the reaction PIG_IRON_MAKING.");
help_text.push_back("- Coal is detected by finding COAL producing reactions on minerals.");
@ -266,13 +293,39 @@ namespace embark_assist{
help_text.push_back(" reaching caverns that have been removed at world gen to fail to be");
help_text.push_back(" generated at all. It's likely this bug also affects magma pools.");
help_text.push_back(" This plugin does not address this but scripts can correct it.");
help_text.push_back("- 'Flat Verified' vs 'Mostly Flat': There's no known way to detect");
help_text.push_back(" if an adjacent Mid Level Tile's biome 'spills over' into a tile.");
help_text.push_back(" 'Flat Verified' means neighbors have the same elevation so spill overs");
help_text.push_back(" don't matter. 'Mostly Flat' means spill overs may ruin a completely");
help_text.push_back(" level embark, but might not. Can be used to 'rescue' a world where");
help_text.push_back(" a 'Flat Verified' match failed.");
help_text.push_back("Version 0.9 2019-06-23");
break;
case pages::Caveats_2:
Screen::drawBorder(" Embark Assistant Help/Info Caveats 2 Page ");
help_text.push_back("- The plugin detects 'incursions' of neighboring tiles into embarks, but");
help_text.push_back(" this functionality is incomplete when the incursion comes from a");
help_text.push_back(" neighboring tile that hasn't been surveyed yet. The embark info displays");
help_text.push_back(" what it can, while indicating if it is incomplete, while the first 'f'ind");
help_text.push_back(" will automatically fail to match any embarks that can not be analyzed");
help_text.push_back(" fully. Such failures only appear on embarks that touch an edge of the");
help_text.push_back(" world tile, and a second (and all subsequent) searches will be complete.");
help_text.push_back(" Since searches can take considerable time, it's left to the user to decide");
help_text.push_back(" whether to make a second, completing, search.");
help_text.push_back("- Incursions are taken into consideration when looking for Aquifers,");
help_text.push_back(" Clay, Sand, Min Soil when Everywhere, Biomes, Regions, Evil Weather,");
help_text.push_back(" Savagery, Evilness, Freezing and Flatness, but ignored for metals/");
help_text.push_back(" economics/minerals (including Flux and Coal) as any volumes are typically");
help_text.push_back(" too small to be of interest. Rivers, Waterfalls, Spires, and Magma Pools");
help_text.push_back(" are not incursion related features.");
help_text.push_back("- There are special rules for handing of intrusions from Lakes and Oceans,");
help_text.push_back(" as well as Mountains into everything that isn't a Lake or Ocean, and the");
help_text.push_back(" rules state that these intrusions should be reversed (i.e. 'normal' biomes");
help_text.push_back(" should push into Lakes, Oceans, and Mountains, even when the indicators");
help_text.push_back(" say otherwise). This rule is clear for edges, but not for corners, as it");
help_text.push_back(" does not specify which of the potentially multiple 'superior' biomes");
help_text.push_back(" should be used. The plugin uses the arbitrarily selected rule that the");
help_text.push_back(" touching corner to the NW should be selected if eligible, then the one to");
help_text.push_back(" the N, followed by the one to the W, and lastly the one acting as the");
help_text.push_back(" reference. This means there's a risk embarks with such 'trouble' corners");
help_text.push_back(" may get affected corner(s) evaluated incorrectly.");
help_text.push_back("Version 0.9 2019-07-12");
break;
}
@ -320,7 +373,10 @@ namespace embark_assist{
embark_assist::screen::paintString(pen_lr, 3, 9, DFHack::Screen::getKeyDisplay(df::interface_key::CUSTOM_L).c_str());
break;
case pages::Caveats:
case pages::Caveats_1:
break;
case pages::Caveats_2:
break;
}
dfhack_viewscreen::render();

File diff suppressed because it is too large Load Diff

@ -331,6 +331,10 @@ void embark_assist::overlay::match_progress(uint16_t count, embark_assist::defs:
void embark_assist::overlay::set_embark(embark_assist::defs::site_infos *site_info) {
state->embark_info.clear();
if (!site_info->incursions_processed) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTRED), "Incomp. Survey" });
}
if (site_info->sand) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_YELLOW), "Sand" });
}
@ -345,12 +349,8 @@ void embark_assist::overlay::set_embark(embark_assist::defs::site_infos *site_in
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BROWN), "Soil " + std::to_string(site_info->min_soil) + " - " + std::to_string(site_info->max_soil) });
if (site_info->flatness == embark_assist::defs::flatnesses::Flat_Verified) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BROWN), "Flat Verified" });
}
else if (site_info->flatness == embark_assist::defs::flatnesses::Mostly_Flat)
{
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BROWN), "Mostly Flat" });
if (site_info->flat) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BROWN), "Flat" });
}
if (site_info->aquifer) {
@ -367,6 +367,55 @@ void embark_assist::overlay::set_embark(embark_assist::defs::site_infos *site_in
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTBLUE), "Waterfall " + std::to_string(site_info->max_waterfall) });
}
if (site_info->blood_rain ||
site_info->permanent_syndrome_rain ||
site_info->temporary_syndrome_rain ||
site_info->reanimating ||
site_info->thralling) {
std::string blood_rain;
std::string permanent_syndrome_rain;
std::string temporary_syndrome_rain;
std::string reanimating;
std::string thralling;
if (site_info->blood_rain) {
blood_rain = "BR ";
}
else {
blood_rain = " ";
}
if (site_info->permanent_syndrome_rain) {
permanent_syndrome_rain = "PS ";
}
else {
permanent_syndrome_rain = " ";
}
if (site_info->temporary_syndrome_rain) {
temporary_syndrome_rain = "TS ";
}
else {
permanent_syndrome_rain = " ";
}
if (site_info->reanimating) {
reanimating = "Re ";
}
else {
reanimating = " ";
}
if (site_info->thralling) {
thralling = "Th";
}
else {
thralling = " ";
}
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTRED), blood_rain + temporary_syndrome_rain + permanent_syndrome_rain + reanimating + thralling });
}
if (site_info->flux) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_WHITE), "Flux" });
}

File diff suppressed because it is too large Load Diff

@ -27,9 +27,52 @@ namespace embark_assist {
df::coord2d apply_offset(uint16_t x, uint16_t y, int8_t offset);
df::world_region_type region_type_of(embark_assist::defs::world_tile_data *survey_results,
int16_t x,
int16_t y,
int8_t i,
int8_t k);
// Returns the direction from which data should be read using DF's
// 0 - 8 range direction indication.
// "corner_location" uses the 0 - 8 notation to indicate the reader's
// relation to the data read. Only some values are legal, as the set of
// relations is limited by how the corners are defined.
// x, y, i, k are the world tile/mid level tile coordinates of the
// tile the results should be applied to.
// Deals with references outside of the world map by returning "yield"
// results, but requires all world tiles affected by the corner to have
// been surveyed.
//
uint8_t translate_corner(embark_assist::defs::world_tile_data *survey_results,
uint8_t corner_location,
uint16_t x,
uint16_t y,
uint8_t i,
uint8_t k);
// Same logic and restrictions as for translate_corner.
//
uint8_t translate_ns_edge(embark_assist::defs::world_tile_data *survey_results,
bool own_edge,
uint16_t x,
uint16_t y,
uint8_t i,
uint8_t k);
// Same logic and restrictions as for translate_corner.
//
uint8_t translate_ew_edge(embark_assist::defs::world_tile_data *survey_results,
bool own_edge,
uint16_t x,
uint16_t y,
uint8_t i,
uint8_t k);
void survey_region_sites(embark_assist::defs::site_lists *site_list);
void survey_embark(embark_assist::defs::mid_level_tiles *mlt,
embark_assist::defs::world_tile_data *survey_results,
embark_assist::defs::site_infos *site_info,
bool use_cache);