diff --git a/docs/changelog.txt b/docs/changelog.txt index 47dcaa58b..c1d7bae72 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -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`: diff --git a/plugins/embark-assistant/defs.h b/plugins/embark-assistant/defs.h index 9d1c8e888..3696c789d 100644 --- a/plugins/embark-assistant/defs.h +++ b/plugins/embark-assistant/defs.h @@ -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; }; diff --git a/plugins/embark-assistant/embark-assistant.cpp b/plugins/embark-assistant/embark-assistant.cpp index 465435a38..68db916cf 100644 --- a/plugins/embark-assistant/embark-assistant.cpp +++ b/plugins/embark-assistant/embark-assistant.cpp @@ -253,6 +253,13 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan command_result embark_assistant(color_ostream &out, std::vector & 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 & // 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 & 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; } diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp index 80c61dc6e..bae87aaa2 100644 --- a/plugins/embark-assistant/finder_ui.cpp +++ b/plugins/embark-assistant/finder_ui.cpp @@ -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(), plugin_self); + if (!fileresult) { + Screen::show(dts::make_unique(), plugin_self); + } + else + { + load_profile(); + find(); + } } //=============================================================================== diff --git a/plugins/embark-assistant/finder_ui.h b/plugins/embark-assistant/finder_ui.h index 70bf4ce42..1011bf251 100644 --- a/plugins/embark-assistant/finder_ui.h +++ b/plugins/embark-assistant/finder_ui.h @@ -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(); } diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp index ef1bc2b39..ebb1deb78 100644 --- a/plugins/embark-assistant/help_ui.cpp +++ b/plugins/embark-assistant/help_ui.cpp @@ -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 /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; } diff --git a/plugins/embark-assistant/matcher.cpp b/plugins/embark-assistant/matcher.cpp index a3975a980..40d2ead91 100644 --- a/plugins/embark-assistant/matcher.cpp +++ b/plugins/embark-assistant/matcher.cpp @@ -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) { diff --git a/plugins/embark-assistant/overlay.cpp b/plugins/embark-assistant/overlay.cpp index a0defd0d5..c689f21ad 100644 --- a/plugins/embark-assistant/overlay.cpp +++ b/plugins/embark-assistant/overlay.cpp @@ -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) { diff --git a/plugins/embark-assistant/overlay.h b/plugins/embark-assistant/overlay.h index d66d6d7fd..f4f7cf3eb 100644 --- a/plugins/embark-assistant/overlay.h +++ b/plugins/embark-assistant/overlay.h @@ -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(); } } \ No newline at end of file