Merge remote-tracking branch 'PatrikLundell/embark-assistant' into develop

Conflicts:
	docs/changelog.txt
develop
lethosor 2019-08-22 21:50:54 -04:00
commit 0b8eba7d23
9 changed files with 2251 additions and 238 deletions

@ -37,7 +37,17 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
================================================================================
# Future
## Fixes
- `embark-assistant`:
- fixed bug causing crash on worlds without generated metals (as well as pruning vectors as originally intended).
- fixed bug causing mineral matching to fail to cut off at the magma sea, reporting presence of things that aren't (like DF does currently).
## Misc Improvements
- `embark-assistant`:
- 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.
- `RemoteFortressReader`:
- added basic framework for controlling and reading the menus in DF, currently only supports the building menu.
- added support for reading item raws.

@ -3,6 +3,7 @@
#include <array>
#include <string>
#include <vector>
#include "df/world_region_type.h"
using namespace std;
using std::array;
@ -55,7 +56,7 @@ namespace embark_assist {
uint16_t coal_count = 0;
uint8_t min_region_soil = 10;
uint8_t max_region_soil = 0;
bool waterfall = false;
uint8_t max_waterfall = 0;
river_sizes river_size;
int16_t biome_index[10]; // Indexed through biome_offset; -1 = null, Index of region, [0] not used
int16_t biome[10]; // Indexed through biome_offset; -1 = null, df::biome_type, [0] not used
@ -82,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 {
@ -107,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;
bool flat;
bool waterfall;
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;
@ -252,7 +269,7 @@ namespace embark_assist {
aquifer_ranges aquifer;
river_ranges min_river;
river_ranges max_river;
yes_no_ranges waterfall;
int8_t min_waterfall; // N/A(-1), Absent, 1-9
yes_no_ranges flat;
present_absent_ranges clay;
present_absent_ranges sand;

@ -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);
@ -224,7 +227,7 @@ command_result embark_assistant(color_ostream &out, std::vector <std::string> &
// Find the end of the normal inorganic definitions.
embark_assist::main::state->max_inorganic = 0;
for (uint16_t i = 0; i < world->raws.inorganics.size(); i++) {
if (world->raws.inorganics[i]->flags.is_set(df::inorganic_flags::GENERATED)) embark_assist::main::state->max_inorganic = i;
if (!world->raws.inorganics[i]->flags.is_set(df::inorganic_flags::GENERATED)) embark_assist::main::state->max_inorganic = i;
}
embark_assist::main::state->max_inorganic++; // To allow it to be used as size() replacement
@ -253,7 +256,7 @@ command_result embark_assistant(color_ostream &out, std::vector <std::string> &
embark_assist::main::state->survey_results[i][k].flux_count = 0;
embark_assist::main::state->survey_results[i][k].min_region_soil = 10;
embark_assist::main::state->survey_results[i][k].max_region_soil = 0;
embark_assist::main::state->survey_results[i][k].waterfall = false;
embark_assist::main::state->survey_results[i][k].max_waterfall = 0;
embark_assist::main::state->survey_results[i][k].river_size = embark_assist::defs::river_sizes::None;
for (uint8_t l = 1; l < 10; l++) {
@ -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;

@ -39,7 +39,7 @@ namespace embark_assist {
aquifer,
min_river,
max_river,
waterfall,
min_waterfall,
flat,
clay,
sand,
@ -246,7 +246,7 @@ namespace embark_assist {
fclose(infile);
// Checking done. No do the work.
// Checking done. Now do the work.
infile = fopen(profile_file_name, "r");
i = first_fields;
@ -452,9 +452,23 @@ namespace embark_assist {
break;
case fields::waterfall:
case fields::flat:
case fields::min_waterfall:
for (int16_t k = -1; k <= 9; k++) {
if (k == -1) {
element->list.push_back({ "N/A", k });
}
else if (k == 0) {
element->list.push_back({ "Absent", k });
}
else {
element->list.push_back({ std::to_string(k), k });
}
}
break;
case fields::blood_rain:
case fields::flat:
{
embark_assist::defs::yes_no_ranges k = embark_assist::defs::yes_no_ranges::NA;
while (true) {
@ -955,8 +969,8 @@ namespace embark_assist {
state->finder_list.push_back({ "Max River", static_cast<int8_t>(i) });
break;
case fields::waterfall:
state->finder_list.push_back({ "Waterfall", static_cast<int8_t>(i) });
case fields::min_waterfall:
state->finder_list.push_back({ "Min Waterfall Drop", static_cast<int8_t>(i) });
break;
case fields::flat:
@ -1184,9 +1198,8 @@ namespace embark_assist {
static_cast<embark_assist::defs::river_ranges>(state->ui[static_cast<uint8_t>(i)]->current_value);
break;
case fields::waterfall:
finder.waterfall =
static_cast<embark_assist::defs::yes_no_ranges>(state->ui[static_cast<uint8_t>(i)]->current_value);
case fields::min_waterfall:
finder.min_waterfall = state->ui[static_cast<uint8_t>(i)]->current_value;
break;
case fields::flat:

@ -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,20 +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("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");
@ -205,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.");
@ -224,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");
@ -242,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");
@ -252,10 +282,10 @@ namespace embark_assist{
help_text.push_back("- The biome determination logic comes from code provided by Ragundo,");
help_text.push_back(" with only marginal changes by the author. References can be found in");
help_text.push_back(" the source file.");
help_text.push_back("- Thralling is determined by weather material interactions causing");
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.");
@ -263,7 +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("Version 0.8 2018-12-04");
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;
}
@ -311,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" });
}
@ -351,16 +355,65 @@ void embark_assist::overlay::set_embark(embark_assist::defs::site_infos *site_in
if (site_info->aquifer) {
if (site_info->aquifer_full) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BLUE), "Aquifer" });
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTBLUE), "Full Aquifer" });
}
else {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTBLUE), "Aquifer" });
state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTBLUE), "Part. Aquifer" });
}
}
if (site_info->waterfall) {
state->embark_info.push_back({ Screen::Pen(' ', COLOR_BLUE), "Waterfall" });
if (site_info->max_waterfall > 0) {
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) {

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);