Added 'fileresult' optional parameter, improved world traversal

develop
PatrikLundell 2019-09-23 13:13:04 +02:00
parent 7a5902418e
commit 5eceab2794
9 changed files with 118 additions and 51 deletions

@ -85,6 +85,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- 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
- added optional parameter "fileresult" for crude external harness automated match support
- improved focus movement logic to go to only required world tiles, increasing speed of subsequent searches considerably
- `exportlegends`: added rivers to custom XML export
- `exterminate`: added support for a special ``enemy`` caste
- `modtools/create-unit`:

@ -11,6 +11,8 @@ using std::ostringstream;
using std::string;
using std::vector;
#define fileresult_file_name "./data/init/embark_assistant_fileresult.txt"
namespace embark_assist {
namespace defs {
// Survey types
@ -315,6 +317,8 @@ namespace embark_assist {
bool y_down;
bool inhibit_x_turn;
bool inhibit_y_turn;
uint16_t target_location_x;
uint16_t target_location_y;
uint16_t count;
finders finder;
};

@ -253,6 +253,13 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
command_result embark_assistant(color_ostream &out, std::vector <std::string> & parameters)
{
bool fileresult = false;
if (parameters.size() == 1 &&
parameters[0] == "fileresult") {
remove(fileresult_file_name);
fileresult = true;
} else
if (!parameters.empty())
return CR_WRONG_USAGE;
@ -277,8 +284,11 @@ 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;
for (uint16_t i = world->raws.inorganics.size() - 1; i >= 0 ; i--) {
if (!world->raws.inorganics[i]->flags.is_set(df::inorganic_flags::GENERATED)) {
embark_assist::main::state->max_inorganic = i;
break;
}
}
embark_assist::main::state->max_inorganic++; // To allow it to be used as size() replacement
@ -348,5 +358,9 @@ command_result embark_assistant(color_ostream &out, std::vector <std::string> &
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);
if (fileresult) {
embark_assist::overlay::fileresult();
}
return CR_OK;
}

@ -1557,11 +1557,18 @@ namespace embark_assist {
// Exported operations
//===============================================================================
void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) {
void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic, bool fileresult) {
if (!embark_assist::finder_ui::state) { // First call. Have to do the setup
embark_assist::finder_ui::ui_setup(find_callback, max_inorganic);
}
Screen::show(dts::make_unique<ViewscreenFindUi>(), plugin_self);
if (!fileresult) {
Screen::show(dts::make_unique<ViewscreenFindUi>(), plugin_self);
}
else
{
load_profile();
find();
}
}
//===============================================================================

@ -10,7 +10,7 @@ using namespace DFHack;
namespace embark_assist {
namespace finder_ui {
void init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic);
void init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic, bool fileresult);
void activate();
void shutdown();
}

@ -167,25 +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("Thirdly, it takes 'intrusions', i.e. small sections of neighboring tiles'");
help_text.push_back("Thirdly, it takes 'incursions', 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("Incompl. Survey if all intrusions couldn't be examined because that requires");
help_text.push_back("Incompl. Survey if all incursions 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("Sand, if present, including through incursions.");
help_text.push_back("Clay, if present, including thorugh incursions.");
help_text.push_back("Min and Max soil depth in the embark rectangle, including incursions.");
help_text.push_back("Flat indicator if all the tiles and incursions have the same elevation.");
help_text.push_back("Aquifer indicator: Part(ial) or Full, when present, including incursions.");
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("PS = Permanent Syndrome, Re = Reanimating, and Th = Thralling. Incursions.");
help_text.push_back("Flux, if present. NOT allowing for small incursion bits.");
help_text.push_back("A list of all metals present in the embark. Not incursions.");
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. Not intrusions.");
help_text.push_back("stones are economic, so they show up here as well. Not incursions.");
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");
@ -256,7 +256,7 @@ namespace embark_assist{
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). 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("Since 'incursion' 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");
@ -266,6 +266,19 @@ namespace embark_assist{
help_text.push_back("ones.");
help_text.push_back("");
help_text.push_back("Caveats & technical stuff:");
help_text.push_back("- The plugin does in fact allow for a single, optional case sensitive");
help_text.push_back(" parameter when invoked: 'fileresult'. When this parameter is provided");
help_text.push_back(" The plugin will read the search profile stored to file and immediately");
help_text.push_back(" initiate a search for matches. This search is performed twice to ensure");
help_text.push_back(" incursions are handled correctly, and then the number of matching world");
help_text.push_back(" is written to the file <DF>/data/init/embark_assistant_fileresult.txt.");
help_text.push_back(" It can be noted that this file is deleted before the first search is");
help_text.push_back(" started. The purpose of this mode is to allow external harnesses to");
help_text.push_back(" generate worlds, search them for matches, and use the file results to");
help_text.push_back(" to determine which worlds to keep. It can be noted that after the search");
help_text.push_back(" the plugin continues to work essentially as usual, including external");
help_text.push_back(" to terminate, and that the author plugin can provide no help when it comes");
help_text.push_back(" to setting up any kind of harness using the plugin functionality.");
help_text.push_back("- The Find searching uses simulated cursor movement input to DF to get it");
help_text.push_back(" to load feature shells and detailed region data, and this costs the");
help_text.push_back(" least when done one feature shell at a time.");
@ -274,14 +287,17 @@ namespace embark_assist{
help_text.push_back(" set of preliminary matches (yellow tiles) than a previous search.");
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.");
break;
case pages::Caveats_2:
Screen::drawBorder(" Embark Assistant Help/Info Caveats 2 Page ");
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");
help_text.push_back(" whenever an aquifer supporting layer is present at a depth of 3 or");
help_text.push_back(" more.");
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 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");
@ -293,12 +309,6 @@ 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.");
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");
@ -314,9 +324,9 @@ namespace embark_assist{
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("- There are special rules for handing of incursions 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(" rules state that these incursions 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");
@ -325,7 +335,7 @@ namespace embark_assist{
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");
help_text.push_back("Version 0.10 2019-09-21");
break;
}

@ -176,8 +176,8 @@ namespace embark_assist {
result->sand_found = true;
}
// Flux. N/A for intrusions.
// Coal. N/A for intrusions
// Flux. N/A for incursions.
// Coal. N/A for incursions
// Min Soil
if (finder->soil_min != embark_assist::defs::soil_ranges::NA &&
@ -270,8 +270,8 @@ namespace embark_assist {
result->thralling_found = true;
}
// Spires. N/A for intrusions
// Magma. N/A for intrusions
// Spires. N/A for incursions
// Magma. N/A for incursions
// Biomes
result->biomes[survey_results->at(x).at(y).biome[mlt->biome_offset]] = true;
@ -279,8 +279,8 @@ namespace embark_assist {
// Region Type
result->region_types[world_data->regions[survey_results->at(x).at(y).biome_index[mlt->biome_offset]]->type] = true;
// Metals. N/A for intrusions
// Economics. N/A for intrusions
// Metals. N/A for incursions
// Economics. N/A for incursions
}
//=======================================================================================
@ -2299,6 +2299,8 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter
while (screen->location.region_pos.x != 0 || screen->location.region_pos.y != 0) {
screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST);
}
iterator->target_location_x = 0;
iterator->target_location_y = 0;
iterator->active = true;
iterator->i = 0;
iterator->k = 0;
@ -2327,21 +2329,24 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter
for (uint16_t l = 0; l <= x_end; l++) {
for (uint16_t m = 0; m <= y_end; m++) {
// This is where the payload goes
if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).preliminary_match) {
if (!survey_results->at(iterator->target_location_x).at(iterator->target_location_y).surveyed ||
match_results->at(iterator->target_location_x).at(iterator->target_location_y).preliminary_match) {
move_cursor(iterator->target_location_x, iterator->target_location_y);
match_world_tile(geo_summary,
survey_results,
&iterator->finder,
match_results,
screen->location.region_pos.x,
screen->location.region_pos.y);
if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).contains_match) {
iterator->target_location_x,
iterator->target_location_y);
if (match_results->at(iterator->target_location_x).at(iterator->target_location_y).contains_match) {
iterator->count++;
}
}
else {
for (uint16_t n = 0; n < 16; n++) {
for (uint16_t p = 0; p < 16; p++) {
match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match[n][p] = false;
match_results->at(iterator->target_location_x).at(iterator->target_location_y).mlt_match[n][p] = false;
}
}
}
@ -2349,15 +2354,15 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter
if (m != y_end) {
if (iterator->y_down) {
screen->feed_key(df::interface_key::CURSOR_DOWN);
if (iterator->target_location_y < world->worldgen.worldgen_parms.dim_y - 1) iterator->target_location_y++;
}
else {
screen->feed_key(df::interface_key::CURSOR_UP);
if (iterator->target_location_y > 0) iterator->target_location_y--;
}
}
else {
if (screen->location.region_pos.x != 0 &&
screen->location.region_pos.x != world->worldgen.worldgen_parms.dim_x - 1) {
if (iterator->target_location_x != 0 &&
iterator->target_location_x != world->worldgen.worldgen_parms.dim_x - 1) {
turn = true;
}
else {
@ -2370,24 +2375,24 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter
}
else {
if (iterator->y_down) {
screen->feed_key(df::interface_key::CURSOR_DOWN);
if (iterator->target_location_y < world->worldgen.worldgen_parms.dim_y - 1) iterator->target_location_y++;
}
else {
screen->feed_key(df::interface_key::CURSOR_UP);
if (iterator->target_location_y > 0) iterator->target_location_y--;
}
}
}
}
if (iterator->x_right) { // Won't do anything at the edge, so we don't bother filter those cases.
screen->feed_key(df::interface_key::CURSOR_RIGHT);
if (iterator->target_location_x < world->worldgen.worldgen_parms.dim_x - 1) iterator->target_location_x++;
}
else {
screen->feed_key(df::interface_key::CURSOR_LEFT);
if (iterator->target_location_x > 0) iterator->target_location_x--;
}
if (!iterator->x_right &&
screen->location.region_pos.x == 0) {
iterator->target_location_x == 0) {
turn = !turn;
if (turn) {
@ -2395,7 +2400,7 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter
}
}
else if (iterator->x_right &&
screen->location.region_pos.x == world->worldgen.worldgen_parms.dim_x - 1) {
iterator->target_location_x == world->worldgen.worldgen_parms.dim_x - 1) {
turn = !turn;
if (turn) {

@ -54,6 +54,9 @@ namespace embark_assist {
uint16_t match_count = 0;
uint16_t max_inorganic;
bool fileresult = false;
uint8_t fileresult_pass = 0;
};
static states *state = nullptr;
@ -113,7 +116,7 @@ namespace embark_assist {
}
else if (input->count(df::interface_key::CUSTOM_F)) {
if (!state->match_active && !state->matching) {
embark_assist::finder_ui::init(embark_assist::overlay::plugin_self, state->find_callback, state->max_inorganic);
embark_assist::finder_ui::init(embark_assist::overlay::plugin_self, state->find_callback, state->max_inorganic, false);
}
}
else if (input->count(df::interface_key::CUSTOM_I)) {
@ -311,6 +314,7 @@ void embark_assist::overlay::match_progress(uint16_t count, embark_assist::defs:
// color_ostream_proxy out(Core::getInstance().getConsole());
state->matching = !done;
state->match_count = count;
for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) {
for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) {
if (match_results->at(i).at(k).preliminary_match) {
@ -324,6 +328,18 @@ void embark_assist::overlay::match_progress(uint16_t count, embark_assist::defs:
}
}
}
if (done && state->fileresult) {
state->fileresult_pass++;
if (state->fileresult_pass == 1) {
embark_assist::finder_ui::init(embark_assist::overlay::plugin_self, state->find_callback, state->max_inorganic, true);
}
else {
FILE* outfile = fopen(fileresult_file_name, "w");
fprintf(outfile, "%i\n", count);
fclose(outfile);
}
}
}
//====================================================================
@ -463,6 +479,14 @@ void embark_assist::overlay::clear_match_results() {
//====================================================================
void embark_assist::overlay::fileresult() {
// Have to search twice, as the first pass cannot be complete due to mutual dependencies.
state->fileresult = true;
embark_assist::finder_ui::init(embark_assist::overlay::plugin_self, state->find_callback, state->max_inorganic, true);
}
//====================================================================
void embark_assist::overlay::shutdown() {
if (state &&
state->world_match_grid) {

@ -32,6 +32,7 @@ namespace embark_assist {
void set_embark(embark_assist::defs::site_infos *site_info);
void set_mid_level_tile_match(embark_assist::defs::mlt_matches mlt_matches);
void clear_match_results();
void fileresult();
void shutdown();
}
}