diff --git a/build/win64/install-debug.bat b/build/win64/install-debug.bat index 34668945c..64b5ae850 100644 --- a/build/win64/install-debug.bat +++ b/build/win64/install-debug.bat @@ -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 .. +cd .. \ No newline at end of file diff --git a/docs/changelog.txt b/docs/changelog.txt index 88b0d59d3..69436490c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -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` diff --git a/plugins/embark-assistant/defs.h b/plugins/embark-assistant/defs.h index da03c1d7e..9d1c8e888 100644 --- a/plugins/embark-assistant/defs.h +++ b/plugins/embark-assistant/defs.h @@ -3,6 +3,7 @@ #include #include #include +#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 metals; std::vector economics; std::vector 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 metals; std::vector economics; std::vector 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; diff --git a/plugins/embark-assistant/embark-assistant.cpp b/plugins/embark-assistant/embark-assistant.cpp index 972da12f9..22dd21298 100644 --- a/plugins/embark-assistant/embark-assistant.cpp +++ b/plugins/embark-assistant/embark-assistant.cpp @@ -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); @@ -272,7 +275,7 @@ command_result embark_assistant(color_ostream &out, std::vector & } embark_assist::main::state->survey_results[i][k].metals.resize(embark_assist::main::state->max_inorganic); embark_assist::main::state->survey_results[i][k].economics.resize(embark_assist::main::state->max_inorganic); - embark_assist::main::state->survey_results[i][k].minerals.resize(embark_assist::main::state->max_inorganic); + embark_assist::main::state->survey_results[i][k].minerals.resize(embark_assist::main::state->max_inorganic); } } @@ -291,7 +294,7 @@ command_result embark_assistant(color_ostream &out, std::vector & 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; diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp index 6e710f3bd..80c61dc6e 100644 --- a/plugins/embark-assistant/finder_ui.cpp +++ b/plugins/embark-assistant/finder_ui.cpp @@ -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(k) }); - break; - - case embark_assist::defs::flatness_ranges::Flat_Verified: - element->list.push_back({ "Flat Verified", static_cast(k) }); - break; - - case embark_assist::defs::flatness_ranges::Mostly_Flat: - element->list.push_back({ "Mostly Flat", static_cast(k) }); - break; - - case embark_assist::defs::flatness_ranges::Uneven: - element->list.push_back({ "Uneven", static_cast(k) }); - break; - } - - if (k == embark_assist::defs::flatness_ranges::Uneven) { - break; - } - - k = static_cast (static_cast(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(i) }); break; - case fields::flatness: - state->finder_list.push_back({ "Flatness", static_cast(i) }); + case fields::flat: + state->finder_list.push_back({ "Flat", static_cast(i) }); break; case fields::soil_min_everywhere: @@ -1233,9 +1202,9 @@ namespace embark_assist { finder.min_waterfall = state->ui[static_cast(i)]->current_value; break; - case fields::flatness: - finder.flatness = - static_cast(state->ui[static_cast(i)]->current_value); + case fields::flat: + finder.flat = + static_cast(state->ui[static_cast(i)]->current_value); break; case fields::soil_min_everywhere: diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp index 3d281b145..ef1bc2b39 100644 --- a/plugins/embark-assistant/help_ui.cpp +++ b/plugins/embark-assistant/help_ui.cpp @@ -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(); diff --git a/plugins/embark-assistant/matcher.cpp b/plugins/embark-assistant/matcher.cpp index 3b483ef18..a3975a980 100644 --- a/plugins/embark-assistant/matcher.cpp +++ b/plugins/embark-assistant/matcher.cpp @@ -12,6 +12,7 @@ #include "df/world_data.h" #include "df/world_raws.h" #include "df/world_region.h" +#include "df/world_region_details.h" #include "df/world_region_type.h" #include "matcher.h" @@ -24,32 +25,22 @@ namespace embark_assist { //======================================================================================= - //======================================================================================= - - bool embark_match(embark_assist::defs::world_tile_data *survey_results, - embark_assist::defs::mid_level_tiles *mlt, - uint16_t x, - uint16_t y, - uint16_t start_x, - uint16_t start_y, - embark_assist::defs::finders *finder) { - -// color_ostream_proxy out(Core::getInstance().getConsole()); - df::world_data *world_data = world->world_data; + struct matcher_info { bool savagery_found[3] = { false, false, false }; bool evilness_found[3] = { false, false, false }; - uint16_t aquifer_count = 0; + bool aquifer_absence_found = false; + bool aquifer_presence_found = false; bool river_found = false; uint8_t max_waterfall = 0; - uint16_t elevation = mlt->at(start_x).at(start_y).elevation; + uint16_t elevation; bool clay_found = false; bool sand_found = false; bool flux_found = false; bool coal_found = false; uint8_t max_soil = 0; bool uneven = false; - int16_t min_temperature = survey_results->at(x).at(y).min_temperature[mlt->at(start_x).at(start_y).biome_offset]; - int16_t max_temperature = survey_results->at(x).at(y).max_temperature[mlt->at(start_x).at(start_y).biome_offset]; + int16_t min_temperature; + int16_t max_temperature; bool blood_rain_found = false; bool permanent_syndrome_rain_found = false; bool temporary_syndrome_rain_found = false; @@ -60,15 +51,449 @@ namespace embark_assist { bool biomes[ENUM_LAST_ITEM(biome_type) + 1]; bool region_types[ENUM_LAST_ITEM(world_region_type) + 1]; uint8_t biome_count; - bool metal_1 = finder->metal_1 == -1; - bool metal_2 = finder->metal_2 == -1; - bool metal_3 = finder->metal_3 == -1; - bool economic_1 = finder->economic_1 == -1; - bool economic_2 = finder->economic_2 == -1; - bool economic_3 = finder->economic_3 == -1; - bool mineral_1 = finder->mineral_1 == -1; - bool mineral_2 = finder->mineral_2 == -1; - bool mineral_3 = finder->mineral_3 == -1; + bool metal_1; + bool metal_2; + bool metal_3; + bool economic_1; + bool economic_2; + bool economic_3; + bool mineral_1; + bool mineral_2; + bool mineral_3; + }; + + //======================================================================================= + + void process_embark_incursion(matcher_info *result, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tile *mlt, // Note this is a single tile, as opposed to most usages of this variable name. + embark_assist::defs::finders *finder, + int16_t elevation, + uint16_t x, + uint16_t y, + bool *failed_match) { + + df::world_data *world_data = world->world_data; + + // Savagery & Evilness + { + result->savagery_found[mlt->savagery_level] = true; + result->evilness_found[mlt->evilness_level] = true; + + embark_assist::defs::evil_savagery_ranges l = embark_assist::defs::evil_savagery_ranges::Low; + while (true) { + if (mlt->savagery_level == static_cast(l)) { + if (finder->savagery[static_cast (l)] == + embark_assist::defs::evil_savagery_values::Absent) { + *failed_match = true; + return; + } + } + else { + if (finder->savagery[static_cast (l)] == + embark_assist::defs::evil_savagery_values::All) { + *failed_match = true; + return; + } + } + + if (mlt->evilness_level == static_cast(l)) { + if (finder->evilness[static_cast (l)] == + embark_assist::defs::evil_savagery_values::Absent) { + *failed_match = true; + return; + } + } + else { + if (finder->evilness[static_cast (l)] == + embark_assist::defs::evil_savagery_values::All) { + *failed_match = true; + return; + } + } + + if (l == embark_assist::defs::evil_savagery_ranges::High) break; + l = static_cast (static_cast(l) + 1); + } + } + + // Aquifer + switch (finder->aquifer) { + case embark_assist::defs::aquifer_ranges::NA: + break; + + case embark_assist::defs::aquifer_ranges::All: + if (!mlt->aquifer) { + *failed_match = true; + return; + } + break; + + case embark_assist::defs::aquifer_ranges::Present: + case embark_assist::defs::aquifer_ranges::Partial: + case embark_assist::defs::aquifer_ranges::Not_All: + if (mlt->aquifer) { + result->aquifer_presence_found = true; + } + else { + result->aquifer_absence_found = true; + } + + break; + + case embark_assist::defs::aquifer_ranges::Absent: + if (mlt->aquifer) { + *failed_match = true; + return; + } + break; + } + + // River & Waterfall. N/A for incursions. + + // Flat + if (finder->flat == embark_assist::defs::yes_no_ranges::Yes && + result->elevation != mlt->elevation) { + *failed_match = true; + return; + } + + // Clay + if (mlt->clay) { + if (finder->clay == embark_assist::defs::present_absent_ranges::Absent) { + *failed_match = true; + return; + } + result->clay_found = true; + } + + // Sand + if (mlt->sand) { + if (finder->sand == embark_assist::defs::present_absent_ranges::Absent) { + *failed_match = true; + return; + } + result->sand_found = true; + } + + // Flux. N/A for intrusions. + // Coal. N/A for intrusions + + // Min Soil + if (finder->soil_min != embark_assist::defs::soil_ranges::NA && + mlt->soil_depth < static_cast(finder->soil_min) && + finder->soil_min_everywhere == embark_assist::defs::all_present_ranges::All) { + *failed_match = true; + return; + } + + if (result->max_soil < mlt->soil_depth) { + result->max_soil = mlt->soil_depth; + } + + // Max Soil + if (finder->soil_max != embark_assist::defs::soil_ranges::NA && + mlt->soil_depth > static_cast(finder->soil_max)) { + *failed_match = true; + return; + } + + // Freezing + if (result->min_temperature > survey_results->at(x).at(y).min_temperature[mlt->biome_offset]) { + result->min_temperature = survey_results->at(x).at(y).min_temperature[mlt->biome_offset]; + } + + if (result->max_temperature < survey_results->at(x).at(y).max_temperature[mlt->biome_offset]) { + result->max_temperature = survey_results->at(x).at(y).max_temperature[mlt->biome_offset]; + } + + if (result->min_temperature <= 0 && + finder->freezing == embark_assist::defs::freezing_ranges::Never) { + *failed_match = true; + return; + } + + if (result->max_temperature > 0 && + finder->freezing == embark_assist::defs::freezing_ranges::Permanent) { + *failed_match = true; + return; + } + + // Blood Rain + if (survey_results->at(x).at(y).blood_rain[mlt->biome_offset]) { + if (finder->blood_rain == embark_assist::defs::yes_no_ranges::No) { + *failed_match = true; + return; + } + result->blood_rain_found = true; + } + + // Syndrome Rain, Permanent + if (survey_results->at(x).at(y).permanent_syndrome_rain[mlt->biome_offset]) { + if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Temporary || + finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Not_Permanent || + finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::None) { + *failed_match = true; + return; + } + result->permanent_syndrome_rain_found = true; + } + + // Syndrome Rain, Temporary + if (survey_results->at(x).at(y).temporary_syndrome_rain[mlt->biome_offset]) { + if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Permanent || + finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::None) { + *failed_match = true; + return; + } + result->temporary_syndrome_rain_found = true; + } + + // Reanmation + if (survey_results->at(x).at(y).reanimating[mlt->biome_offset]) { + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Thralling || + finder->reanimation == embark_assist::defs::reanimation_ranges::None) { + *failed_match = true; + return; + } + result->reanimation_found = true; + } + + // Thralling + if (survey_results->at(x).at(y).thralling[mlt->biome_offset]) { + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Reanimation || + finder->reanimation == embark_assist::defs::reanimation_ranges::Not_Thralling || + finder->reanimation == embark_assist::defs::reanimation_ranges::None) { + *failed_match = true; + return; + } + result->thralling_found = true; + } + + // Spires. N/A for intrusions + // Magma. N/A for intrusions + // Biomes + + result->biomes[survey_results->at(x).at(y).biome[mlt->biome_offset]] = true; + + // 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 + } + + //======================================================================================= + + + void process_embark_incursion_mid_level_tile(uint8_t from_direction, + matcher_info *result, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt, + embark_assist::defs::finders *finder, + uint16_t x, + uint16_t y, + uint8_t i, + uint8_t k, + bool *failed_match) { + int8_t fetch_i = i; + int8_t fetch_k = k; + int16_t fetch_x = x; + int16_t fetch_y = y; + df::world_data *world_data = world->world_data; + + // Logic can be implemented with modulo and division, but that's harder to read. + switch (from_direction) { + case 0: + fetch_i = i - 1; + fetch_k = k - 1; + break; + + case 1: + fetch_k = k - 1; + break; + + case 2: + fetch_i = i + 1; + fetch_k = k - 1; + break; + + case 3: + fetch_i = i - 1; + break; + + case 4: + return; // Own tile provides the data, so there's no incursion. + break; + + case 5: + fetch_i = i + 1; + break; + + case 6: + fetch_i = i - 1; + fetch_k = k + 1; + break; + + case 7: + fetch_k = k + 1; + break; + + case 8: + fetch_i = i + 1; + fetch_k = k + 1; + } + + if (fetch_i < 0) { + fetch_x = x - 1; + } + else if (fetch_i > 15) { + fetch_x = x + 1; + } + + if (fetch_k < 0) { + fetch_y = y - 1; + } + else if (fetch_k > 15) { + fetch_y = y + 1; + } + + if (fetch_x < 0 || + fetch_x == world_data->world_width || + fetch_y < 0 || + fetch_y == world_data->world_height) { + return; // We're at the world edge, so no incursions from the outside. + } + + if (!&survey_results->at(fetch_x).at(fetch_y).surveyed) { + *failed_match = true; + return; + } + + if (fetch_k < 0) { + if (fetch_i < 0) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[15], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else if (fetch_i > 15) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[0], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[i], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + } + else if (fetch_k > 15) { + if (fetch_i < 0) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[15], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else if (fetch_i > 15) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[0], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[i], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + } + else { + if (fetch_i < 0) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).east_column[k], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else if (fetch_i > 15) { + process_embark_incursion(result, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).west_column[k], + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + else { + process_embark_incursion(result, + survey_results, + &mlt->at(fetch_i).at(fetch_k), + finder, + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y, + failed_match); + } + } + } + + //======================================================================================= + + bool embark_match(embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt, + uint16_t x, + uint16_t y, + uint16_t start_x, + uint16_t start_y, + embark_assist::defs::finders *finder) { + +// color_ostream_proxy out(Core::getInstance().getConsole()); + df::world_data *world_data = world->world_data; + matcher_info result; + result.elevation = mlt->at(start_x).at(start_y).elevation; + result.min_temperature = survey_results->at(x).at(y).min_temperature[mlt->at(start_x).at(start_y).biome_offset]; + result.max_temperature = survey_results->at(x).at(y).max_temperature[mlt->at(start_x).at(start_y).biome_offset]; + result.metal_1 = finder->metal_1 == -1; + result.metal_2 = finder->metal_2 == -1; + result.metal_3 = finder->metal_3 == -1; + result.economic_1 = finder->economic_1 == -1; + result.economic_2 = finder->economic_2 == -1; + result.economic_3 = finder->economic_3 == -1; + result.mineral_1 = finder->mineral_1 == -1; + result.mineral_2 = finder->mineral_2 == -1; + result.mineral_3 = finder->mineral_3 == -1; + bool failed_match = false; const uint16_t embark_size = finder->x_dim * finder->y_dim; @@ -77,24 +502,18 @@ namespace embark_assist { finder->biome_1 != -1 || finder->biome_2 != -1 || finder->biome_3 != -1) { - for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) biomes[i] = false; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) result.biomes[i] = false; } - for (uint8_t i = 0; i <= ENUM_LAST_ITEM(world_region_type); i++) region_types[i] = false; - - if (finder->flatness == embark_assist::defs::flatness_ranges::Flat_Verified && - (start_x == 0 || - start_x + finder->x_dim == 16 || - start_y == 0 || - start_y + finder->y_dim == 16)) return false; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(world_region_type); i++) result.region_types[i] = false; for (uint16_t i = start_x; i < start_x + finder->x_dim; i++) { for (uint16_t k = start_y; k < start_y + finder->y_dim; k++) { // Savagery & Evilness { - savagery_found[mlt->at(i).at(k).savagery_level] = true; - evilness_found[mlt->at(i).at(k).evilness_level] = true; + result.savagery_found[mlt->at(i).at(k).savagery_level] = true; + result.evilness_found[mlt->at(i).at(k).evilness_level] = true; embark_assist::defs::evil_savagery_ranges l = embark_assist::defs::evil_savagery_ranges::Low; while (true) { @@ -128,17 +547,23 @@ namespace embark_assist { case embark_assist::defs::aquifer_ranges::All: if (!mlt->at(i).at(k).aquifer) return false; - aquifer_count++; + result.aquifer_presence_found = true; break; case embark_assist::defs::aquifer_ranges::Present: case embark_assist::defs::aquifer_ranges::Partial: case embark_assist::defs::aquifer_ranges::Not_All: - if (mlt->at(i).at(k).aquifer) aquifer_count++; + if (mlt->at(i).at(k).aquifer) { + result.aquifer_presence_found = true; + } + else { + result.aquifer_absence_found = true; + } break; case embark_assist::defs::aquifer_ranges::Absent: if (mlt->at(i).at(k).aquifer) return false; + result.aquifer_presence_found = true; break; } @@ -150,52 +575,51 @@ namespace embark_assist { if (i < start_x + finder->x_dim - 2 && mlt->at(i + 1).at(k).river_present && - abs(mlt->at(i).at(k).river_elevation - mlt->at(i + 1).at(k).river_elevation) > max_waterfall) { + abs(mlt->at(i).at(k).river_elevation - mlt->at(i + 1).at(k).river_elevation) > result.max_waterfall) { if (finder->min_waterfall == 0) return false; // 0 = Absent - max_waterfall = + result.max_waterfall = abs(mlt->at(i).at(k).river_elevation - mlt->at(i + 1).at(k).river_elevation); } if (k < start_y + finder->y_dim - 2 && mlt->at(i).at(k + 1).river_present && - abs(mlt->at(i).at(k).river_elevation - mlt->at(i).at(k + 1).river_elevation) > max_waterfall) { + abs(mlt->at(i).at(k).river_elevation - mlt->at(i).at(k + 1).river_elevation) > result.max_waterfall) { if (finder->min_waterfall == 0) return false; // 0 = Absent - max_waterfall = + result.max_waterfall = abs(mlt->at(i).at(k).river_elevation - mlt->at(i).at(k + 1).river_elevation); } - river_found = true; + result.river_found = true; } - // Flatness - if ((finder->flatness == embark_assist::defs::flatness_ranges::Flat_Verified || - finder->flatness == embark_assist::defs::flatness_ranges::Mostly_Flat) && - elevation != mlt->at(i).at(k).elevation) return false; + // Flat + if (finder->flat == embark_assist::defs::yes_no_ranges::Yes && + result.elevation != mlt->at(i).at(k).elevation) return false; - if (elevation != mlt->at(i).at(k).elevation) uneven = true; + if (result.elevation != mlt->at(i).at(k).elevation) result.uneven = true; // Clay if (mlt->at(i).at(k).clay) { if (finder->clay == embark_assist::defs::present_absent_ranges::Absent) return false; - clay_found = true; + result.clay_found = true; } // Sand if (mlt->at(i).at(k).sand) { if (finder->sand == embark_assist::defs::present_absent_ranges::Absent) return false; - sand_found = true; + result.sand_found = true; } // Flux if (mlt->at(i).at(k).flux) { if (finder->flux == embark_assist::defs::present_absent_ranges::Absent) return false; - flux_found = true; + result.flux_found = true; } // Coal if (mlt->at(i).at(k).coal) { if (finder->coal == embark_assist::defs::present_absent_ranges::Absent) return false; - coal_found = true; + result.coal_found = true; } // Min Soil @@ -203,8 +627,8 @@ namespace embark_assist { mlt->at(i).at(k).soil_depth < static_cast(finder->soil_min) && finder->soil_min_everywhere == embark_assist::defs::all_present_ranges::All) return false; - if (max_soil < mlt->at(i).at(k).soil_depth) { - max_soil = mlt->at(i).at(k).soil_depth; + if (result.max_soil < mlt->at(i).at(k).soil_depth) { + result.max_soil = mlt->at(i).at(k).soil_depth; } // Max Soil @@ -212,24 +636,24 @@ namespace embark_assist { mlt->at(i).at(k).soil_depth > static_cast(finder->soil_max)) return false; // Freezing - if (min_temperature > survey_results->at(x).at(y).min_temperature[mlt->at(i).at(k).biome_offset]) { - min_temperature = survey_results->at(x).at(y).min_temperature[mlt->at(i).at(k).biome_offset]; + if (result.min_temperature > survey_results->at(x).at(y).min_temperature[mlt->at(i).at(k).biome_offset]) { + result.min_temperature = survey_results->at(x).at(y).min_temperature[mlt->at(i).at(k).biome_offset]; } - if (max_temperature < survey_results->at(x).at(y).max_temperature[mlt->at(i).at(k).biome_offset]) { - max_temperature = survey_results->at(x).at(y).max_temperature[mlt->at(i).at(k).biome_offset]; + if (result.max_temperature < survey_results->at(x).at(y).max_temperature[mlt->at(i).at(k).biome_offset]) { + result.max_temperature = survey_results->at(x).at(y).max_temperature[mlt->at(i).at(k).biome_offset]; } - if (min_temperature <= 0 && + if (result.min_temperature <= 0 && finder->freezing == embark_assist::defs::freezing_ranges::Never) return false; - if (max_temperature > 0 && + if (result.max_temperature > 0 && finder->freezing == embark_assist::defs::freezing_ranges::Permanent) return false; // Blood Rain if (survey_results->at(x).at(y).blood_rain[mlt->at(i).at(k).biome_offset]) { if (finder->blood_rain == embark_assist::defs::yes_no_ranges::No) return false; - blood_rain_found = true; + result.blood_rain_found = true; } // Syndrome Rain, Permanent @@ -237,21 +661,21 @@ namespace embark_assist { if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Temporary || finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Not_Permanent || finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::None) return false; - permanent_syndrome_rain_found = true; + result.permanent_syndrome_rain_found = true; } // Syndrome Rain, Temporary if (survey_results->at(x).at(y).temporary_syndrome_rain[mlt->at(i).at(k).biome_offset]) { if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Permanent || finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::None) return false; - temporary_syndrome_rain_found = true; + result.temporary_syndrome_rain_found = true; } // Reanmation if (survey_results->at(x).at(y).reanimating[mlt->at(i).at(k).biome_offset]) { if (finder->reanimation == embark_assist::defs::reanimation_ranges::Thralling || finder->reanimation == embark_assist::defs::reanimation_ranges::None) return false; - reanimation_found = true; + result.reanimation_found = true; } // Thralling @@ -259,50 +683,345 @@ namespace embark_assist { if (finder->reanimation == embark_assist::defs::reanimation_ranges::Reanimation || finder->reanimation == embark_assist::defs::reanimation_ranges::Not_Thralling || finder->reanimation == embark_assist::defs::reanimation_ranges::None) return false; - thralling_found = true; + result.thralling_found = true; } // Spires if (mlt->at(i).at(k).adamantine_level != -1) { - spire_count++; + result.spire_count++; if (finder->spire_count_max != -1 && - finder->spire_count_max < spire_count) return false; + finder->spire_count_max < result.spire_count) return false; } // Magma if (mlt->at(i).at(k).magma_level != -1) { - if (mlt->at(i).at(k).magma_level > magma_level) + if (mlt->at(i).at(k).magma_level > result.magma_level) { - magma_level = mlt->at(i).at(k).magma_level; + result.magma_level = mlt->at(i).at(k).magma_level; if (finder->magma_max != embark_assist::defs::magma_ranges::NA && - static_cast(finder->magma_max) < magma_level) return false; + static_cast(finder->magma_max) < result.magma_level) return false; } } // Biomes - biomes[survey_results->at(x).at(y).biome[mlt->at(i).at(k).biome_offset]] = true; + result.biomes[survey_results->at(x).at(y).biome[mlt->at(i).at(k).biome_offset]] = true; // Region Type - region_types[world_data->regions[survey_results->at(x).at(y).biome_index[mlt->at(i).at(k).biome_offset]]->type] = true; + result.region_types[world_data->regions[survey_results->at(x).at(y).biome_index[mlt->at(i).at(k).biome_offset]]->type] = true; // Metals - metal_1 = metal_1 || mlt->at(i).at(k).metals[finder->metal_1]; - metal_2 = metal_2 || mlt->at(i).at(k).metals[finder->metal_2]; - metal_3 = metal_3 || mlt->at(i).at(k).metals[finder->metal_3]; + result.metal_1 = result.metal_1 || mlt->at(i).at(k).metals[finder->metal_1]; + result.metal_2 = result.metal_2 || mlt->at(i).at(k).metals[finder->metal_2]; + result.metal_3 = result.metal_3 || mlt->at(i).at(k).metals[finder->metal_3]; // Economics - economic_1 = economic_1 || mlt->at(i).at(k).economics[finder->economic_1]; - economic_2 = economic_2 || mlt->at(i).at(k).economics[finder->economic_2]; - economic_3 = economic_3 || mlt->at(i).at(k).economics[finder->economic_3]; + result.economic_1 = result.economic_1 || mlt->at(i).at(k).economics[finder->economic_1]; + result.economic_2 = result.economic_2 || mlt->at(i).at(k).economics[finder->economic_2]; + result.economic_3 = result.economic_3 || mlt->at(i).at(k).economics[finder->economic_3]; // Minerals - mineral_1 = mineral_1 || mlt->at(i).at(k).minerals[finder->mineral_1]; - mineral_2 = mineral_2 || mlt->at(i).at(k).minerals[finder->mineral_2]; - mineral_3 = mineral_3 || mlt->at(i).at(k).minerals[finder->mineral_3]; + result.mineral_1 = result.mineral_1 || mlt->at(i).at(k).minerals[finder->mineral_1]; + result.mineral_2 = result.mineral_2 || mlt->at(i).at(k).minerals[finder->mineral_2]; + result.mineral_3 = result.mineral_3 || mlt->at(i).at(k).minerals[finder->mineral_3]; } } + // Take incursions into account. + + for (int8_t i = start_x; i < start_x + finder->x_dim; i++) { + + // NW corner, north row + if ((i == 0 && start_y == 0 && x - 1 >= 0 && y - 1 >= 0 && !survey_results->at(x - 1).at(y - 1).surveyed) || + (i == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) || + (start_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed)) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 4, + x, + y, + i, + start_y), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y, + &failed_match); + } + + // N edge, north row + if (start_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_ns_edge(survey_results, + true, + x, + y, + i, + start_y), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y, + &failed_match); + } + + // NE corner, north row + if ((i == 15 && start_y == 0 && x + 1 < world_data->world_width && y - 1 >= 0 && !survey_results->at(x + 1).at(y - 1).surveyed) || + (i == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) || + (start_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed)) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 5, + x, + y, + i, + start_y), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y, + &failed_match); + } + + // SW corner, south row + if ((i == 0 && start_y + finder->y_dim == 16 && x - 1 >= 0 && y + 1 < world_data->world_height && !survey_results->at(x - 1).at(y + 1).surveyed) || + (i == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) || + (start_y + finder->y_dim == 16 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed)) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 7, + x, + y, + i, + start_y + finder->y_dim - 1), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y + finder->y_dim - 1, + &failed_match); + } + + // S edge, south row + if (start_y + finder->y_dim == 16 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_ns_edge(survey_results, + false, + x, + y, + i, + start_y + finder->y_dim - 1), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y + finder->y_dim - 1, + &failed_match); + } + + // SE corner south row + if ((i == 15 && start_y + finder->y_dim == 16 && x + 1 < world_data->world_width && y + 1 < world_data->world_height && !survey_results->at(x + 1).at(y + 1).surveyed) || + (i == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) || + (start_y + finder->y_dim == 16 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed)) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 8, + x, + y, + i, + start_y + finder->y_dim - 1), + &result, + survey_results, + mlt, + finder, + x, + y, + i, + start_y + finder->y_dim - 1, + &failed_match); + } + + if (failed_match) return false; + } + + for (int8_t k = start_y; k < start_y + finder->y_dim; k++) { + // NW corner, west side + if ((start_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed)) { + failed_match = true; + } + else if (k > start_y) { // We've already covered the NW corner of the NW, with its complications. + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 4, + x, + y, + start_x, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x, + k, + &failed_match); + } + + // W edge, west side + if (start_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_ew_edge(survey_results, + true, + x, + y, + start_x, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x, + k, + &failed_match); + } + + // SW corner, west side + if (start_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) { + failed_match = true; + } + else if (k < start_y + finder->y_dim - 1) { // We've already covered the SW corner of the SW tile, with its complicatinons. + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 7, + x, + y, + start_x, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x, + k, + &failed_match); + } + + // NE corner, east side + if ((start_x + finder->x_dim == 16 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed)) { + failed_match = true; + } + else if (k > start_y) { // We've already covered the NE tile's NE corner, with its complications. + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 5, + x, + y, + start_x + finder->x_dim - 1, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x + finder->x_dim - 1, + k, + &failed_match); + } + + // E edge, east side + if (start_x + finder->y_dim == 16 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) { + failed_match = true; + } + else { + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_ew_edge(survey_results, + false, + x, + y, + start_x + finder->x_dim - 1, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x + finder->x_dim - 1, + k, + &failed_match); + } + + // SE corner, east side + if (start_x + finder->x_dim == 16 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) { + failed_match = true; + } + else if (k < start_y + finder->y_dim - 1) { // We've already covered the SE tile's SE corner, with its complications. + process_embark_incursion_mid_level_tile + (embark_assist::survey::translate_corner(survey_results, + 8, + x, + y, + start_x + finder->x_dim - 1, + k), + &result, + survey_results, + mlt, + finder, + x, + y, + start_x + finder->x_dim - 1, + k, + &failed_match); + } + + if (failed_match) return false; + } + // Summary section, for all the stuff that require the complete picture // // Savagery & Evilness @@ -312,11 +1031,11 @@ namespace embark_assist { while (true) { if (finder->savagery[static_cast (l)] == embark_assist::defs::evil_savagery_values::Present && - !savagery_found[static_cast(l)]) return false; + !result.savagery_found[static_cast(l)]) return false; if (finder->evilness[static_cast (l)] == embark_assist::defs::evil_savagery_values::Present && - !evilness_found[static_cast(l)]) return false; + !result.evilness_found[static_cast(l)]) return false; if (l == embark_assist::defs::evil_savagery_ranges::High) break; l = static_cast (static_cast(l) + 1); @@ -331,119 +1050,107 @@ namespace embark_assist { break; case embark_assist::defs::aquifer_ranges::Present: - if (aquifer_count == 0) return false; + if (!result.aquifer_presence_found) return false; break; case embark_assist::defs::aquifer_ranges::Partial: - if (aquifer_count == 0 || aquifer_count == embark_size) return false; + if (!result.aquifer_absence_found || !result.aquifer_presence_found) return false; break; case embark_assist::defs::aquifer_ranges::Not_All: - if (aquifer_count == embark_size) return false; + if (!result.aquifer_absence_found) return false; break; } // River & Waterfall - if (!river_found && finder->min_river > embark_assist::defs::river_ranges::None) return false; - if (max_waterfall < finder->min_waterfall) return false; // N/A = -1 is always smaller, so no additional check needed. - - // Flatness - if (!uneven && finder->flatness == embark_assist::defs::flatness_ranges::Uneven) return false; + if (!result.river_found && finder->min_river > embark_assist::defs::river_ranges::None) return false; + if (result.max_waterfall < finder->min_waterfall) return false; // N/A = -1 is always smaller, so no additional check needed. - if (finder->flatness == embark_assist::defs::flatness_ranges::Flat_Verified) { - for (uint16_t i = start_x - 1; i < start_x + finder->x_dim + 1; i++) { - if (elevation != mlt->at(i).at(start_y - 1).elevation || - elevation != mlt->at(i).at(start_y + finder->y_dim).elevation) return false; - } - - for (uint16_t k = start_y; k < start_y + finder->y_dim; k++) { - if (elevation != mlt->at(start_x - 1).at(k).elevation || - elevation != mlt->at(start_x + finder->x_dim).at(k).elevation) return false; - } - } + // Flat + if (!result.uneven && finder->flat == embark_assist::defs::yes_no_ranges::No) return false; // Clay - if (finder->clay == embark_assist::defs::present_absent_ranges::Present && !clay_found) return false; + if (finder->clay == embark_assist::defs::present_absent_ranges::Present && !result.clay_found) return false; // Sand - if (finder->sand == embark_assist::defs::present_absent_ranges::Present && !sand_found) return false; + if (finder->sand == embark_assist::defs::present_absent_ranges::Present && !result.sand_found) return false; // Flux - if (finder->flux == embark_assist::defs::present_absent_ranges::Present && !flux_found) return false; + if (finder->flux == embark_assist::defs::present_absent_ranges::Present && !result.flux_found) return false; // Coal - if (finder->coal == embark_assist::defs::present_absent_ranges::Present && !coal_found) return false; + if (finder->coal == embark_assist::defs::present_absent_ranges::Present && !result.coal_found) return false; // Min Soil if (finder->soil_min != embark_assist::defs::soil_ranges::NA && finder->soil_min_everywhere == embark_assist::defs::all_present_ranges::Present && - max_soil < static_cast(finder->soil_min)) return false; + result.max_soil < static_cast(finder->soil_min)) return false; // Freezing if (finder->freezing == embark_assist::defs::freezing_ranges::At_Least_Partial && - min_temperature > 0) return false; + result.min_temperature > 0) return false; if (finder->freezing == embark_assist::defs::freezing_ranges::Partial && - (min_temperature > 0 || - max_temperature <= 0)) return false; + (result.min_temperature > 0 || + result.max_temperature <= 0)) return false; if (finder->freezing == embark_assist::defs::freezing_ranges::At_Most_Partial && - max_temperature <= 0) return false; + result.max_temperature <= 0) return false; // Blood Rain - if (finder->blood_rain == embark_assist::defs::yes_no_ranges::Yes && !blood_rain_found) return false; + if (finder->blood_rain == embark_assist::defs::yes_no_ranges::Yes && !result.blood_rain_found) return false; // Syndrome Rain - if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Any && !permanent_syndrome_rain_found && !temporary_syndrome_rain_found) return false; - if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Permanent && !permanent_syndrome_rain_found) return false; - if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Temporary && !temporary_syndrome_rain_found) return false; + if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Any && !result.permanent_syndrome_rain_found && !result.temporary_syndrome_rain_found) return false; + if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Permanent && !result.permanent_syndrome_rain_found) return false; + if (finder->syndrome_rain == embark_assist::defs::syndrome_rain_ranges::Temporary && !result.temporary_syndrome_rain_found) return false; // Reanimation - if (finder->reanimation == embark_assist::defs::reanimation_ranges::Both && !(reanimation_found && thralling_found)) return false; - if (finder->reanimation == embark_assist::defs::reanimation_ranges::Any && !reanimation_found && !thralling_found) return false; - if (finder->reanimation == embark_assist::defs::reanimation_ranges::Thralling && !thralling_found) return false; - if (finder->reanimation == embark_assist::defs::reanimation_ranges::Reanimation && !reanimation_found) return false; + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Both && !(result.reanimation_found && result.thralling_found)) return false; + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Any && !result.reanimation_found && !result.thralling_found) return false; + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Thralling && !result.thralling_found) return false; + if (finder->reanimation == embark_assist::defs::reanimation_ranges::Reanimation && !result.reanimation_found) return false; // Spires - if (finder->spire_count_min != -1 && finder->spire_count_min > spire_count) return false; - if (finder->spire_count_max != -1 && finder->spire_count_max < spire_count) return false; + if (finder->spire_count_min != -1 && finder->spire_count_min > result.spire_count) return false; + if (finder->spire_count_max != -1 && finder->spire_count_max < result.spire_count) return false; // Magma if (// finder->magma_min != embark_assist::defs::magma_ranges::NA && // This check is redundant. - finder->magma_min > static_cast(magma_level)) return false; + finder->magma_min > static_cast(result.magma_level)) return false; // Biomes if (finder->biome_count_min != -1 || finder->biome_count_max != -1) { - biome_count = 0; + result.biome_count = 0; for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { - if (biomes[i]) biome_count++; + if (result.biomes[i]) result.biome_count++; } - if (biome_count < finder->biome_count_min || + if (result.biome_count < finder->biome_count_min || (finder->biome_count_max != -1 && - finder->biome_count_max < biome_count)) return false; + finder->biome_count_max < result.biome_count)) return false; } - if (finder->biome_1 != -1 && !biomes[finder->biome_1]) return false; - if (finder->biome_2 != -1 && !biomes[finder->biome_2]) return false; - if (finder->biome_3 != -1 && !biomes[finder->biome_3]) return false; + if (finder->biome_1 != -1 && !result.biomes[finder->biome_1]) return false; + if (finder->biome_2 != -1 && !result.biomes[finder->biome_2]) return false; + if (finder->biome_3 != -1 && !result.biomes[finder->biome_3]) return false; // Region Type - if (finder->region_type_1 != -1 && !region_types[finder->region_type_1]) return false; - if (finder->region_type_2 != -1 && !region_types[finder->region_type_2]) return false; - if (finder->region_type_3 != -1 && !region_types[finder->region_type_3]) return false; + if (finder->region_type_1 != -1 && !result.region_types[finder->region_type_1]) return false; + if (finder->region_type_2 != -1 && !result.region_types[finder->region_type_2]) return false; + if (finder->region_type_3 != -1 && !result.region_types[finder->region_type_3]) return false; // Metals, Economics, and Minerals - if (!metal_1 || - !metal_2 || - !metal_3 || - !economic_1 || - !economic_2 || - !economic_3 || - !mineral_1 || - !mineral_2 || - !mineral_3) return false; + if (!result.metal_1 || + !result.metal_2 || + !result.metal_3 || + !result.economic_1 || + !result.economic_2 || + !result.economic_3 || + !result.mineral_1 || + !result.mineral_2 || + !result.mineral_3) return false; return true; } @@ -1561,12 +2268,6 @@ uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iter return 0; } - if (iterator->finder.flatness == embark_assist::defs::flatness_ranges::Flat_Verified && - (iterator->finder.x_dim > 14 || - iterator->finder.y_dim > 14)) { - out.printerr("matcher::find: Can never verify flatness without border around embark\n"); - } - if (iterator->finder.spire_count_max < iterator->finder.spire_count_min && iterator->finder.spire_count_max != -1) { out.printerr("matcher::find: Will never find any matches with max spires < min spires\n"); diff --git a/plugins/embark-assistant/overlay.cpp b/plugins/embark-assistant/overlay.cpp index 494dbcd4a..a0defd0d5 100644 --- a/plugins/embark-assistant/overlay.cpp +++ b/plugins/embark-assistant/overlay.cpp @@ -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" }); } diff --git a/plugins/embark-assistant/survey.cpp b/plugins/embark-assistant/survey.cpp index 42a766674..a2942d415 100644 --- a/plugins/embark-assistant/survey.cpp +++ b/plugins/embark-assistant/survey.cpp @@ -50,6 +50,7 @@ #include "df/world_region.h" #include "df/world_region_details.h" #include "df/world_region_feature.h" +#include "df/world_region_type.h" #include "df/world_river.h" #include "df/world_site.h" #include "df/world_site_type.h" @@ -112,7 +113,7 @@ namespace embark_assist { for (uint16_t i = 0; i < world->raws.inorganics.size(); i++) { for (uint16_t k = 0; k < world->raws.inorganics[i]->economic_uses.size(); k++) { for (uint16_t l = 0; l < world->raws.reactions.reactions[world->raws.inorganics[i]->economic_uses[k]]->products.size(); l++) { - df::reaction_product_itemst *product = static_cast(world->raws.reactions.reactions[world->raws.inorganics[i]->economic_uses[k]]->products[l]); + df::reaction_product_itemst *product = static_cast(world->raws.reactions.reactions[world->raws.inorganics[i]->economic_uses[k]]->products[l]); if (product->mat_type == df::builtin_mats::COAL) { state->coals.push_back(i); @@ -172,7 +173,7 @@ namespace embark_assist { } } - for (uint16_t l = 0; l < state->coals.size(); l++) { + for (uint16_t l = 0; l < state->coals.size(); l++) { if (layer->mat_index == state->coals[l]) { geo_summary->at(i).coal_absent = false; break; @@ -229,7 +230,7 @@ namespace embark_assist { //================================================================================= void survey_rivers(embark_assist::defs::world_tile_data *survey_results) { -// color_ostream_proxy out(Core::getInstance().getConsole()); + // color_ostream_proxy out(Core::getInstance().getConsole()); df::world_data *world_data = world->world_data; int16_t x; int16_t y; @@ -327,23 +328,23 @@ namespace embark_assist { thralling = true; } else if (ce_type == df::creature_interaction_effect_type::PAIN || - ce_type == df::creature_interaction_effect_type::SWELLING || - ce_type == df::creature_interaction_effect_type::OOZING || - ce_type == df::creature_interaction_effect_type::BRUISING || - ce_type == df::creature_interaction_effect_type::BLISTERS || - ce_type == df::creature_interaction_effect_type::NUMBNESS || - ce_type == df::creature_interaction_effect_type::PARALYSIS || - ce_type == df::creature_interaction_effect_type::FEVER || - ce_type == df::creature_interaction_effect_type::BLEEDING || - ce_type == df::creature_interaction_effect_type::COUGH_BLOOD || - ce_type == df::creature_interaction_effect_type::VOMIT_BLOOD || - ce_type == df::creature_interaction_effect_type::NAUSEA || - ce_type == df::creature_interaction_effect_type::UNCONSCIOUSNESS || - ce_type == df::creature_interaction_effect_type::NECROSIS || - ce_type == df::creature_interaction_effect_type::IMPAIR_FUNCTION || - ce_type == df::creature_interaction_effect_type::DROWSINESS || - ce_type == df::creature_interaction_effect_type::DIZZINESS || - ce_type == df::creature_interaction_effect_type::ERRATIC_BEHAVIOR) { // Doubtful if possible for region. + ce_type == df::creature_interaction_effect_type::SWELLING || + ce_type == df::creature_interaction_effect_type::OOZING || + ce_type == df::creature_interaction_effect_type::BRUISING || + ce_type == df::creature_interaction_effect_type::BLISTERS || + ce_type == df::creature_interaction_effect_type::NUMBNESS || + ce_type == df::creature_interaction_effect_type::PARALYSIS || + ce_type == df::creature_interaction_effect_type::FEVER || + ce_type == df::creature_interaction_effect_type::BLEEDING || + ce_type == df::creature_interaction_effect_type::COUGH_BLOOD || + ce_type == df::creature_interaction_effect_type::VOMIT_BLOOD || + ce_type == df::creature_interaction_effect_type::NAUSEA || + ce_type == df::creature_interaction_effect_type::UNCONSCIOUSNESS || + ce_type == df::creature_interaction_effect_type::NECROSIS || + ce_type == df::creature_interaction_effect_type::IMPAIR_FUNCTION || + ce_type == df::creature_interaction_effect_type::DROWSINESS || + ce_type == df::creature_interaction_effect_type::DIZZINESS || + ce_type == df::creature_interaction_effect_type::ERRATIC_BEHAVIOR) { // Doubtful if possible for region. if (ce->end == -1) { permanent_syndrome_rain = true; } @@ -446,7 +447,7 @@ namespace embark_assist { } else if (world->world_data->flip_latitude == df::world_data::T_flip_latitude::North || - world->world_data->flip_latitude == df::world_data::T_flip_latitude::South) { + world->world_data->flip_latitude == df::world_data::T_flip_latitude::South) { steps = world->world_data->world_height / 2; if (latitude > steps) { @@ -485,7 +486,7 @@ namespace embark_assist { divisor = (63 / steps * lat); } else if (world->world_data->world_height == 129 || - world->world_data->world_height == 257) { + world->world_data->world_height == 257) { divisor = (64 / steps * lat); } else { @@ -494,6 +495,222 @@ namespace embark_assist { return max_temperature - ceil(divisor * 3 / 4); } + + //================================================================================= + + void process_embark_incursion(embark_assist::defs::site_infos *site_info, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tile *mlt, // Note this is a single tile, as opposed to most usages of this variable name. + int16_t elevation, + uint16_t x, + uint16_t y) { + + if (mlt->aquifer) { + site_info->aquifer = true; + } + else { + site_info->aquifer_full = false; + } + + if (mlt->soil_depth < site_info->min_soil) { + site_info->min_soil = mlt->soil_depth; + } + + if (mlt->soil_depth > site_info->max_soil) { + site_info->max_soil = mlt->soil_depth; + } + + if (elevation != mlt->elevation) { + site_info->flat = false; + } + + if (mlt->clay) { + site_info->clay = true; + } + + if (mlt->sand) { + site_info->sand = true; + } + + if (survey_results->at(x).at(y).blood_rain [mlt->biome_offset]) { + site_info->blood_rain = true; + } + + if (survey_results->at(x).at(y).permanent_syndrome_rain[mlt->biome_offset]) { + site_info->permanent_syndrome_rain = true; + } + + if (survey_results->at(x).at(y).temporary_syndrome_rain[mlt->biome_offset]) { + site_info->temporary_syndrome_rain = true; + } + + if (survey_results->at(x).at(y).reanimating[mlt->biome_offset]) { + site_info->reanimating = true; + } + + if (survey_results->at(x).at(y).thralling[mlt->biome_offset]) { + site_info->thralling = true; + } + } + + //================================================================================= + + void process_embark_incursion_mid_level_tile(uint8_t from_direction, + embark_assist::defs::site_infos *site_info, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt, + uint8_t i, + uint8_t k) { + + int8_t fetch_i = i; + int8_t fetch_k = k; + int16_t fetch_x = state->x; + int16_t fetch_y = state->y; + df::world_data *world_data = world->world_data; + + // Logic can be implemented with modulo and division, but that's harder to read. + switch (from_direction) { + case 0: + fetch_i = i - 1; + fetch_k = k - 1; + break; + + case 1: + fetch_k = k - 1; + break; + + case 2: + fetch_i = i + 1; + fetch_k = k - 1; + break; + + case 3: + fetch_i = i - 1; + break; + + case 4: + return; // Own tile provides the data, so there's no incursion. + break; + + case 5: + fetch_i = i + 1; + break; + + case 6: + fetch_i = i - 1; + fetch_k = k + 1; + break; + + case 7: + fetch_k = k + 1; + break; + + case 8: + fetch_i = i + 1; + fetch_k = k + 1; + break; + } + + if (fetch_i < 0) { + fetch_x = state->x - 1; + } + else if (fetch_i > 15) { + fetch_x = state->x + 1; + } + + if (fetch_k < 0) { + fetch_y = state->y - 1; + } + else if (fetch_k > 15) { + fetch_y = state->y + 1; + } + + if (fetch_x < 0 || + fetch_x == world_data->world_width || + fetch_y < 0 || + fetch_y == world_data->world_height) { + return; // We're at the world edge, so no incursions from the outside. + } + + if (fetch_k < 0) { + if (fetch_i < 0) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[15], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else if (fetch_i > 15) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[0], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).south_row[i], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + } + else if (fetch_k > 15) { + if (fetch_i < 0) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[15], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else if (fetch_i > 15) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[0], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).north_row[i], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + } + else { + if (fetch_i < 0) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).east_column[k], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else if (fetch_i > 15) { + process_embark_incursion(site_info, + survey_results, + &survey_results->at(fetch_x).at(fetch_y).west_column[k], + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + else { + process_embark_incursion(site_info, + survey_results, + &mlt->at(fetch_i).at(fetch_k), + mlt->at(i).at(k).elevation, + fetch_x, + fetch_y); + } + } + } } } @@ -1051,8 +1268,111 @@ void embark_assist::survey::survey_mid_level_tile(embark_assist::defs::geo_data } tile->biome_count = count; + + for (uint8_t i = 0; i < 16; i++) { + tile->north_row[i].aquifer = mlt->at(i).at(0).aquifer; + tile->south_row[i].aquifer = mlt->at(i).at(15).aquifer; + tile->west_column[i].aquifer = mlt->at(0).at(i).aquifer; + tile->east_column[i].aquifer = mlt->at(15).at(i).aquifer; + + tile->north_row[i].clay= mlt->at(i).at(0).clay; + tile->south_row[i].clay = mlt->at(i).at(15).clay; + tile->west_column[i].clay = mlt->at(0).at(i).clay; + tile->east_column[i].clay = mlt->at(15).at(i).clay; + + tile->north_row[i].sand = mlt->at(i).at(0).sand; + tile->south_row[i].sand = mlt->at(i).at(15).sand; + tile->west_column[i].sand = mlt->at(0).at(i).sand; + tile->east_column[i].sand = mlt->at(15).at(i).sand; + + tile->north_row[i].flux = mlt->at(i).at(0).flux; // Not used + tile->south_row[i].flux = mlt->at(i).at(15).flux; + tile->west_column[i].flux = mlt->at(0).at(i).flux; + tile->east_column[i].flux = mlt->at(15).at(i).flux; + + tile->north_row[i].coal = mlt->at(i).at(0).coal; // Not used + tile->south_row[i].coal = mlt->at(i).at(15).coal; + tile->west_column[i].coal = mlt->at(0).at(i).coal; + tile->east_column[i].coal = mlt->at(15).at(i).coal; + + tile->north_row[i].soil_depth = mlt->at(i).at(0).soil_depth; + tile->south_row[i].soil_depth = mlt->at(i).at(15).soil_depth; + tile->west_column[i].soil_depth = mlt->at(0).at(i).soil_depth; + tile->east_column[i].soil_depth = mlt->at(15).at(i).soil_depth; + + tile->north_row[i].offset = mlt->at(i).at(0).offset; // Not used + tile->south_row[i].offset = mlt->at(i).at(15).offset; + tile->west_column[i].offset = mlt->at(0).at(i).offset; + tile->east_column[i].offset = mlt->at(15).at(i).offset; + + tile->north_row[i].elevation = mlt->at(i).at(0).elevation; + tile->south_row[i].elevation = mlt->at(i).at(15).elevation; + tile->west_column[i].elevation = mlt->at(0).at(i).elevation; + tile->east_column[i].elevation = mlt->at(15).at(i).elevation; + + tile->north_row[i].river_present = mlt->at(i).at(0).river_present; // Not used + tile->south_row[i].river_present = mlt->at(i).at(15).river_present; + tile->west_column[i].river_present = mlt->at(0).at(i).river_present; + tile->east_column[i].river_present = mlt->at(15).at(i).river_present; + + tile->north_row[i].river_elevation = mlt->at(i).at(0).river_elevation; // Not used + tile->south_row[i].river_elevation = mlt->at(i).at(15).river_elevation; + tile->west_column[i].river_elevation = mlt->at(0).at(i).river_elevation; + tile->east_column[i].river_elevation = mlt->at(15).at(i).river_elevation; + + tile->north_row[i].adamantine_level = mlt->at(i).at(0).adamantine_level; // Not used + tile->south_row[i].adamantine_level = mlt->at(i).at(15).adamantine_level; + tile->west_column[i].adamantine_level = mlt->at(0).at(i).adamantine_level; + tile->east_column[i].adamantine_level = mlt->at(15).at(i).adamantine_level; + + tile->north_row[i].magma_level = mlt->at(i).at(0).magma_level; // Not used + tile->south_row[i].magma_level = mlt->at(i).at(15).magma_level; + tile->west_column[i].magma_level = mlt->at(0).at(i).magma_level; + tile->east_column[i].magma_level = mlt->at(15).at(i).magma_level; + + tile->north_row[i].biome_offset = mlt->at(i).at(0).biome_offset; + tile->south_row[i].biome_offset = mlt->at(i).at(15).biome_offset; + tile->west_column[i].biome_offset = mlt->at(0).at(i).biome_offset; + tile->east_column[i].biome_offset = mlt->at(15).at(i).biome_offset; + + tile->north_row[i].savagery_level = mlt->at(i).at(0).savagery_level; + tile->south_row[i].savagery_level = mlt->at(i).at(15).savagery_level; + tile->west_column[i].savagery_level = mlt->at(0).at(i).savagery_level; + tile->east_column[i].savagery_level = mlt->at(15).at(i).savagery_level; + + tile->north_row[i].evilness_level = mlt->at(i).at(0).evilness_level; + tile->south_row[i].evilness_level = mlt->at(i).at(15).evilness_level; + tile->west_column[i].evilness_level = mlt->at(0).at(i).evilness_level; + tile->east_column[i].evilness_level = mlt->at(15).at(i).evilness_level; + + tile->north_row[i].metals.resize(0); // Not used + tile->south_row[i].metals.resize(0); + tile->west_column[i].metals.resize(0); + tile->east_column[i].metals.resize(0); + + tile->north_row[i].economics.resize(0); // Not used + tile->south_row[i].economics.resize(0); + tile->west_column[i].economics.resize(0); + tile->east_column[i].economics.resize(0); + + tile->north_row[i].minerals.resize(0); // Not used + tile->south_row[i].minerals.resize(0); + tile->west_column[i].minerals.resize(0); + tile->east_column[i].minerals.resize(0); + + tile->north_corner_selection[i] = world_data->region_details[0]->edges.biome_corner[i][0]; + tile->west_corner_selection[i] = world_data->region_details[0]->edges.biome_corner[0][i]; + } + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + tile->region_type[i][k] = world_data->regions[tile->biome[mlt->at(i).at(k).biome_offset]]->type; + } + } + tile->surveyed = true; } + //================================================================================= df::coord2d embark_assist::survey::apply_offset(uint16_t x, uint16_t y, int8_t offset) { @@ -1124,6 +1444,454 @@ df::coord2d embark_assist::survey::apply_offset(uint16_t x, uint16_t y, int8_t o //================================================================================= +void adjust_coordinates(int16_t *x, int16_t *y, int8_t *i, int8_t *k) { + if (*i < 0) { + *x = *x - 1; + *i = *i + 16; + } + else if (*i > 15) { + *x = *x + 1; + *i = *i - 16; + } + + if (*k < 0) { + *y = *y - 1; + *k = *k + 16; + } + else if (*k > 15) { + *y = *y + 1; + *k = *k - 16; + } +} + +//================================================================================= + +df::world_region_type embark_assist::survey::region_type_of(embark_assist::defs::world_tile_data *survey_results, + int16_t x, + int16_t y, + int8_t i, + int8_t k) { + + df::world_data *world_data = world->world_data; + int16_t effective_x = x; + int16_t effective_y = y; + int8_t effective_i = i; + int8_t effective_k = k; + adjust_coordinates(&effective_x, &effective_y, &effective_i, &effective_i); + + if (effective_x < 0 || + effective_x >= world_data->world_width || + effective_y < 0 || + effective_y >= world_data->world_height) { + return df::world_region_type::Lake; // Essentially dummy value, yielding to everything. It will + // be handled properly later anyway. + } + + return survey_results->at(effective_x).at(effective_y).region_type[effective_i][effective_k]; +} + +//================================================================================= + +uint8_t embark_assist::survey::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) { + + df::world_data *world_data = world->world_data; + df::world_region_type nw_region_type; + df::world_region_type n_region_type; + df::world_region_type w_region_type; + df::world_region_type home_region_type; + + int16_t effective_x = x; + int16_t effective_y = y; + int8_t effective_i = i; + int8_t effective_k = k; + + uint8_t effective_corner; + bool nw_region_type_active; + bool n_region_type_active; + bool w_region_type_active; + bool home_region_type_active; + uint8_t nw_region_type_level; + uint8_t n_region_type_level; + uint8_t w_region_type_level; + uint8_t home_region_type_level; + + if (corner_location == 4) { // We're the reference. No change. + } + else if (corner_location == 5) { // Tile to the east is the reference + effective_i = i + 1; + } + else if (corner_location == 7) { // Tile to the south is the reference + effective_k = k + 1; + } + else { // 8, tile to the southeast is the reference. + effective_i = i + 1; + effective_k = k + 1; + } + + adjust_coordinates(&effective_x, &effective_y, &effective_i, &effective_i); + + if (effective_x < 0 || effective_x == world_data->world_width || + effective_y < 0 || effective_y == world_data->world_height) { + effective_x = x; + effective_y = y; + effective_i = i; + effective_k = k; + } + + if (effective_x == x && effective_y == y) { + effective_corner = world_data->region_details[0]->edges.biome_corner[effective_i][effective_k]; + } + else if (effective_y != y) { + effective_corner = survey_results->at(effective_x).at(effective_y).north_corner_selection[effective_i]; + } + else { + effective_corner = survey_results->at(effective_x).at(effective_y).west_corner_selection[effective_k]; + } + + nw_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k - 1); + n_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i, effective_k - 1); + w_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i - 1, effective_k); + home_region_type = embark_assist::survey::region_type_of(survey_results, x, y, effective_i, effective_k); + + if (nw_region_type == df::world_region_type::Lake || + nw_region_type == df::world_region_type::Ocean) { + nw_region_type_level = 0; + } + else if (nw_region_type == df::world_region_type::Mountains) { + nw_region_type_level = 1; + } + else { + nw_region_type_level = 2; + } + + if (n_region_type == df::world_region_type::Lake || + n_region_type == df::world_region_type::Ocean) { + n_region_type_level = 0; + } + else if (n_region_type == df::world_region_type::Mountains) { + n_region_type_level = 1; + } + else { + n_region_type_level = 2; + } + + if (w_region_type == df::world_region_type::Lake || + w_region_type == df::world_region_type::Ocean) { + w_region_type_level = 0; + } + else if (w_region_type == df::world_region_type::Mountains) { + w_region_type_level = 1; + } + else { + w_region_type_level = 2; + } + + if (home_region_type == df::world_region_type::Lake || + home_region_type == df::world_region_type::Ocean) { + home_region_type_level = 0; + } + else if (n_region_type == df::world_region_type::Mountains) { + home_region_type_level = 1; + } + else { + home_region_type_level = 2; + } + + nw_region_type_active = nw_region_type_level >= n_region_type_level && + nw_region_type_level >= w_region_type_level && + nw_region_type_level >= home_region_type_level; + + n_region_type_active = n_region_type_level >= nw_region_type_level && + n_region_type_level >= w_region_type_level && + n_region_type_level >= home_region_type_level; + + w_region_type_active = w_region_type_level >= nw_region_type_level && + w_region_type_level >= n_region_type_level && + w_region_type_level >= home_region_type_level; + + home_region_type_active = home_region_type_level >= nw_region_type_level && + home_region_type_level >= n_region_type_level && + home_region_type_level >= w_region_type_level; + + if ((effective_corner == 0 && !nw_region_type_active) || + (effective_corner == 1 && !n_region_type_active) || + (effective_corner == 2 && !w_region_type_active) || + (effective_corner == 3 && !home_region_type_active)) { + //### The designated corner is suppressed, but we do not have any + // knowledge of how to select a replacement. Thus, the presedence + // list used is fairly arbitrary: Use the lowest number available. + if (nw_region_type_active) { + effective_corner = 0; + } + else if (n_region_type_active) { + effective_corner = 1; + } + else if (w_region_type_active) { + effective_corner = 2; + } + else { + effective_corner = 3; + } + } + + switch (effective_corner) { + case 0: + return corner_location - 4; + break; + + case 1: + return corner_location - 3; + break; + + case 2: + return corner_location - 1; + break; + + case 3: + return corner_location; + break; + } + + return -1; // Should never happen + + /* The logic that's reduced to the code above. + switch (corner_location) { + case 0: // N/A Not to the north or west + case 1: // N/A + case 2: // N/A + case 3: // N/A + case 6: // N/A + return -1; // Should never happen + break; + + case 4: // Self + switch (corner) { + case 0: + return 0; // Northwest + break; + + case 1: + return 1; // North + break; + + case 2: + return 3; // West + break; + + case 3: + return 4; // Self + } + + case 5: // East + switch (corner) { + case 0: + return 1; // North + break; + + case 1: + return 2; // Northeast + break; + + case 2: + return 4; // Self + break; + + case 3: + return 5; // East + } + case 7: // South + switch (corner) { + case 0: + return 3; // West + break; + + case 1: + return 4; // Self + break; + + case 2: + return 6; // Southwest + break; + + case 3: + return 7; // South + } + + case 8: // Southeast + switch (corner) { + case 0: + return 4; // Self + break; + + case 1: + return 5; // East + break; + + case 2: + return 7; // South + break; + + case 3: + return 8; // Southeast + } + } + */ +} + +//================================================================================= + +uint8_t embark_assist::survey::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) { + + df::world_data *world_data = world->world_data; + uint8_t effective_edge; + df::world_region_type north_region_type; + df::world_region_type south_region_type; + + if (own_edge) { + effective_edge = world_data->region_details[0]->edges.biome_x[i][k]; + south_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k); + north_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k - 1); + } + else { + effective_edge = world_data->region_details[0]->edges.biome_x[i][k + 1]; + north_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k); + south_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k + 1); + } + + // Apply rules for Ocean && Lake to yield to everything else, + // and Mountain to everything but those. + // + if ((north_region_type == df::world_region_type::Lake || + north_region_type == df::world_region_type::Ocean) && + south_region_type != df::world_region_type::Lake && + south_region_type != df::world_region_type::Ocean) { + effective_edge = 1; + } + + if ((south_region_type == df::world_region_type::Lake || + south_region_type == df::world_region_type::Ocean) && + north_region_type != df::world_region_type::Lake && + north_region_type != df::world_region_type::Ocean) { + effective_edge = 0; + } + + if (north_region_type == df::world_region_type::Mountains && + south_region_type != df::world_region_type::Lake && + south_region_type != df::world_region_type::Ocean && + south_region_type != df::world_region_type::Mountains) { + effective_edge = 1; + } + + if (south_region_type == df::world_region_type::Mountains && + north_region_type != df::world_region_type::Lake && + north_region_type != df::world_region_type::Ocean && + north_region_type != df::world_region_type::Mountains) { + effective_edge = 0; + } + + if (effective_edge == 0) { + if (own_edge) { + return 1; + } + else { + return 4; + } + } + else { + if (own_edge) { + return 4; + } + else { + return 7; + } + } +} + +//================================================================================= + +uint8_t embark_assist::survey::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) { + + df::world_data *world_data = world->world_data; + uint8_t effective_edge; + df::world_region_type west_region_type; + df::world_region_type east_region_type; + + if (own_edge) { + effective_edge = world_data->region_details[0]->edges.biome_x[i][k]; + east_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k); + west_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i - 1, k); + } + else { + effective_edge = world_data->region_details[0]->edges.biome_x[i + 1][k]; + west_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k); + east_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i + 1, k); + } + + // Apply rules for Ocean && Lake to yield to everything else, + // and Mountain to everything but those. + // + if ((west_region_type == df::world_region_type::Lake || + west_region_type == df::world_region_type::Ocean) && + east_region_type != df::world_region_type::Lake && + east_region_type != df::world_region_type::Ocean) { + effective_edge = 1; + } + + if ((east_region_type == df::world_region_type::Lake || + east_region_type == df::world_region_type::Ocean) && + west_region_type != df::world_region_type::Lake && + west_region_type != df::world_region_type::Ocean) { + effective_edge = 0; + } + + if (west_region_type == df::world_region_type::Mountains && + west_region_type != df::world_region_type::Lake && + east_region_type != df::world_region_type::Ocean && + east_region_type != df::world_region_type::Mountains) { + effective_edge = 1; + } + + if (east_region_type == df::world_region_type::Mountains && + east_region_type != df::world_region_type::Lake && + west_region_type != df::world_region_type::Ocean && + west_region_type != df::world_region_type::Mountains) { + effective_edge = 0; + } + if (effective_edge == 0) { + if (own_edge) { + return 3; + } + else { + return 4; + } + } + else { + if (own_edge) { + return 4; + } + else { + return 5; + } + } +} + +//================================================================================= + void embark_assist::survey::survey_region_sites(embark_assist::defs::site_lists *site_list) { // color_ostream_proxy out(Core::getInstance().getConsole()); auto screen = Gui::getViewscreenByType(0); @@ -1196,6 +1964,7 @@ void embark_assist::survey::survey_region_sites(embark_assist::defs::site_lists //================================================================================= void embark_assist::survey::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) { @@ -1207,7 +1976,8 @@ void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles * std::vector metals(state->max_inorganic); std::vector economics(state->max_inorganic); std::vector minerals(state->max_inorganic); - bool flatness_verification_failed; + bool incursion_processing_failed = false; + df::world_data *world_data = world->world_data; if (!use_cache) { // For some reason DF scrambles these values on world tile movements (at least in Lua...). state->local_min_x = screen->location.embark_pos_min.x; @@ -1219,16 +1989,22 @@ void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles * state->x = x; state->y = y; + site_info->incursions_processed = true; site_info->aquifer = false; site_info->aquifer_full = true; site_info->min_soil = 10; site_info->max_soil = 0; - site_info->flatness = embark_assist::defs::flatnesses::Mostly_Flat; + site_info->flat = true; site_info->max_waterfall = 0; site_info->clay = false; site_info->sand = false; site_info->flux = false; site_info->coal = false; + site_info->blood_rain = false; + site_info->permanent_syndrome_rain = false; + site_info->temporary_syndrome_rain = false; + site_info->reanimating = false; + site_info->thralling = false; site_info->metals.clear(); site_info->economics.clear(); site_info->metals.clear(); @@ -1254,7 +2030,7 @@ void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles * elevation = mlt->at(i).at(k).elevation; } else if (elevation != mlt->at(i).at(k).elevation) { - site_info->flatness = embark_assist::defs::flatnesses::Uneven; + site_info->flat = false; } if (mlt->at(i).at(k).river_present) { @@ -1291,42 +2067,31 @@ void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles * site_info->coal = true; } - for (uint16_t l = 0; l < state->max_inorganic; l++) { - metals[l] = metals[l] || mlt->at(i).at(k).metals[l]; - economics[l] = economics[l] || mlt->at(i).at(k).economics[l]; - minerals[l] = minerals[l] || mlt->at(i).at(k).minerals[l]; + if (survey_results->at(x).at(y).blood_rain[mlt->at(i).at(k).biome_offset]) { + site_info->blood_rain = true; } - } - } - if (site_info->flatness == embark_assist::defs::flatnesses::Mostly_Flat && - state->local_min_x > 0 && - state->local_max_x < 15 && - state->local_min_y > 0 && - state->local_max_y < 15) - { - flatness_verification_failed = false; + if (survey_results->at(x).at(y).permanent_syndrome_rain[mlt->at(i).at(k).biome_offset]) { + site_info->permanent_syndrome_rain = true; + } - for (uint8_t i = state->local_min_x - 1; i <= state->local_max_x + 1; i++) { - if (mlt->at(i).at(state->local_min_y - 1).elevation != elevation || - mlt->at(i).at(state->local_max_y + 1).elevation != elevation) { - flatness_verification_failed = true; - break; + if (survey_results->at(x).at(y).temporary_syndrome_rain[mlt->at(i).at(k).biome_offset]) { + site_info->temporary_syndrome_rain = true; } - } - if (!flatness_verification_failed) { - for (uint8_t k = state->local_min_y; k <= state->local_max_y; k++) { - if (mlt->at(state->local_min_x - 1).at(k).elevation != elevation || - mlt->at(state->local_max_x + 1).at(k).elevation != elevation) { - flatness_verification_failed = true; - break; - } + if (survey_results->at(x).at(y).reanimating[mlt->at(i).at(k).biome_offset]) { + site_info->reanimating = true; + } + + if (survey_results->at(x).at(y).thralling[mlt->at(i).at(k).biome_offset]) { + site_info->thralling = true; } - } - if (!flatness_verification_failed) { - site_info->flatness = embark_assist::defs::flatnesses::Flat_Verified; + for (uint16_t l = 0; l < state->max_inorganic; l++) { + metals[l] = metals[l] || mlt->at(i).at(k).metals[l]; + economics[l] = economics[l] || mlt->at(i).at(k).economics[l]; + minerals[l] = minerals[l] || mlt->at(i).at(k).minerals[l]; + } } } @@ -1343,6 +2108,250 @@ void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles * site_info->minerals.push_back(l); } } + + // Take incursions into account. + + for (int8_t i = state->local_min_x; i <= state->local_max_x; i++) { + // NW corner, north row + if ((i == 0 && state->local_min_y == 0 && x - 1 >= 0 && y - 1 >= 0 && !survey_results->at(x - 1).at (y - 1).surveyed) || + (i == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) || + (state->local_min_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed)) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 4, + x, + y, + i, + state->local_min_y), + site_info, + survey_results, + mlt, + i, + state->local_min_y); + } + + // N edge, north row + if (state->local_min_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_ns_edge(survey_results, + true, + x, + y, + i, + state->local_min_y), + site_info, + survey_results, + mlt, + i, + state->local_min_y); + } + + // NE corner, north row + if ((i == 15 && state->local_min_y == 0 && x + 1 < world_data->world_width && y - 1 >= 0 && !survey_results->at(x + 1).at(y - 1).surveyed) || + (i == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) || + (state->local_min_y == 0 && y - 1 >= 0 && !survey_results->at(x).at(y - 1).surveyed)) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 5, + x, + y, + i, + state->local_min_y), + site_info, + survey_results, + mlt, + i, + state->local_min_y); + } + + // SW corner, south row + if ((i == 0 && state->local_max_y == 15 && x - 1 >= 0 && y + 1 < world_data->world_height && !survey_results->at(x - 1).at(y + 1).surveyed) || + (i == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) || + (state->local_max_y == 15 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed)) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 7, + x, + y, + i, + state->local_max_y), + site_info, + survey_results, + mlt, + i, + state->local_max_y); + } + + // S edge, south row + if (state->local_max_y == 15 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_ns_edge(survey_results, + false, + x, + y, + i, + state->local_max_y), + site_info, + survey_results, + mlt, + i, + state->local_max_y); + } + + // SE corner south row + if ((i == 15 && state->local_max_y == 15 && x + 1 < world_data->world_width && y + 1 < world_data->world_height && !survey_results->at(x + 1).at(y + 1).surveyed) || + (i == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) || + (state->local_max_y == 15 && y + 1 < world_data->world_height && !survey_results->at(x).at(y + 1).surveyed)) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 8, + x, + y, + i, + state->local_max_y), + site_info, + survey_results, + mlt, + i, + state->local_max_y); + } + } + + for (int8_t k = state->local_min_y; k <= state->local_max_y; k++) { + // NW corner, west side + if ((state->local_min_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed)) { + incursion_processing_failed = true; + } + else if (k > state->local_min_y) { // We've already covered the NW corner of the NW, with its complications. + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 4, + x, + y, + state->local_min_x, + k), + site_info, + survey_results, + mlt, + state->local_min_x, + k); + } + + // W edge, west side + if (state->local_min_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_ns_edge(survey_results, + true, + x, + y, + state->local_min_x, + k), + site_info, + survey_results, + mlt, + state->local_min_x, + k); + } + + // SW corner, west side + if (state->local_min_x == 0 && x - 1 >= 0 && !survey_results->at(x - 1).at(y).surveyed) { + incursion_processing_failed = true; + } + else if (k < state->local_max_y) { // We've already covered the SW corner of the SW tile, with its complicatinons. + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 7, + x, + y, + state->local_min_x, + k), + site_info, + survey_results, + mlt, + state->local_min_x, + k); + } + + // NE corner, east side + if ((state->local_max_x == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed)) { + incursion_processing_failed = true; + } + else if (k > state->local_min_y) { // We've already covered the NE tile's NE corner, with its complications. + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 5, + x, + y, + state->local_max_x, + k), + site_info, + survey_results, + mlt, + state->local_max_x, + k); + } + + // E edge, east side + if (state->local_max_x == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) { + incursion_processing_failed = true; + } + else { + process_embark_incursion_mid_level_tile + (translate_ns_edge(survey_results, + false, + x, + y, + state->local_max_x, + k), + site_info, + survey_results, + mlt, + state->local_max_x, + k); + } + + // SE corner, east side + if (state->local_max_x == 15 && x + 1 < world_data->world_width && !survey_results->at(x + 1).at(y).surveyed) { + incursion_processing_failed = true; + } + else if (k < state->local_max_y) { // We've already covered the SE tile's SE corner, with its complications. + process_embark_incursion_mid_level_tile + (translate_corner(survey_results, + 8, + x, + y, + state->local_max_x, + k), + site_info, + survey_results, + mlt, + state->local_max_x, + k); + } + } + + if (incursion_processing_failed) site_info->incursions_processed = false; } //================================================================================= diff --git a/plugins/embark-assistant/survey.h b/plugins/embark-assistant/survey.h index 03d2d9a03..5f201b04f 100644 --- a/plugins/embark-assistant/survey.h +++ b/plugins/embark-assistant/survey.h @@ -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);