From 80fe49b339e571eb3fe11a644608657225bba7fe Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 14:13:34 +0200 Subject: [PATCH 001/170] Add embark-assistant plugin --- plugins/CMakeLists.txt | 1 + plugins/embark-assistant/CMakeLists.txt | 48 + plugins/embark-assistant/biome_type.cpp | 752 +++++++++ plugins/embark-assistant/biome_type.h | 7 + plugins/embark-assistant/defs.h | 256 +++ plugins/embark-assistant/embark-assistant.cpp | 296 ++++ plugins/embark-assistant/embark-assistant.h | 1 + plugins/embark-assistant/finder_ui.cpp | 1143 +++++++++++++ plugins/embark-assistant/finder_ui.h | 17 + plugins/embark-assistant/help_ui.cpp | 314 ++++ plugins/embark-assistant/help_ui.h | 15 + plugins/embark-assistant/matcher.cpp | 1445 +++++++++++++++++ plugins/embark-assistant/matcher.h | 21 + plugins/embark-assistant/overlay.cpp | 439 +++++ plugins/embark-assistant/overlay.h | 37 + plugins/embark-assistant/screen.cpp | 26 + plugins/embark-assistant/screen.h | 7 + plugins/embark-assistant/survey.cpp | 1080 ++++++++++++ plugins/embark-assistant/survey.h | 38 + 19 files changed, 5943 insertions(+) create mode 100644 plugins/embark-assistant/CMakeLists.txt create mode 100644 plugins/embark-assistant/biome_type.cpp create mode 100644 plugins/embark-assistant/biome_type.h create mode 100644 plugins/embark-assistant/defs.h create mode 100644 plugins/embark-assistant/embark-assistant.cpp create mode 100644 plugins/embark-assistant/embark-assistant.h create mode 100644 plugins/embark-assistant/finder_ui.cpp create mode 100644 plugins/embark-assistant/finder_ui.h create mode 100644 plugins/embark-assistant/help_ui.cpp create mode 100644 plugins/embark-assistant/help_ui.h create mode 100644 plugins/embark-assistant/matcher.cpp create mode 100644 plugins/embark-assistant/matcher.h create mode 100644 plugins/embark-assistant/overlay.cpp create mode 100644 plugins/embark-assistant/overlay.h create mode 100644 plugins/embark-assistant/screen.cpp create mode 100644 plugins/embark-assistant/screen.h create mode 100644 plugins/embark-assistant/survey.cpp create mode 100644 plugins/embark-assistant/survey.h diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index b6e05b749..e85e0aaf4 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -111,6 +111,7 @@ if (BUILD_SUPPORTED) add_subdirectory(diggingInvaders) DFHACK_PLUGIN(dwarfvet dwarfvet.cpp) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) + add_subdirectory(embark-assistant) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(fastdwarf fastdwarf.cpp) diff --git a/plugins/embark-assistant/CMakeLists.txt b/plugins/embark-assistant/CMakeLists.txt new file mode 100644 index 000000000..e57561ec1 --- /dev/null +++ b/plugins/embark-assistant/CMakeLists.txt @@ -0,0 +1,48 @@ +PROJECT (embark-assistant) +# A list of source files +SET(PROJECT_SRCS + biome_type.cpp + embark-assistant.cpp + finder_ui.cpp + help_ui.cpp + matcher.cpp + overlay.cpp + screen.cpp + survey.cpp +) +# A list of headers +SET(PROJECT_HDRS + biome_type.h + defs.h + embark-assistant.h + finder_ui.h + help_ui.h + matcher.h + overlay.h + screen.h + survey.h +) +SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) + +# mash them together (headers are marked as headers and nothing will try to compile them) +LIST(APPEND PROJECT_SRCS ${PROJECT_HDRS}) + +# option to use a thread for no particular reason +#OPTION(SKELETON_THREAD "Use threads in the skeleton plugin." ON) +#linux +IF(UNIX) + add_definitions(-DLINUX_BUILD) + SET(PROJECT_LIBS + # add any extra linux libs here + ${PROJECT_LIBS} + ) +# windows +ELSE(UNIX) + SET(PROJECT_LIBS + # add any extra windows libs here + ${PROJECT_LIBS} + $(NOINHERIT) + ) +ENDIF(UNIX) +# this makes sure all the stuff is put in proper places and linked to dfhack +DFHACK_PLUGIN(embark-assistant ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS}) diff --git a/plugins/embark-assistant/biome_type.cpp b/plugins/embark-assistant/biome_type.cpp new file mode 100644 index 000000000..82603a004 --- /dev/null +++ b/plugins/embark-assistant/biome_type.cpp @@ -0,0 +1,752 @@ +/* The code is copied from Ragundo's repo referenced below. +The changes are: +- The addition of a .h file reference. +- The simplification of the code using ofsub to remove the use of (and + .h reference to) that function (analysis of the code showed the + simplified code is the result, as the ofsub expressions will never be + true given the range of the values it can be passed in these functions). +- The change of the main function to take a separate y coordinate for + use in the tropicality determination to allow proper determination of + the tropicality of mid level tiles ("region tiles") referencing a + neighboring world tile's biome. +*/ +/* +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +// You can always find the latest version of this plugin in Github +// https://github.com/ragundo/exportmaps + +#include "../../include/dfhack.h" +#include +#include +#include +#include + +#include "biome_type.h" + +/***************************************************************************** +Local functions forward declaration +*****************************************************************************/ +std::pair check_tropicality(df::region_map_entry& region, + int a1 +); + +int get_lake_biome(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude +); + +int get_ocean_biome(df::region_map_entry& region, + bool is_tropical_area_by_latitude +); + +int get_desert_biome(df::region_map_entry& region); + +int get_biome_grassland(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_savanna(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_shrubland(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_marsh(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_forest(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_swamp(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_desert_or_grassland_or_savanna(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +int get_biome_shrubland_or_marsh(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +); + +/***************************************************************************** +Module main function. +Return the biome type, given a position coordinate expressed in world_tiles +The world ref coordinates are used for tropicality determination and may refer +to a tile neighboring the "official" one. +*****************************************************************************/ +int get_biome_type(int world_coord_x, + int world_coord_y, + int world_ref_coord_y +) +{ + // Biome is per region, so get the region where this biome exists + df::region_map_entry& region = df::global::world->world_data->region_map[world_coord_x][world_coord_y]; + + // Check if the y reference position coordinate belongs to a tropical area + std::pair p = check_tropicality(region, + world_ref_coord_y + ); + bool is_possible_tropical_area_by_latitude = p.first; + bool is_tropical_area_by_latitude = p.second; + + // Begin the discrimination + if (region.flags.is_set(df::region_map_entry_flags::is_lake)) // is it a lake? + return get_lake_biome(region, + is_possible_tropical_area_by_latitude + ); + + // Not a lake. Check elevation + // Elevation greater then 149 means a mountain biome + // Elevation below 100 means a ocean biome + // Elevation between 100 and 149 are land biomes + + if (region.elevation >= 150) // is it a mountain? + return df::enums::biome_type::biome_type::MOUNTAIN; // 0 + + if (region.elevation < 100) // is it a ocean? + return get_ocean_biome(region, + is_possible_tropical_area_by_latitude + ); + + // land biome. Elevation between 100 and 149 + if (region.temperature <= -5) + { + if (region.drainage < 75) + return df::enums::biome_type::biome_type::TUNDRA; // 2 + else + return df::enums::biome_type::biome_type::GLACIER; // 1 + } + + // Not a lake, mountain, ocean, glacier or tundra + // Vegetation determines the biome type + if (region.vegetation < 66) + { + if (region.vegetation < 33) + return get_biome_desert_or_grassland_or_savanna(region, + is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + world_coord_y, + world_coord_x + ); + else // vegetation between 33 and 65 + return get_biome_shrubland_or_marsh(region, + is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + world_coord_y, + world_coord_x + ); + } + + // Not a lake, mountain, ocean, glacier, tundra, desert, grassland or savanna + // vegetation >= 66 + if (region.drainage >= 33) + return get_biome_forest(region, + is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + world_coord_y, + world_coord_x + ); + + // Not a lake, mountain, ocean, glacier, tundra, desert, grassland, savanna or forest + // vegetation >= 66, drainage < 33 + return get_biome_swamp(region, + is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + world_coord_y, + world_coord_x); +} + + + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +std::pair check_tropicality_no_poles_world(df::region_map_entry& region, + int y_pos +) +{ + bool is_possible_tropical_area_by_latitude = false; + bool is_tropical_area_by_latitude = false; + + // If there're no poles, tropical area is determined by temperature + if (region.temperature >= 75) + is_possible_tropical_area_by_latitude = true; + is_tropical_area_by_latitude = region.temperature >= 85; + + return std::pair(is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude + ); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +std::pair check_tropicality_north_pole_only_world(df::region_map_entry& region, + int y_pos +) +{ + int v6; + bool is_possible_tropical_area_by_latitude = false; + bool is_tropical_area_by_latitude = false; + df::world_data* wdata = df::global::world->world_data; + + // Scale the smaller worlds to the big one + if (wdata->world_height == 17) + v6 = 16 * y_pos; + else if (wdata->world_height == 33) + v6 = 8 * y_pos; + else if (wdata->world_height == 65) + v6 = 4 * y_pos; + else if (wdata->world_height == 129) + v6 = 2 * y_pos; + else + v6 = y_pos; + + is_possible_tropical_area_by_latitude = v6 > 170; + is_tropical_area_by_latitude = v6 >= 200; + + return std::pair(is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude + ); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +std::pair check_tropicality_south_pole_only_world(df::region_map_entry& region, + int y_pos +) +{ + int v6 = df::global::world->world_data->world_height - y_pos - 1; + bool is_possible_tropical_area_by_latitude = false; + bool is_tropical_area_by_latitude = false; + df::world_data* wdata = df::global::world->world_data; + + if (wdata->world_height == 17) + v6 *= 16; + else if (wdata->world_height == 33) + v6 *= 8; + else if (wdata->world_height == 65) + v6 *= 4; + else if (wdata->world_height == 129) + v6 *= 2; + else + v6 *= 1; + + is_possible_tropical_area_by_latitude = v6 > 170; + is_tropical_area_by_latitude = v6 >= 200; + + return std::pair(is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude + ); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +std::pair check_tropicality_both_poles_world(df::region_map_entry& region, + int y_pos +) +{ + int v6; + bool is_possible_tropical_area_by_latitude = false; + bool is_tropical_area_by_latitude = false; + df::world_data* wdata = df::global::world->world_data; + + if (y_pos < wdata->world_height / 2) + v6 = 2 * y_pos; + else + { + v6 = wdata->world_height + 2 * (wdata->world_height / 2 - y_pos) - 1; + if (v6 < 0) + v6 = 0; + if (v6 >= wdata->world_height) + v6 = wdata->world_height - 1; + } + + if (wdata->world_height == 17) + v6 *= 16; + else if (wdata->world_height == 33) + v6 *= 8; + else if (wdata->world_height == 65) + v6 *= 4; + else if (wdata->world_height == 129) + v6 *= 2; + else + v6 *= 1; + + is_possible_tropical_area_by_latitude = v6 > 170; + is_tropical_area_by_latitude = v6 >= 200; + + return std::pair(is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude + ); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +std::pair check_tropicality(df::region_map_entry& region, + int y_pos +) +{ + int flip_latitude = df::global::world->world_data->flip_latitude; + + if (flip_latitude == -1) // NO POLES + return check_tropicality_no_poles_world(region, + y_pos + ); + + else if (flip_latitude == 0) // NORTH POLE ONLY + return check_tropicality_north_pole_only_world(region, + y_pos + ); + + else if (flip_latitude == 1) // SOUTH_POLE ONLY + return check_tropicality_south_pole_only_world(region, + y_pos + ); + + else if (flip_latitude == 2) // BOTH POLES + return check_tropicality_both_poles_world(region, + y_pos + ); + + return std::pair(false, false); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_parameter_percentage(int flip_latitude, + int y_pos, + int rainfall, + int world_height +) +{ + int result; + int ypos = y_pos; + + if (flip_latitude == -1) // NO POLES + return 100; + + else if (flip_latitude == 1) // SOUTH POLE + ypos = world_height - y_pos - 1; + else if (flip_latitude == 2) // NORTH & SOUTH POLE + { + if (ypos < world_height / 2) + ypos *= 2; + else + { + ypos = world_height + 2 * (world_height / 2 - ypos) - 1; + if (ypos < 0) + ypos = 0; + if (ypos >= world_height) + ypos = world_height - 1; + } + } + + int latitude; // 0 - 256 (size of a large world) + switch (world_height) + { + case 17: // Pocket world + latitude = 16 * ypos; + break; + case 33: // Smaller world + latitude = 8 * ypos; + break; + case 65: // Small world + latitude = 4 * ypos; + break; + case 129: // Medium world + latitude = 2 * ypos; + break; + default: // Large world + latitude = ypos; + break; + } + + // latitude > 220 + if ((latitude - 171) > 49) + return 100; + + + // Latitude between 191 and 200 + if ((latitude > 190) && (latitude < 201)) + return 0; + + // Latitude between 201 and 220 + if ((latitude > 190) && (latitude >= 201)) + result = rainfall + 16 * (latitude - 207); + else + // Latitude between 0 and 190 + result = (16 * (184 - latitude) - rainfall); + + if (result < 0) + return 0; + + if (result > 100) + return 100; + + return result; +} + +//----------------------------------------------------------------------------// +// Utility function +// +// return some unknow parameter as a percentage +//----------------------------------------------------------------------------// +int get_region_parameter(int y, + int x, + char a4 +) +{ + int result = 100; + + if ((df::global::cur_season && *df::global::cur_season != 1) || !a4) + { + int world_height = df::global::world->world_data->world_height; + if (world_height > 65) // Medium and large worlds + { + // access to region 2D array + df::region_map_entry& region = df::global::world->world_data->region_map[x][y]; + return get_parameter_percentage(df::global::world->world_data->flip_latitude, + y, + region.rainfall, + world_height + ); + } + } + return result; +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_lake_biome(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude +) +{ + // salinity values tell us the lake type + // greater than 66 is a salt water lake + // between 33 and 65 is a brackish water lake + // less than 33 is a fresh water lake + if (region.salinity < 66) + { + if (region.salinity < 33) + if (is_possible_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::LAKE_TROPICAL_FRESHWATER; // 39 + else + return df::enums::biome_type::biome_type::LAKE_TEMPERATE_FRESHWATER; // 36 + else // salinity >= 33 + if (is_possible_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::LAKE_TROPICAL_BRACKISHWATER; // 40 + else + return df::enums::biome_type::biome_type::LAKE_TEMPERATE_BRACKISHWATER; // 37 + } + else // salinity >= 66 + { + if (is_possible_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::LAKE_TROPICAL_SALTWATER;// 41 + else + return df::enums::biome_type::biome_type::LAKE_TEMPERATE_SALTWATER; // 38 + } +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_ocean_biome(df::region_map_entry& region, + bool is_tropical_area_by_latitude +) +{ + if (is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::OCEAN_TROPICAL; // 27 + else + if (region.temperature <= -5) + return df::enums::biome_type::biome_type::OCEAN_ARCTIC; // 29 + else + return df::enums::biome_type::biome_type::OCEAN_TEMPERATE; // 28 +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_desert_biome(df::region_map_entry& region) +{ + if (region.drainage < 66) + { + if (region.drainage < 33) + return df::enums::biome_type::biome_type::DESERT_SAND; // 26 + else // drainage between 33 and 65 + return df::enums::biome_type::biome_type::DESERT_ROCK; // 25 + } + // drainage >= 66 + return df::enums::biome_type::biome_type::DESERT_BADLAND; // 24 +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_grassland(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::GRASSLAND_TROPICAL; // 21 + else + return df::enums::biome_type::biome_type::GRASSLAND_TEMPERATE; //18; +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_savanna(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) <= 6)) || is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::SAVANNA_TROPICAL; // 22 + else + return df::enums::biome_type::biome_type::SAVANNA_TEMPERATE; //19; + +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_desert_or_grassland_or_savanna(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if (region.vegetation < 20) + { + if (region.vegetation < 10) + return get_desert_biome(region); + else // vegetation between 10 and 19 + return get_biome_grassland(is_possible_tropical_area_by_latitude, is_tropical_area_by_latitude, y, x); + } + // vegetation between 20 and 32 + return get_biome_savanna(is_possible_tropical_area_by_latitude, is_tropical_area_by_latitude, y, x); +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_shrubland(bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if (is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66 || is_tropical_area_by_latitude)) + return df::enums::biome_type::biome_type::SHRUBLAND_TROPICAL; // 23 + else + return df::enums::biome_type::biome_type::SHRUBLAND_TEMPERATE; // 20 +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_marsh(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if (region.salinity < 66) + { + if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::MARSH_TROPICAL_FRESHWATER; // 10 + else + return df::enums::biome_type::biome_type::MARSH_TEMPERATE_FRESHWATER; // 5 + } + else // drainage < 33, salinity >= 66 + { + if ((is_possible_tropical_area_by_latitude && (get_region_parameter(y, x, 0) < 66)) || is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::MARSH_TROPICAL_SALTWATER; // 11 + else + return df::enums::biome_type::biome_type::MARSH_TEMPERATE_SALTWATER; // 6 + } +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_shrubland_or_marsh(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + if (region.drainage >= 33) + return get_biome_shrubland(is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + y, + x + ); + // drainage < 33 + return get_biome_marsh(region, + is_possible_tropical_area_by_latitude, + is_tropical_area_by_latitude, + y, + x + ); +} + + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_forest(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + int parameter = get_region_parameter(y, x, 0); + + // drainage >= 33, not tropical area + if (!is_possible_tropical_area_by_latitude) + { + if ((region.rainfall < 75) || (region.temperature < 65)) + { + if (region.temperature >= 10) + return df::enums::biome_type::biome_type::FOREST_TEMPERATE_CONIFER; // 13 + else + return df::enums::biome_type::biome_type::FOREST_TAIGA; // 12 + } + else + return df::enums::biome_type::biome_type::FOREST_TEMPERATE_BROADLEAF; // 14 + } + else // drainage >= 33, tropical area + { + if (((parameter < 66) || is_tropical_area_by_latitude) && (region.rainfall < 75)) + return df::enums::biome_type::biome_type::FOREST_TROPICAL_CONIFER; // 15 + if (parameter < 66) + return df::enums::biome_type::biome_type::FOREST_TROPICAL_DRY_BROADLEAF; // 16 + if (is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::FOREST_TROPICAL_MOIST_BROADLEAF; // 17 + else + { + if ((region.rainfall < 75) || (region.temperature < 65)) + { + if (region.temperature >= 10) + return df::enums::biome_type::biome_type::FOREST_TEMPERATE_CONIFER; // 13 + else + return df::enums::biome_type::biome_type::FOREST_TAIGA; // 12 + } + else + return df::enums::biome_type::biome_type::FOREST_TEMPERATE_BROADLEAF; // 14 + } + } +} + +//----------------------------------------------------------------------------// +// Utility function +// +//----------------------------------------------------------------------------// +int get_biome_swamp(df::region_map_entry& region, + bool is_possible_tropical_area_by_latitude, + bool is_tropical_area_by_latitude, + int y, + int x +) +{ + int parameter = get_region_parameter(y, x, 0); + + if (is_possible_tropical_area_by_latitude) + { + if (region.salinity < 66) + { + if ((parameter < 66) || is_tropical_area_by_latitude) + return df::enums::biome_type::biome_type::SWAMP_TROPICAL_FRESHWATER; // 7 + else + return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_FRESHWATER;// 3 + } + else // elevation between 100 and 149, vegetation >= 66, drainage < 33, salinity >= 66 + { + if ((parameter < 66) || is_tropical_area_by_latitude) + { + if (region.drainage < 10) + return df::enums::biome_type::biome_type::SWAMP_MANGROVE; //9 + else // drainage >= 10 + return df::enums::biome_type::biome_type::SWAMP_TROPICAL_SALTWATER; // 8 + } + else + return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_SALTWATER; // 4 + } + } + else // elevation between 100 and 149, vegetation >= 66, drainage < 33, not tropical area + { + if (region.salinity >= 66) + return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_SALTWATER; // 4 + else + return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_FRESHWATER; // 3 + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/biome_type.h b/plugins/embark-assistant/biome_type.h new file mode 100644 index 000000000..9ea562749 --- /dev/null +++ b/plugins/embark-assistant/biome_type.h @@ -0,0 +1,7 @@ +// world_coord_x/y is the location of the tile "owning" the biome, while world_ref_coord_y is the +// location of the tile the biome appears on. They differ when a mid level tile ("region tile") +// refers to a neighboring tile for the biome parameters. The difference can affect the tropicality +// determination. Since Tropicality is determined by latitude, the x coordinate of the reference is +// omitted. +// +int get_biome_type(int world_coord_x, int world_coord_y, int world_ref_coord_y); diff --git a/plugins/embark-assistant/defs.h b/plugins/embark-assistant/defs.h new file mode 100644 index 000000000..79ad5dd5b --- /dev/null +++ b/plugins/embark-assistant/defs.h @@ -0,0 +1,256 @@ +#pragma once + +#include +#include +#include + +using namespace std; +using std::array; +using std::ostringstream; +using std::string; +using std::vector; + +namespace embark_assist { + namespace defs { + // Survey types + // + enum class river_sizes { + None, + Brook, + Stream, + Minor, + Medium, + Major + }; + + struct mid_level_tile { + bool aquifer = false; + bool clay = false; + bool sand = false; + bool flux = false; + int8_t soil_depth; + int8_t offset; + int16_t elevation; + bool river_present = false; + int16_t river_elevation = 100; + int8_t biome_offset; + uint8_t savagery_level; // 0 - 2 + uint8_t evilness_level; // 0 - 2 + std::vector metals; + std::vector economics; + std::vector minerals; + }; + + typedef std::array, 16> mid_level_tiles; +// typedef mid_level_tile mid_level_tiles[16][16]; + + struct region_tile_datum { + bool surveyed = false; + uint16_t aquifer_count = 0; + uint16_t clay_count = 0; + uint16_t sand_count = 0; + uint16_t flux_count = 0; + uint8_t min_region_soil = 10; + uint8_t max_region_soil = 0; + bool waterfall = false; + + river_sizes river_size; + int16_t biome_index[10]; // Indexed through biome_offset; -1 = null, Index of region, [0] not used + int16_t biome[10]; // Indexed through biome_offset; -1 = null, df::biome_type, [0] not used + uint8_t biome_count; + bool evil_weather[10]; + bool evil_weather_possible; + bool evil_weather_full; + bool reanimating[10]; + bool reanimating_possible; + bool reanimating_full; + bool thralling[10]; + bool thralling_possible; + bool thralling_full; + uint16_t savagery_count[3]; + uint16_t evilness_count[3]; + std::vector metals; + std::vector economics; + std::vector minerals; + }; + + struct geo_datum { + uint8_t soil_size = 0; + bool top_soil_only = true; + bool top_soil_aquifer_only = true; + bool aquifer_absent = true; + bool clay_absent = true; + bool sand_absent = true; + bool flux_absent = true; + std::vector possible_metals; + std::vector possible_economics; + std::vector possible_minerals; + }; + + typedef std::vector geo_data; + + struct sites { + uint8_t x; + uint8_t y; + char type; + }; + + struct site_infos { + bool aquifer; + bool aquifer_full; + uint8_t min_soil; + uint8_t max_soil; + bool flat; + bool waterfall; + bool clay; + bool sand; + bool flux; + std::vector metals; + std::vector economics; + std::vector minerals; + // Could add savagery, evilness, and biomes, but DF provides those easily. + }; + + typedef std::vector site_lists; + + typedef std::vector> world_tile_data; + + typedef bool mlt_matches[16][16]; + // An embark region match is indicated by marking the top left corner + // tile as a match. Thus, the bottom and right side won't show matches + // unless the appropriate dimension has a width of 1. + + struct matches { + bool preliminary_match; + bool contains_match; + mlt_matches mlt_match; + }; + + typedef std::vector> match_results; + + // matcher types + // + enum class evil_savagery_values : int8_t { + NA = -1, + All, + Present, + Absent + }; + + enum class evil_savagery_ranges : int8_t { + Low, + Medium, + High + }; + + enum class aquifer_ranges : int8_t { + NA = -1, + All, + Present, + Partial, + Not_All, + Absent + }; + + enum class river_ranges : int8_t { + NA = -1, + None, + Brook, + Stream, + Minor, + Medium, + Major + }; + + enum class yes_no_ranges : int8_t { + NA = -1, + Yes, + No + }; + + enum class all_present_ranges : int8_t { + All, + Present + }; + enum class present_absent_ranges : int8_t { + NA = -1, + Present, + Absent + }; + + enum class soil_ranges : int8_t { + NA = -1, + None, + Very_Shallow, + Shallow, + Deep, + Very_Deep + }; + + /* // Future possible enhancement + enum class freezing_ranges : int8_t { + NA = -1, + Permanent, + At_Least_Partial, + Partial, + At_Most_Partial, + Never + }; + */ + + struct finders { + uint16_t x_dim; + uint16_t y_dim; + evil_savagery_values savagery[static_cast(evil_savagery_ranges::High) + 1]; + evil_savagery_values evilness[static_cast(evil_savagery_ranges::High) + 1]; + aquifer_ranges aquifer; + river_ranges min_river; + river_ranges max_river; + yes_no_ranges waterfall; + yes_no_ranges flat; + present_absent_ranges clay; + present_absent_ranges sand; + present_absent_ranges flux; + soil_ranges soil_min; + all_present_ranges soil_min_everywhere; + soil_ranges soil_max; + /*freezing_ranges freezing;*/ + yes_no_ranges evil_weather; // Will probably blow up with the magic release arcs... + yes_no_ranges reanimation; + yes_no_ranges thralling; + int8_t biome_count_min; // N/A(-1), 1-9 + int8_t biome_count_max; // N/A(-1), 1-9 + int8_t region_type_1; // N/A(-1), df::world_region_type + int8_t region_type_2; // N/A(-1), df::world_region_type + int8_t region_type_3; // N/A(-1), df::world_region_type + int8_t biome_1; // N/A(-1), df::biome_type + int8_t biome_2; // N/A(-1), df::biome_type + int8_t biome_3; // N/A(-1), df::biome_type + int16_t metal_1; // N/A(-1), 0-max_inorganic; + int16_t metal_2; // N/A(-1), 0-max_inorganic; + int16_t metal_3; // N/A(-1), 0-max_inorganic; + int16_t economic_1; // N/A(-1), 0-max_inorganic; + int16_t economic_2; // N/A(-1), 0-max_inorganic; + int16_t economic_3; // N/A(-1), 0-max_inorganic; + int16_t mineral_1; // N/A(-1), 0-max_inorganic; + int16_t mineral_2; // N/A(-1), 0-max_inorganic; + int16_t mineral_3; // N/A(-1), 0-max_inorganic; + }; + + struct match_iterators { + bool active; + uint16_t x; // x position of focus when iteration started so we can return it. + uint16_t y; // y + uint16_t i; + uint16_t k; + bool x_right; + bool y_down; + bool inhibit_x_turn; + bool inhibit_y_turn; + uint16_t count; + finders finder; + }; + + typedef void(*find_callbacks) (embark_assist::defs::finders finder); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/embark-assistant.cpp b/plugins/embark-assistant/embark-assistant.cpp new file mode 100644 index 000000000..283b696a0 --- /dev/null +++ b/plugins/embark-assistant/embark-assistant.cpp @@ -0,0 +1,296 @@ +#include "Core.h" +#include +#include +#include + +#include +#include +#include + +#include "DataDefs.h" +#include "df/coord2d.h" +#include "df/inorganic_flags.h" +#include "df/inorganic_raw.h" +#include "df/interfacest.h" +#include "df/viewscreen.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_geo_biome.h" +#include "df/world_raws.h" + +#include "defs.h" +#include "embark-assistant.h" +#include "finder_ui.h" +#include "matcher.h" +#include "overlay.h" +#include "survey.h" + +DFHACK_PLUGIN("embark-assistant"); + +using namespace DFHack; +using namespace df::enums; +using namespace Gui; + +REQUIRE_GLOBAL(world); + +namespace embark_assist { + namespace main { + struct states { + embark_assist::defs::geo_data geo_summary; + embark_assist::defs::world_tile_data survey_results; + embark_assist::defs::site_lists region_sites; + embark_assist::defs::site_infos site_info; + embark_assist::defs::match_results match_results; + embark_assist::defs::match_iterators match_iterator; + uint16_t max_inorganic; + }; + + static states *state = nullptr; + + void embark_update (); + void shutdown(); + + //=============================================================================== + + void embark_update() { + auto screen = Gui::getViewscreenByType(0); + embark_assist::defs::mid_level_tiles mlt; + embark_assist::survey::initiate(&mlt); + + embark_assist::survey::survey_mid_level_tile(&state->geo_summary, + &state->survey_results, + &mlt); + + embark_assist::survey::survey_embark(&mlt, &state->site_info, false); + embark_assist::overlay::set_embark(&state->site_info); + + embark_assist::survey::survey_region_sites(&state->region_sites); + embark_assist::overlay::set_sites(&state->region_sites); + + embark_assist::overlay::set_mid_level_tile_match(state->match_results.at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match); + } + + //=============================================================================== + + void match() { +// color_ostream_proxy out(Core::getInstance().getConsole()); + + uint16_t count = embark_assist::matcher::find(&state->match_iterator, + &state->geo_summary, + &state->survey_results, + &state->match_results); + + embark_assist::overlay::match_progress(count, &state->match_results, !state->match_iterator.active); + + if (!state->match_iterator.active) { + auto screen = Gui::getViewscreenByType(0); + embark_assist::overlay::set_mid_level_tile_match(state->match_results.at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match); + } + } + + //=============================================================================== + + void clear_match() { +// color_ostream_proxy out(Core::getInstance().getConsole()); + if (state->match_iterator.active) { + embark_assist::matcher::move_cursor(state->match_iterator.x, state->match_iterator.y); + } + embark_assist::survey::clear_results(&state->match_results); + embark_assist::overlay::clear_match_results(); + embark_assist::main::state->match_iterator.active = false; + } + + //=============================================================================== + + void find(embark_assist::defs::finders finder) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + + state->match_iterator.x = embark_assist::survey::get_last_pos().x; + state->match_iterator.y = embark_assist::survey::get_last_pos().y; + state->match_iterator.finder = finder; + embark_assist::overlay::initiate_match(); + } + + //=============================================================================== + + void shutdown() { +// color_ostream_proxy out(Core::getInstance().getConsole()); + embark_assist::survey::shutdown(); + embark_assist::finder_ui::shutdown(); + embark_assist::overlay::shutdown(); + delete state; + state = nullptr; + } + } +} + +//======================================================================================= + +command_result embark_assistant (color_ostream &out, std::vector & parameters); + +//======================================================================================= + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + commands.push_back(PluginCommand( + "embark-assistant", "Embark site selection support.", + embark_assistant, true, /* true means that the command can't be used from non-interactive user interface */ + // Extended help string. Used by CR_WRONG_USAGE and the help command: + " This command starts the embark-assist plugin that provides embark site\n" + " selection help. It has to be called while th pre embark screen is\n" + " displayed and shows extended (and correct(?)) resource information for\n" + " the embark rectangle as well as normally undisplayed sites in the\n" + " current embark region. It also has a site selection tool with more\n" + " options than DF's vanilla search tool. For detailed help invoke the\n" + " in game info screen. Requires 42 lines to display properly.\n" + )); + return CR_OK; +} + +//======================================================================================= + +DFhackCExport command_result plugin_shutdown (color_ostream &out) +{ + return CR_OK; +} + +//======================================================================================= + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) +{ + switch (event) { + case DFHack::SC_UNKNOWN: + break; + + case DFHack::SC_WORLD_LOADED: + break; + + case DFHack::SC_WORLD_UNLOADED: + case DFHack::SC_MAP_LOADED: + if (embark_assist::main::state) { + embark_assist::main::shutdown(); + } + break; + + case DFHack::SC_MAP_UNLOADED: + break; + + case DFHack::SC_VIEWSCREEN_CHANGED: + break; + + case DFHack::SC_CORE_INITIALIZED: + break; + + case DFHack::SC_BEGIN_UNLOAD: + break; + + case DFHack::SC_PAUSED: + break; + + case DFHack::SC_UNPAUSED: + break; + } + return CR_OK; +} + + +//======================================================================================= + +command_result embark_assistant(color_ostream &out, std::vector & parameters) +{ + if (!parameters.empty()) + return CR_WRONG_USAGE; + + CoreSuspender suspend; + + auto screen = Gui::getViewscreenByType(0); + if (!screen) { + out.printerr("This plugin works only in the embark site selection phase.\n"); + return CR_WRONG_USAGE; + } + + df::world_data *world_data = world->world_data; + + if (embark_assist::main::state) { + out.printerr("You can't invoke the embark assistant while it's already active.\n"); + return CR_WRONG_USAGE; + } + + embark_assist::main::state = new embark_assist::main::states; + + embark_assist::main::state->match_iterator.active = false; + + // Find the end of the normal inorganic definitions. + embark_assist::main::state->max_inorganic = 0; + for (uint16_t i = 0; i < world->raws.inorganics.size(); i++) { + if (world->raws.inorganics[i]->flags.is_set(df::inorganic_flags::GENERATED)) embark_assist::main::state->max_inorganic = i; + } + embark_assist::main::state->max_inorganic++; // To allow it to be used as size() replacement + + if (!embark_assist::overlay::setup(plugin_self, + embark_assist::main::embark_update, + embark_assist::main::match, + embark_assist::main::clear_match, + embark_assist::main::find, + embark_assist::main::shutdown, + embark_assist::main::state->max_inorganic)) { + return CR_FAILURE; + } + + embark_assist::survey::setup(embark_assist::main::state->max_inorganic); + embark_assist::main::state->geo_summary.resize(world_data->geo_biomes.size()); + embark_assist::main::state->survey_results.resize(world->worldgen.worldgen_parms.dim_x); + + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + embark_assist::main::state->survey_results[i].resize(world->worldgen.worldgen_parms.dim_y); + + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + embark_assist::main::state->survey_results[i][k].surveyed = false; + embark_assist::main::state->survey_results[i][k].aquifer_count = 0; + embark_assist::main::state->survey_results[i][k].clay_count = 0; + embark_assist::main::state->survey_results[i][k].sand_count = 0; + embark_assist::main::state->survey_results[i][k].flux_count = 0; + embark_assist::main::state->survey_results[i][k].min_region_soil = 10; + embark_assist::main::state->survey_results[i][k].max_region_soil = 0; + embark_assist::main::state->survey_results[i][k].waterfall = false; + embark_assist::main::state->survey_results[i][k].river_size = embark_assist::defs::river_sizes::None; + + for (uint8_t l = 1; l < 10; l++) { + embark_assist::main::state->survey_results[i][k].biome_index[l] = -1; + embark_assist::main::state->survey_results[i][k].biome[l] = -1; + embark_assist::main::state->survey_results[i][k].evil_weather[l] = false; + embark_assist::main::state->survey_results[i][k].reanimating[l] = false; + embark_assist::main::state->survey_results[i][k].thralling[l] = false; + } + + for (uint8_t l = 0; l < 2; l++) { + embark_assist::main::state->survey_results[i][k].savagery_count[l] = 0; + embark_assist::main::state->survey_results[i][k].evilness_count[l] = 0; + } + 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::survey::high_level_world_survey(&embark_assist::main::state->geo_summary, + &embark_assist::main::state->survey_results); + + embark_assist::main::state->match_results.resize(world->worldgen.worldgen_parms.dim_x); + + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + embark_assist::main::state->match_results[i].resize(world->worldgen.worldgen_parms.dim_y); + } + + embark_assist::survey::clear_results(&embark_assist::main::state->match_results); + embark_assist::survey::survey_region_sites(&embark_assist::main::state->region_sites); + embark_assist::overlay::set_sites(&embark_assist::main::state->region_sites); + + 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::overlay::set_embark(&embark_assist::main::state->site_info); + + return CR_OK; +} diff --git a/plugins/embark-assistant/embark-assistant.h b/plugins/embark-assistant/embark-assistant.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/plugins/embark-assistant/embark-assistant.h @@ -0,0 +1 @@ +#pragma once diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp new file mode 100644 index 000000000..3ebaa9e0f --- /dev/null +++ b/plugins/embark-assistant/finder_ui.cpp @@ -0,0 +1,1143 @@ +#include "Core.h" +#include + +#include + +#include "Types.h" + +#include "df/biome_type.h" +#include "df/inorganic_raw.h" +#include "df/material_flags.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_region_type.h" +#include "df/world_raws.h" + +#include "embark-assistant.h" +#include "finder_ui.h" +#include "screen.h" + +using df::global::world; + +namespace embark_assist { + namespace finder_ui { + + enum class fields : int8_t { + x_dim, + y_dim, + savagery_calm, + savagery_medium, + savagery_savage, + good, + neutral, + evil, + aquifer, + min_river, + max_river, + waterfall, + flat, + clay, + sand, + flux, + soil_min, + soil_min_everywhere, + soil_max, + evil_weather, + reanimation, + thralling, + biome_count_min, + biome_count_max, + region_type_1, + region_type_2, + region_type_3, + biome_1, + biome_2, + biome_3, + metal_1, + metal_2, + metal_3, + economic_1, + economic_2, + economic_3, + mineral_1, + mineral_2, + mineral_3 + }; + fields first_fields = fields::x_dim; + fields last_fields = fields::mineral_3; + + struct display_map_elements { + std::string text; + int16_t key; + }; + + typedef std::vector display_maps; + typedef std::vector name_lists; + typedef std::list< display_map_elements> sort_lists; + + struct ui_lists { + uint16_t current_display_value; // Not the value itself, but a reference to its index. + int16_t current_value; // The integer representation of the value (if an enum). + uint16_t current_index; // What's selected + uint16_t focus; // The value under the (possibly inactive) cursor + display_maps list; // The strings to be displayed together with keys + // to allow location of the actual elements (e.g. a raws.inorganics mat_index + // or underlying enum value). + }; + + typedef std::vector uis; + + const DFHack::Screen::Pen active_pen(' ', COLOR_YELLOW); + const DFHack::Screen::Pen passive_pen(' ', COLOR_DARKGREY); + const DFHack::Screen::Pen normal_pen(' ', COLOR_GREY); + const DFHack::Screen::Pen white_pen(' ', COLOR_WHITE); + const DFHack::Screen::Pen lr_pen(' ', COLOR_LIGHTRED); + + //========================================================================================================== + + struct states { + embark_assist::defs::find_callbacks find_callback; + uis ui; + display_maps finder_list; // Don't need the element key, but it's easier to use the same type. + uint16_t finder_list_focus; + bool finder_list_active; + uint16_t max_inorganic; + }; + + static states *state = 0; + + //========================================================================================================== + + bool compare(const display_map_elements& first, const display_map_elements& second) { + uint16_t i = 0; + while (i < first.text.length() && i < second.text.length()) { + if (first.text[i] < second.text[i]) { + return true; + } + else if (first.text[i] > second.text[i]) { + return false; + } + ++i; + } + return first.text.length() < second.text.length(); + } + + //========================================================================================================== + + void append(sort_lists *sort_list, display_map_elements element) { + sort_lists::iterator iterator; + for (iterator = sort_list->begin(); iterator != sort_list->end(); ++iterator) { + if (iterator->key == element.key) { + return; + } + } + sort_list->push_back(element); + } + + //========================================================================================================== + + void ui_setup(embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + if (!embark_assist::finder_ui::state) { + state = new(states); + state->finder_list_focus = 0; + state->finder_list_active = true; + state->find_callback = find_callback; + state->max_inorganic = max_inorganic; + } + + fields i = first_fields; + ui_lists *element; + + while (true) { + element = new ui_lists; + element->current_display_value = 0; + element->current_index = 0; + element->focus = 0; + + switch (i) { + case fields::x_dim: + for (int16_t k = 1; k < 16; k++) { + element->list.push_back({ std::to_string(k), k }); + } + + break; + + case fields::y_dim: + for (int16_t k = 1; k < 16; k++) { + element->list.push_back({ std::to_string(k), k }); + } + + break; + + case fields::savagery_calm: + case fields::savagery_medium: + case fields::savagery_savage: + case fields::good: + case fields::neutral: + case fields::evil: + { + embark_assist::defs::evil_savagery_values k = embark_assist::defs::evil_savagery_values::NA; + while (true) { + switch (k) { + case embark_assist::defs::evil_savagery_values::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::evil_savagery_values::All: + element->list.push_back({ "All", static_cast(k) }); + break; + + case embark_assist::defs::evil_savagery_values::Present: + element->list.push_back({ "Present", static_cast(k) }); + break; + + case embark_assist::defs::evil_savagery_values::Absent: + element->list.push_back({ "Absent", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::evil_savagery_values::Absent) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::aquifer: + { + embark_assist::defs::aquifer_ranges k = embark_assist::defs::aquifer_ranges::NA; + while (true) { + switch (k) { + case embark_assist::defs::aquifer_ranges::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::aquifer_ranges::All: + element->list.push_back({ "All", static_cast(k) }); + break; + + case embark_assist::defs::aquifer_ranges::Present: + element->list.push_back({ "Present", static_cast(k) }); + break; + + case embark_assist::defs::aquifer_ranges::Partial: + element->list.push_back({ "Partial", static_cast(k) }); + break; + + case embark_assist::defs::aquifer_ranges::Not_All: + element->list.push_back({ "Not All", static_cast(k) }); + break; + + case embark_assist::defs::aquifer_ranges::Absent: + element->list.push_back({ "Absent", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::aquifer_ranges::Absent) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::min_river: + case fields::max_river: + { + embark_assist::defs::river_ranges k = embark_assist::defs::river_ranges::NA; + while (true) { + switch (k) { + case embark_assist::defs::river_ranges::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::None: + element->list.push_back({ "None", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::Brook: + element->list.push_back({ "Brook", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::Stream: + element->list.push_back({ "Stream", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::Minor: + element->list.push_back({ "Minor", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::Medium: + element->list.push_back({ "Medium", static_cast(k) }); + break; + + case embark_assist::defs::river_ranges::Major: + element->list.push_back({ "Major", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::river_ranges::Major) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::waterfall: + case fields::flat: + case fields::evil_weather: + case fields::reanimation: + case fields::thralling: + { + embark_assist::defs::yes_no_ranges k = embark_assist::defs::yes_no_ranges::NA; + while (true) { + switch (k) { + case embark_assist::defs::yes_no_ranges::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::yes_no_ranges::Yes: + element->list.push_back({ "Yes", static_cast(k) }); + break; + + case embark_assist::defs::yes_no_ranges::No: + element->list.push_back({ "No", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::yes_no_ranges::No) { + 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; + while (true) { + switch (k) { + case embark_assist::defs::all_present_ranges::All: + element->list.push_back({ "All", static_cast(k) }); + break; + + case embark_assist::defs::all_present_ranges::Present: + element->list.push_back({ "Present", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::all_present_ranges::Present) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::clay: + case fields::sand: + case fields::flux: + { + embark_assist::defs::present_absent_ranges k = embark_assist::defs::present_absent_ranges::NA; + while (true) { + switch (k) { + case embark_assist::defs::present_absent_ranges::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::present_absent_ranges::Present: + element->list.push_back({ "Present", static_cast(k) }); + break; + + case embark_assist::defs::present_absent_ranges::Absent: + element->list.push_back({ "Absent", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::present_absent_ranges::Absent) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::soil_min: + case fields::soil_max: + { + embark_assist::defs::soil_ranges k = embark_assist::defs::soil_ranges::NA; + while (true) { + switch (k) { + case embark_assist::defs::soil_ranges::NA: + element->list.push_back({ "N/A", static_cast(k) }); + break; + + case embark_assist::defs::soil_ranges::None: + element->list.push_back({ "None", static_cast(k) }); + break; + + case embark_assist::defs::soil_ranges::Very_Shallow: + element->list.push_back({ "Very Shallow", static_cast(k) }); + break; + + case embark_assist::defs::soil_ranges::Shallow: + element->list.push_back({ "Shallow", static_cast(k) }); + break; + + case embark_assist::defs::soil_ranges::Deep: + element->list.push_back({ "Deep", static_cast(k) }); + break; + + case embark_assist::defs::soil_ranges::Very_Deep: + element->list.push_back({ "Very Deep", static_cast(k) }); + break; + } + + if (k == embark_assist::defs::soil_ranges::Very_Deep) { + break; + } + + k = static_cast (static_cast(k) + 1); + } + } + + break; + + case fields::biome_count_min: + case fields::biome_count_max: + for (int16_t k = 0; k < 10; k++) { + if (k == 0) { + element->list.push_back({ "N/A", -1 }); + } + else { + element->list.push_back({ std::to_string(k), k }); + } + } + + break; + + case fields::region_type_1: + case fields::region_type_2: + case fields::region_type_3: + { + std::list name; + std::list::iterator iterator; + + FOR_ENUM_ITEMS(world_region_type, iter) { + name.push_back({ ENUM_KEY_STR(world_region_type, iter), static_cast(iter) }); + } + name.sort(compare); + + element->list.push_back({ "N/A", -1 }); + + for (iterator = name.begin(); iterator != name.end(); ++iterator) { + element->list.push_back({ iterator->text, iterator->key }); + } + + name.clear(); + } + break; + + case fields::biome_1: + case fields::biome_2: + case fields::biome_3: + { + sort_lists name; + sort_lists::iterator iterator; + + FOR_ENUM_ITEMS(biome_type, iter) { + std::string s = ENUM_KEY_STR(biome_type, iter); + + if (s.substr(0, 4) != "POOL" && + s.substr(0, 5) != "RIVER" && + s.substr(0, 3) != "SUB") { + name.push_back({ s, static_cast(iter) }); + } + } + name.sort(compare); + + element->list.push_back({ "N/A", -1 }); + + for (iterator = name.begin(); iterator != name.end(); ++iterator) { + element->list.push_back({ iterator->text, iterator->key }); + } + + name.clear(); + } + break; + + case fields::metal_1: + case fields::metal_2: + case fields::metal_3: + { + sort_lists name; + sort_lists::iterator iterator; + + for (uint16_t k = 0; k < embark_assist::finder_ui::state->max_inorganic; k++) { + for (uint16_t l = 0; l < world->raws.inorganics[k]->metal_ore.mat_index.size(); l++) { + append(&name, { world->raws.inorganics[world->raws.inorganics[k]->metal_ore.mat_index[l]]->id, + world->raws.inorganics[k]->metal_ore.mat_index[l] }); + } + } + + name.sort(compare); + + element->list.push_back({ "N/A", -1 }); + + for (iterator = name.begin(); iterator != name.end(); ++iterator) { + element->list.push_back({ iterator->text, iterator->key }); + } + + name.clear(); + } + break; + + case fields::economic_1: + case fields::economic_2: + case fields::economic_3: + { + sort_lists name; + sort_lists::iterator iterator; + + for (int16_t k = 0; k < embark_assist::finder_ui::state->max_inorganic; k++) { + if (world->raws.inorganics[k]->economic_uses.size() != 0 && + !world->raws.inorganics[k]->material.flags.is_set(df::material_flags::IS_METAL)) { + append(&name, { world->raws.inorganics[k]->id, k }); + } + } + + name.sort(compare); + + element->list.push_back({ "N/A", -1 }); + + for (iterator = name.begin(); iterator != name.end(); ++iterator) { + element->list.push_back({ iterator->text, iterator->key }); + } + + name.clear(); + } + break; + + case fields::mineral_1: + case fields::mineral_2: + case fields::mineral_3: + { + sort_lists name; + sort_lists::iterator iterator; + + for (int16_t k = 0; k < embark_assist::finder_ui::state->max_inorganic; k++) { + if (world->raws.inorganics[k]->environment.location.size() != 0 || + world->raws.inorganics[k]->environment_spec.mat_index.size() != 0 || + world->raws.inorganics[k]->flags.is_set(df::inorganic_flags::SEDIMENTARY) || + world->raws.inorganics[k]->flags.is_set(df::inorganic_flags::IGNEOUS_EXTRUSIVE) || + world->raws.inorganics[k]->flags.is_set(df::inorganic_flags::IGNEOUS_INTRUSIVE) || + world->raws.inorganics[k]->flags.is_set(df::inorganic_flags::METAMORPHIC) || + world->raws.inorganics[k]->flags.is_set(df::inorganic_flags::SOIL)) { + append(&name, { world->raws.inorganics[k]->id, k }); + } + } + + name.sort(compare); + + element->list.push_back({ "N/A", -1 }); + + for (iterator = name.begin(); iterator != name.end(); ++iterator) { + element->list.push_back({ iterator->text, iterator->key }); + } + + name.clear(); + } + break; + } + + element->current_value = element->list[0].key; + + state->ui.push_back(element); + + switch (i) { + case fields::x_dim: + state->finder_list.push_back({ "X Dimension", static_cast(i) }); + break; + + case fields::y_dim: + state->finder_list.push_back({ "Y Dimension", static_cast(i) }); + break; + + case fields::savagery_calm: + state->finder_list.push_back({ "Low Savagery", static_cast(i) }); + break; + + case fields::savagery_medium: + state->finder_list.push_back({ "Medium Savagery", static_cast(i) }); + break; + + case fields::savagery_savage: + state->finder_list.push_back({ "High Savagery", static_cast(i) }); + break; + + case fields::good: + state->finder_list.push_back({ "Good", static_cast(i) }); + break; + + case fields::neutral: + state->finder_list.push_back({ "Neutral", static_cast(i) }); + break; + + case fields::evil: + state->finder_list.push_back({ "Evil", static_cast(i) }); + break; + + case fields::aquifer: + state->finder_list.push_back({ "Aquifer", static_cast(i) }); + break; + + case fields::min_river: + state->finder_list.push_back({ "Min River", static_cast(i) }); + break; + + case fields::max_river: + state->finder_list.push_back({ "Max River", static_cast(i) }); + break; + + case fields::waterfall: + state->finder_list.push_back({ "Waterfall", static_cast(i) }); + break; + + case fields::flat: + state->finder_list.push_back({ "Flat", static_cast(i) }); + break; + + case fields::soil_min_everywhere: + state->finder_list.push_back({ "Min Soil Everywhere", static_cast(i) }); + break; + + case fields::evil_weather: + state->finder_list.push_back({ "Evil Weather", static_cast(i) }); + break; + + case fields::reanimation: + state->finder_list.push_back({ "Reanimation", static_cast(i) }); + break; + + case fields::thralling: + state->finder_list.push_back({ "Thralling", static_cast(i) }); + break; + + case fields::clay: + state->finder_list.push_back({ "Clay", static_cast(i) }); + break; + + case fields::sand: + state->finder_list.push_back({ "Sand", static_cast(i) }); + break; + + case fields::flux: + state->finder_list.push_back({ "Flux", static_cast(i) }); + break; + + case fields::soil_min: + state->finder_list.push_back({ "Min Soil", static_cast(i) }); + break; + + case fields::soil_max: + state->finder_list.push_back({ "Max Soil", static_cast(i) }); + break; + + case fields::biome_count_min: + state->finder_list.push_back({ "Min Biome Count", static_cast(i) }); + break; + + case fields::biome_count_max: + state->finder_list.push_back({ "Max Biome Count", static_cast(i) }); + break; + + case fields::region_type_1: + state->finder_list.push_back({ "Region Type 1", static_cast(i) }); + break; + + case fields::region_type_2: + state->finder_list.push_back({ "Region Type 2", static_cast(i) }); + break; + + case fields::region_type_3: + state->finder_list.push_back({ "Region Type 3", static_cast(i) }); + break; + + case fields::biome_1: + state->finder_list.push_back({ "Biome 1", static_cast(i) }); + break; + + case fields::biome_2: + state->finder_list.push_back({ "Biome 2", static_cast(i) }); + break; + + case fields::biome_3: + state->finder_list.push_back({ "Biome 3", static_cast(i) }); + break; + + case fields::metal_1: + state->finder_list.push_back({ "Metal 1", static_cast(i) }); + break; + + case fields::metal_2: + state->finder_list.push_back({ "Metal 2", static_cast(i) }); + break; + + case fields::metal_3: + state->finder_list.push_back({ "Metal 3", static_cast(i) }); + break; + + case fields::economic_1: + state->finder_list.push_back({ "Economic 1", static_cast(i) }); + break; + + case fields::economic_2: + state->finder_list.push_back({ "Economic 2", static_cast(i) }); + break; + + case fields::economic_3: + state->finder_list.push_back({ "Economic 3", static_cast(i) }); + break; + + case fields::mineral_1: + state->finder_list.push_back({ "Mineral 1", static_cast(i) }); + break; + + case fields::mineral_2: + state->finder_list.push_back({ "Mineral 2", static_cast(i) }); + break; + + case fields::mineral_3: + state->finder_list.push_back({ "Mineral 3", static_cast(i) }); + break; + } + + if (i == last_fields) { + break; // done + } + + i = static_cast (static_cast(i) + 1); + } + + // Default embark area size to that of the current selection. The "size" calculation is actually one + // off to compensate for the list starting with 1 at index 0. + // + auto screen = Gui::getViewscreenByType(0); + int16_t x = screen->location.region_pos.x; + int16_t y = screen->location.region_pos.y; + state->ui[static_cast(fields::x_dim)]->current_display_value = + Gui::getViewscreenByType(0)->location.embark_pos_max.x - + Gui::getViewscreenByType(0)->location.embark_pos_min.x; + state->ui[static_cast(fields::x_dim)]->current_index = + state->ui[static_cast(fields::x_dim)]->current_display_value; + state->ui[static_cast(fields::x_dim)]->current_value = + state->ui[static_cast(fields::x_dim)]->current_display_value + 1; + + state->ui[static_cast(fields::y_dim)]->current_display_value = + Gui::getViewscreenByType(0)->location.embark_pos_max.y - + Gui::getViewscreenByType(0)->location.embark_pos_min.y; + state->ui[static_cast(fields::y_dim)]->current_index = + state->ui[static_cast(fields::y_dim)]->current_display_value; + state->ui[static_cast(fields::y_dim)]->current_value = + state->ui[static_cast(fields::y_dim)]->current_display_value + 1; + } + + + //========================================================================================================== + + void find() { +// color_ostream_proxy out(Core::getInstance().getConsole()); + embark_assist::defs::finders finder; + fields i = first_fields; + + while (true) { + switch (i) { + case fields::x_dim: + finder.x_dim = state->ui[static_cast(i)]->current_value; + break; + + case fields::y_dim: + finder.y_dim = state->ui[static_cast(i)]->current_value; + break; + + case fields::savagery_calm: + finder.savagery[0] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::savagery_medium: + finder.savagery[1] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + case fields::savagery_savage: + finder.savagery[2] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::good: + finder.evilness[0] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::neutral: + finder.evilness[1] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::evil: + finder.evilness[2] = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::aquifer: + finder.aquifer = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::min_river: + finder.min_river = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::max_river: + finder.max_river = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::waterfall: + finder.waterfall = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::flat: + finder.flat = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::soil_min_everywhere: + finder.soil_min_everywhere = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::evil_weather: + finder.evil_weather = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::reanimation: + finder.reanimation = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::thralling: + finder.thralling = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::clay: + finder.clay = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::sand: + finder.sand = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::flux: + finder.flux = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::soil_min: + finder.soil_min = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::soil_max: + finder.soil_max = + static_cast(state->ui[static_cast(i)]->current_value); + break; + + case fields::biome_count_min: + finder.biome_count_min = state->ui[static_cast(i)]->current_value; + break; + + case fields::biome_count_max: + finder.biome_count_max = state->ui[static_cast(i)]->current_value; + break; + + case fields::region_type_1: + finder.region_type_1 = state->ui[static_cast(i)]->current_value; + break; + + case fields::region_type_2: + finder.region_type_2 = state->ui[static_cast(i)]->current_value; + break; + + case fields::region_type_3: + finder.region_type_3 = state->ui[static_cast(i)]->current_value; + break; + + case fields::biome_1: + finder.biome_1 = state->ui[static_cast(i)]->current_value; + break; + + case fields::biome_2: + finder.biome_2 = state->ui[static_cast(i)]->current_value; + break; + + case fields::biome_3: + finder.biome_3 = state->ui[static_cast(i)]->current_value; + break; + + case fields::metal_1: + finder.metal_1 = state->ui[static_cast(i)]->current_value; + break; + + case fields::metal_2: + finder.metal_2 = state->ui[static_cast(i)]->current_value; + break; + + case fields::metal_3: + finder.metal_3 = state->ui[static_cast(i)]->current_value; + break; + + case fields::economic_1: + finder.economic_1 = state->ui[static_cast(i)]->current_value; + break; + + case fields::economic_2: + finder.economic_2 = state->ui[static_cast(i)]->current_value; + break; + + case fields::economic_3: + finder.economic_3 = state->ui[static_cast(i)]->current_value; + break; + + case fields::mineral_1: + finder.mineral_1 = state->ui[static_cast(i)]->current_value; + break; + + case fields::mineral_2: + finder.mineral_2 = state->ui[static_cast(i)]->current_value; + break; + + case fields::mineral_3: + finder.mineral_3 = state->ui[static_cast(i)]->current_value; + break; + } + + if (i == last_fields) { + break; // done + } + + i = static_cast (static_cast(i) + 1); + } + + state->find_callback(finder); + } + + //========================================================================================================== + + class ViewscreenFindUi : public dfhack_viewscreen + { + public: + ViewscreenFindUi::ViewscreenFindUi(); + + void feed(std::set *input); + + void render(); + + std::string getFocusString() { return "Finder UI"; } + + private: + }; + + //=============================================================================== + + void ViewscreenFindUi::feed(std::set *input) { + if (input->count(df::interface_key::LEAVESCREEN)) + { + input->clear(); + Screen::dismiss(this); + return; + + } else if (input->count(df::interface_key::CURSOR_LEFT) || + input->count(df::interface_key::CURSOR_RIGHT)) { + state->finder_list_active = !state->finder_list_active; + + } else if (input->count(df::interface_key::CURSOR_UP)) { + if (state->finder_list_active) { + if (state->finder_list_focus > 0) { + state->finder_list_focus--; + } + else { + state->finder_list_focus = static_cast(last_fields); + } + } + else { + if (state->ui[state->finder_list_focus]->current_index > 0) { + state->ui[state->finder_list_focus]->current_index--; + } else { + state->ui[state->finder_list_focus]->current_index = static_cast(state->ui[state->finder_list_focus]->list.size()) - 1; + } + } + + } else if (input->count(df::interface_key::CURSOR_DOWN)) { + if (state->finder_list_active) { + if (state->finder_list_focus < static_cast(last_fields)) { + state->finder_list_focus++; + } else { + state->finder_list_focus = 0; + } + } + else { + if (state->ui[state->finder_list_focus]->current_index < state->ui[state->finder_list_focus]->list.size() - 1) { + state->ui[state->finder_list_focus]->current_index++; + } else { + state->ui[state->finder_list_focus]->current_index = 0; + } + } + } else if (input->count(df::interface_key::SELECT)) { + if (!state->finder_list_active) { + state->ui[state->finder_list_focus]->current_display_value = state->ui[state->finder_list_focus]->current_index; + state->ui[state->finder_list_focus]->current_value = state->ui[state->finder_list_focus]->list[state->ui[state->finder_list_focus]->current_index].key; + state->finder_list_active = true; + } + } else if (input->count(df::interface_key::CUSTOM_F)) { + input->clear(); + Screen::dismiss(this); + find(); + return; + } + } + + //=============================================================================== + + void ViewscreenFindUi::render() { +// color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen_size = DFHack::Screen::getWindowSize(); + const int list_column = 53; + uint16_t offset = 0; + + Screen::clear(); + Screen::drawBorder("Embark Assistant Site Finder"); + + embark_assist::screen::paintString(lr_pen, 1, 1, "4/6"); + embark_assist::screen::paintString(white_pen, 4, 1, ":Shift list"); + embark_assist::screen::paintString(lr_pen, 16, 1, "8/2"); + embark_assist::screen::paintString(white_pen, 19, 1, ":Up/down"); + embark_assist::screen::paintString(lr_pen, 28, 1, "ENTER"); + embark_assist::screen::paintString(white_pen, 33, 1, ":Select item"); + embark_assist::screen::paintString(lr_pen, 46, 1, "f"); + embark_assist::screen::paintString(white_pen, 47, 1, ":Find"); + embark_assist::screen::paintString(lr_pen, 53, 1, "ESC"); + embark_assist::screen::paintString(white_pen, 56, 1, ":Abort"); + + for (uint16_t i = 0; i < state->finder_list.size(); i++) { + if (i == state->finder_list_focus) { + if (state->finder_list_active) { + embark_assist::screen::paintString(active_pen, 1, 2 + i, state->finder_list[i].text); + } + else { + embark_assist::screen::paintString(passive_pen, 1, 2 + i, state->finder_list[i].text); + } + + embark_assist::screen::paintString(active_pen, + 21, + 2 + i, + state->ui[i]->list[state->ui[i]->current_display_value].text); + } + else { + embark_assist::screen::paintString(normal_pen, 1, 2 + i, state->finder_list[i].text); + + embark_assist::screen::paintString(white_pen, + 21, + 2 + i, + state->ui[i]->list[state->ui[i]->current_display_value].text); + } + + } + + // Implement scrolling lists if they don't fit on the screen. + if (state->ui[state->finder_list_focus]->list.size() > screen_size.y - 3) { + offset = (screen_size.y - 3) / 2; + if (state->ui[state->finder_list_focus]->current_index < offset) { + offset = 0; + } + else { + offset = state->ui[state->finder_list_focus]->current_index - offset; + } + + if (state->ui[state->finder_list_focus]->list.size() - offset < screen_size.y - 3) { + offset = static_cast(state->ui[state->finder_list_focus]->list.size()) - (screen_size.y - 3); + } + } + + for (uint16_t i = 0; i < state->ui[state->finder_list_focus]->list.size(); i++) { + if (i == state->ui[state->finder_list_focus]->current_index) { + if (!state->finder_list_active) { // Negated expression to get the display lines in the same order as above. + embark_assist::screen::paintString(active_pen, list_column, 2 + i - offset, state->ui[state->finder_list_focus]->list[i].text); + } + else { + embark_assist::screen::paintString(passive_pen, list_column, 2 + i - offset, state->ui[state->finder_list_focus]->list[i].text); + } + } + else { + embark_assist::screen::paintString(normal_pen, list_column, 2 + i - offset, state->ui[state->finder_list_focus]->list[i].text); + } + } + + dfhack_viewscreen::render(); + } + + //=============================================================================== + + ViewscreenFindUi::ViewscreenFindUi() { + } + + //=============================================================================== + + void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { + if (!state) { // First call. Have to do the setup + ui_setup(find_callback, max_inorganic); + } + Screen::show(new ViewscreenFindUi(), plugin_self); + } + + //=============================================================================== + + void embark_assist::finder_ui::activate() { + } + + //=============================================================================== + + void embark_assist::finder_ui::shutdown() { + if (embark_assist::finder_ui::state) { + for (uint16_t i = 0; i < state->ui.size(); i++) { + delete state->ui[i]; + } + + delete state; + state = nullptr; + } + } + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/finder_ui.h b/plugins/embark-assistant/finder_ui.h new file mode 100644 index 000000000..70bf4ce42 --- /dev/null +++ b/plugins/embark-assistant/finder_ui.h @@ -0,0 +1,17 @@ +#pragma once + +#include "PluginManager.h" + +#include "DataDefs.h" + +#include "defs.h" + +using namespace DFHack; + +namespace embark_assist { + namespace finder_ui { + void init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic); + void activate(); + void shutdown(); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp new file mode 100644 index 000000000..e1830883a --- /dev/null +++ b/plugins/embark-assistant/help_ui.cpp @@ -0,0 +1,314 @@ +#include "Core.h" +#include + +#include +#include +#include + +#include "Types.h" + +#include "help_ui.h" +#include "screen.h" + +using std::vector; + +namespace embark_assist{ + namespace help_ui { + enum class pages { + Intro, + General, + Finder, + Caveats + }; + + class ViewscreenHelpUi : public dfhack_viewscreen + { + public: + ViewscreenHelpUi::ViewscreenHelpUi(); + + void feed(std::set *input); + + void render(); + + std::string getFocusString() { return "Help UI"; } + + private: + pages current_page = pages::Intro; + }; + + //=============================================================================== + + void ViewscreenHelpUi::feed(std::set *input) { + if (input->count(df::interface_key::LEAVESCREEN)) + { + input->clear(); + Screen::dismiss(this); + return; + } + else if (input->count(df::interface_key::CHANGETAB)) { + switch (current_page) { + case pages::Intro: + current_page = pages::General; + break; + + case pages::General: + current_page = pages::Finder; + break; + + case pages::Finder: + current_page = pages::Caveats; + break; + + case pages::Caveats: + current_page = pages::Intro; + break; + } + } + else if (input->count(df::interface_key::SEC_CHANGETAB)) { + switch (current_page) { + case pages::Intro: + current_page = pages::Caveats; + break; + + case pages::General: + current_page = pages::Intro; + break; + + case pages::Finder: + current_page = pages::General; + break; + + case pages::Caveats: + current_page = pages::Intro; + break; + } + } + } + + //=============================================================================== + + void ViewscreenHelpUi::render() { + color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen_size = DFHack::Screen::getWindowSize(); + Screen::Pen pen(' ', COLOR_WHITE); + Screen::Pen site_pen = Screen::Pen(' ', COLOR_YELLOW, COLOR_BLACK, false); + Screen::Pen pen_lr(' ', COLOR_LIGHTRED); + + std::vector help_text; + + Screen::clear(); + + switch (current_page) { + case pages::Intro: + Screen::drawBorder("Embark Assistant Help/Info Introduction Page"); + + help_text.push_back("Embark Assistant is used on the embark selection screen to provide information"); + help_text.push_back("to help selecting a suitable embark site. It provides three services:"); + help_text.push_back("- Display of normally invisible sites overlayed on the region map."); + help_text.push_back("- Embark rectangle resources. More detailed and correct than vanilla DF."); + help_text.push_back("- Site find search. Richer set of selection criteria than the vanilla"); + help_text.push_back(" DF Find that Embark Assistant suppresses (by using the same key)."); + help_text.push_back(""); + help_text.push_back("The functionality requires a screen height of at least 42 lines to display"); + help_text.push_back("correctly (that's the height of the Finder screen), as fitting everything"); + help_text.push_back("onto a standard 80*25 screen would be too challenging. The help is adjusted"); + help_text.push_back("to fit into onto an 80*42 screen."); + help_text.push_back("This help/info is split over several screens, and you can move between them"); + help_text.push_back("using the TAB/Shift-TAB keys, and leave the help from any screen using ESC."); + help_text.push_back(""); + help_text.push_back("When the Embark Assistant is started it provides site information (if any)"); + help_text.push_back("as an overlay over the region map. Beneath that you will find a summary of"); + help_text.push_back("the resources in the current embark rectangle (explained in more detail on"); + help_text.push_back("the the next screen)."); + help_text.push_back("On the right side the command keys the Embark Assistant uses are listed"); + help_text.push_back("(this partially overwrites the DFHack Embark Tools information until the"); + help_text.push_back("screen is resized). It can also be mentioned that the DF 'f'ind key help"); + help_text.push_back("at the bottom of the screen is masked as the functionality is overridden by"); + help_text.push_back("the Embark Assistant."); + help_text.push_back("Main screen control keys used by the Embark Assistant:"); + help_text.push_back("i: Info/Help. Brings up this display."); + help_text.push_back("f: Brings up the Find Embark screen. See the Find page for more information."); + help_text.push_back("c: Clears the results of a Find operation, and also cancels an operation if"); + help_text.push_back(" one is under way."); + help_text.push_back("q: Quits the Embark Assistant and brings you back to the vanilla DF interface."); + help_text.push_back(" It can be noted that the Embark Assistant automatically cancels itself"); + help_text.push_back(" when DF leaves the embark screen either through Abort Game or by"); + 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."); + + break; + + case pages::General: + Screen::drawBorder("Embark Assistant Help/Info General Page"); + + help_text.push_back("The Embark Assistant overlays the region map with characters indicating sites"); + help_text.push_back("normally not displayed by DF. The following key is used:"); + help_text.push_back("C: Camp"); + help_text.push_back("c: Cave. Only displayed if the DF worldgen parameter does not display caves."); + help_text.push_back("i: Important Location. The author doesn't actually know what those are."); + help_text.push_back("l: Lair"); + help_text.push_back("L: Labyrinth"); + help_text.push_back("M: Monument. The author is unsure how/if this is broken down further."); + help_text.push_back("S: Shrine"); + help_text.push_back("V: Vault"); + help_text.push_back("The Embark info below the region map differs from the vanilla DF display in a"); + help_text.push_back("few respects. Firstly, it shows resources in the embark rectangle, rather than"); + 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("The info the Embark Assistant displays is:"); + help_text.push_back("Sand, if present"); + help_text.push_back("Clay, if present"); + help_text.push_back("Min and Max soil depth in the embark rectangle."); + help_text.push_back("Flat indicator if all the tiles in the embark have the same elevation."); + help_text.push_back("Aquifer indicator, color coded as blue if all tiles have an aquifer and light"); + help_text.push_back("blue if some, but not all, tiles have one."); + help_text.push_back("Waterfall, if the embark has river elevation differences."); + help_text.push_back("Flux, if present"); + help_text.push_back("A list of all metals present in the embark."); + help_text.push_back("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("In addition to the above, the Find functionality can also produce blinking"); + help_text.push_back("overlays over the region map and the middle world map to indicate where"); + help_text.push_back("matching embarks are found. The region display marks the top left corner of"); + help_text.push_back("a matching embark rectangle as a matching tile."); + + break; + + case pages::Finder: + Screen::drawBorder("Embark Assistant Help/Info Find Page"); + + help_text.push_back("The Embark Assist Finder page is brought up with the f command key."); + help_text.push_back("The top of the Finder page lists the command keys available on the page:"); + help_text.push_back("4/6 or horizontal arrow keys to move between the element and element values."); + help_text.push_back("8/2 or vertical arrow keys to move up/down in the current list."); + help_text.push_back("ENTER to select a value in the value list, entering it among the selections."); + help_text.push_back("f to activate the Find functionality using the values in the middle column."); + help_text.push_back("ESC to leave the screen without activating a Find operation."); + help_text.push_back("The X and Y dimensions are those of the embark to search for. Unlike DF"); + help_text.push_back("itself these parameters are initiated to match the actual embark rectangle"); + help_text.push_back("when a new search is initiated (prior results are cleared."); + help_text.push_back("The 6 Savagery and Evilness parameters takes some getting used to. They"); + help_text.push_back("allow for searching for embarks with e.g. has both Good and Evil tiles."); + help_text.push_back("All as a parameter means every embark tile has to have this value."); + help_text.push_back("Present means at least one embark tile has to have this value."); + help_text.push_back("Absent means the feature mustn't exist in any of the embark tiles."); + help_text.push_back("N/A means no restrictions are applied."); + help_text.push_back("The Aquifer criterion introduces some new parameters:"); + help_text.push_back("Partial means at least one tile has to have an aquifer, but it also has"); + help_text.push_back("to be absent from at least one tile. Not All means an aquifer is tolerated"); + 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("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("The parameters for biomes, regions, etc. all require that the required"); + help_text.push_back("feature is Present in the embark, and entering the same value multiple"); + help_text.push_back("times does nothing (the first match ticks all requirements off). It can be"); + help_text.push_back("noted that all the Economic materials are found in the much longer Mineral"); + help_text.push_back("list. Note that Find is a fairly time consuming task (is it is in vanilla)."); + break; + + case pages::Caveats: + Screen::drawBorder("Embark Assistant Help/Info Caveats Page"); + + 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("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("data is generated as well."); + 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"); + help_text.push_back(" to load feature shells and detailed region data, and this costs the"); + help_text.push_back(" least when done one feature shell at a time."); + 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("- The site info is deduced by the author, so there may be errors and"); + help_text.push_back(" there are probably site types that end up not being identified."); + help_text.push_back("- Aquifer indications are based on the author's belief that they occur"); + help_text.push_back(" whenever an aquifer supporting layer is present at a depth of 3 or"); + help_text.push_back(" more."); + help_text.push_back("- The biome determination logic comes from code provided by Ragundo,"); + help_text.push_back(" with only marginal changes by the author. References can be found in"); + help_text.push_back(" the source file."); + help_text.push_back("- Thralling is determined by weather material interactions causing"); + 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("- 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("- Right world map overlay not implemented as author has failed to"); + help_text.push_back(" emulate the sizing logic exactly."); + help_text.push_back("Version 0.1 2017-08-30"); + + break; + } + + // Add control keys to first line. + embark_assist::screen::paintString(pen_lr, 1, 1, "TAB/Shift-TAB"); + embark_assist::screen::paintString(pen, 14, 1, ":Next/Previous Page"); + embark_assist::screen::paintString(pen_lr, 34, 1, "ESC"); + embark_assist::screen::paintString(pen, 37, 1, ":Leave Info/Help"); + + for (uint16_t i = 0; i < help_text.size(); i++) { + embark_assist::screen::paintString(pen, 1, 2 + i, help_text[i]); + } + + switch (current_page) { + case pages::Intro: + embark_assist::screen::paintString(pen_lr, 1, 26, "i"); + embark_assist::screen::paintString(pen_lr, 1, 27, "f"); + embark_assist::screen::paintString(pen_lr, 1, 28, "c"); + embark_assist::screen::paintString(pen_lr, 1, 30, "q"); + break; + + case pages::General: + embark_assist::screen::paintString(site_pen, 1, 4, "C"); + embark_assist::screen::paintString(site_pen, 1, 5, "c"); + embark_assist::screen::paintString(site_pen, 1, 6, "i"); + embark_assist::screen::paintString(site_pen, 1, 7, "l"); + embark_assist::screen::paintString(site_pen, 1, 8, "L"); + embark_assist::screen::paintString(site_pen, 1, 9, "M"); + embark_assist::screen::paintString(site_pen, 1, 10, "S"); + embark_assist::screen::paintString(site_pen, 1, 11, "V"); + break; + + case pages::Finder: + embark_assist::screen::paintString(pen_lr, 1, 4, "4/6"); + embark_assist::screen::paintString(pen_lr, 1, 5, "8/2"); + embark_assist::screen::paintString(pen_lr, 1, 6, "ENTER"); + embark_assist::screen::paintString(pen_lr, 1, 7, "f"); + embark_assist::screen::paintString(pen_lr, 1, 8, "ESC"); + break; + + case pages::Caveats: + break; + } + dfhack_viewscreen::render(); + } + + //=============================================================================== + + ViewscreenHelpUi::ViewscreenHelpUi() { + } + + //=============================================================================== + // Exported operations + //=============================================================================== + + void init(DFHack::Plugin *plugin_self) { + Screen::show(new ViewscreenHelpUi(), plugin_self); + } + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/help_ui.h b/plugins/embark-assistant/help_ui.h new file mode 100644 index 000000000..65a2e4f1d --- /dev/null +++ b/plugins/embark-assistant/help_ui.h @@ -0,0 +1,15 @@ +#pragma once + +#include "PluginManager.h" + +#include "DataDefs.h" + +#include "defs.h" + +using namespace DFHack; + +namespace embark_assist { + namespace help_ui { + void init(DFHack::Plugin *plugin_self); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/matcher.cpp b/plugins/embark-assistant/matcher.cpp new file mode 100644 index 000000000..b4d3f438e --- /dev/null +++ b/plugins/embark-assistant/matcher.cpp @@ -0,0 +1,1445 @@ +#include + +#include + +#include "DataDefs.h" +#include "df/biome_type.h" +#include "df/inorganic_raw.h" +#include "df/region_map_entry.h" +#include "df/viewscreen.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_raws.h" +#include "df/world_region.h" +#include "df/world_region_type.h" + +#include "matcher.h" +#include "survey.h" + +using df::global::world; + +namespace embark_assist { + namespace matcher { + + //======================================================================================= + + //======================================================================================= + + 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; + bool savagery_found[3] = { false, false, false }; + bool evilness_found[3] = { false, false, false }; + uint16_t aquifer_count = 0; + bool river_found = false; + bool waterfall_found = false; + uint16_t river_elevation; + uint16_t elevation = mlt->at(start_x).at(start_y).elevation; + bool clay_found = false; + bool sand_found = false; + bool flux_found = false; + uint8_t max_soil = 0; + bool uneven = false; + bool evil_weather_found = false; + bool reanimation_found = false; + bool thralling_found = false; + 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; + + const uint16_t embark_size = finder->x_dim * finder->y_dim; + + if (finder->biome_count_min != -1 || + finder->biome_count_max != -1 || + 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(world_region_type); i++) 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; + + embark_assist::defs::evil_savagery_ranges l = embark_assist::defs::evil_savagery_ranges::Low; + while (true) { + if (mlt->at(i).at(k).savagery_level == static_cast(l)) { + if (finder->savagery[static_cast (l)] == + embark_assist::defs::evil_savagery_values::Absent) return false; + } + else { + if (finder->savagery[static_cast (l)] == + embark_assist::defs::evil_savagery_values::All) return false; + } + + if (mlt->at(i).at(k).evilness_level == static_cast(l)) { + if (finder->evilness[static_cast (l)] == + embark_assist::defs::evil_savagery_values::Absent) return false; + } + else { + if (finder->evilness[static_cast (l)] == + embark_assist::defs::evil_savagery_values::All) return false; + } + + 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->at(i).at(k).aquifer) return false; + aquifer_count++; + 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++; + break; + + case embark_assist::defs::aquifer_ranges::Absent: + if (mlt->at(i).at(k).aquifer) return false; + break; + } + + // River & Waterfall + if (mlt->at(i).at(k).river_present) { + // Actual size values were checked on the world tile level for min rivers + if (finder->max_river != embark_assist::defs::river_ranges::NA && + finder->max_river < static_cast(survey_results->at(x).at(y).river_size)) return false; + + if (river_found && river_elevation != mlt->at(i).at(k).river_elevation) { + if (finder->waterfall == embark_assist::defs::yes_no_ranges::No) return false; + waterfall_found = true; + } + river_found = true; + river_elevation = mlt->at(i).at(k).river_elevation; + } + + // Flat + if (finder->flat == embark_assist::defs::yes_no_ranges::Yes && + elevation != mlt->at(i).at(k).elevation) return false; + + if (elevation != mlt->at(i).at(k).elevation) 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; + } + + // Sand + if (mlt->at(i).at(k).sand) { + if (finder->sand == embark_assist::defs::present_absent_ranges::Absent) return false; + 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; + } + + // Min Soil + if (finder->soil_min != embark_assist::defs::soil_ranges::NA && + 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; + } + + // Max Soil + if (finder->soil_max != embark_assist::defs::soil_ranges::NA && + mlt->at(i).at(k).soil_depth > static_cast(finder->soil_max)) return false; + + // Evil Weather + if (survey_results->at(x).at(y).evil_weather[mlt->at(i).at(k).biome_offset]) { + if (finder->evil_weather == embark_assist::defs::yes_no_ranges::No) return false; + evil_weather_found = true; + } + + // Reanmation + if (survey_results->at(x).at(y).reanimating[mlt->at(i).at(k).biome_offset]) { + if (finder->reanimation == embark_assist::defs::yes_no_ranges::No) return false; + reanimation_found = true; + } + + // Thralling + if (survey_results->at(x).at(y).thralling[mlt->at(i).at(k).biome_offset]) { + if (finder->thralling == embark_assist::defs::yes_no_ranges::No) return false; + thralling_found = true; + } + + // Biomes + 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; + + // 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]; + + // 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]; + + // 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]; + } + } + + // Summary section, for all the stuff that require the complete picture + // + // Savagery & Evilness + { + embark_assist::defs::evil_savagery_ranges l = embark_assist::defs::evil_savagery_ranges::Low; + + while (true) { + if (finder->savagery[static_cast (l)] == + embark_assist::defs::evil_savagery_values::Present && + !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; + + 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: + case embark_assist::defs::aquifer_ranges::All: // Checked above + case embark_assist::defs::aquifer_ranges::Absent: // Ditto + break; + + case embark_assist::defs::aquifer_ranges::Present: + if (aquifer_count == 0) return false; + break; + + case embark_assist::defs::aquifer_ranges::Partial: + if (aquifer_count == 0 || aquifer_count == embark_size) return false; + break; + + case embark_assist::defs::aquifer_ranges::Not_All: + if (aquifer_count == embark_size) return false; + break; + } + + // River & Waterfall + if (!river_found && finder->min_river > embark_assist::defs::river_ranges::None) return false; + if (finder->waterfall == embark_assist::defs::yes_no_ranges::Yes && !waterfall_found) return false; + + // Flat + if (!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; + + // Sand + if (finder->sand == embark_assist::defs::present_absent_ranges::Present && !sand_found) return false; + + // Flux + if (finder->flux == embark_assist::defs::present_absent_ranges::Present && !flux_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; + + // Evil Weather + if (finder->evil_weather == embark_assist::defs::yes_no_ranges::Yes && !evil_weather_found) return false; + + // Reanimation + if (finder->reanimation == embark_assist::defs::yes_no_ranges::Yes && !reanimation_found) return false; + + // Thralling + if (finder->thralling == embark_assist::defs::yes_no_ranges::Yes && !thralling_found) return false; + + // Biomes + if (finder->biome_count_min != -1 || + finder->biome_count_max != -1) { + biome_count = 0; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { + if (biomes[i]) biome_count++; + } + + if (biome_count < finder->biome_count_min || + (finder->biome_count_max != -1 && + finder->biome_count_max < 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; + + // 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; + + // 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; + + return true; + } + + //======================================================================================= + + void mid_level_tile_match(embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt, + uint16_t x, + uint16_t y, + embark_assist::defs::finders *finder, + embark_assist::defs::match_results *match_results) { + +// color_ostream_proxy out(Core::getInstance().getConsole()); + bool match = false; + + for (uint16_t i = 0; i < 16; i++) { + for (uint16_t k = 0; k < 16; k++) { + if (i < 16 - finder->x_dim + 1 && k < 16 - finder->y_dim + 1) { + match_results->at(x).at(y).mlt_match[i][k] = embark_match(survey_results, mlt, x, y, i, k, finder); + match = match || match_results->at(x).at(y).mlt_match[i][k]; + } + else { + match_results->at(x).at(y).mlt_match[i][k] = false; + } + } + } + match_results->at(x).at(y).contains_match = match; + match_results->at(x).at(y).preliminary_match = false; + } + + //======================================================================================= + + bool world_tile_match(embark_assist::defs::world_tile_data *survey_results, + uint16_t x, + uint16_t y, + embark_assist::defs::finders *finder) { + +// color_ostream_proxy out(Core::getInstance().getConsole()); + df::world_data *world_data = world->world_data; + embark_assist::defs::region_tile_datum *tile = &survey_results->at(x).at(y); + const uint16_t embark_size = finder->x_dim * finder->y_dim; + uint16_t count; + bool found; + + if (tile->surveyed) { + // Savagery + for (uint8_t i = 0; i < 3; i++) + { + switch (finder->savagery[i]) { + case embark_assist::defs::evil_savagery_values::NA: + break; // No restriction + + case embark_assist::defs::evil_savagery_values::All: + if (tile->savagery_count[i] < embark_size) return false; + break; + + case embark_assist::defs::evil_savagery_values::Present: + if (tile->savagery_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Absent: + if (tile->savagery_count[i] > 256 - embark_size) return false; + break; + } + } + + // Evilness + for (uint8_t i = 0; i < 3; i++) + { + switch (finder->evilness[i]) { + case embark_assist::defs::evil_savagery_values::NA: + break; // No restriction + + case embark_assist::defs::evil_savagery_values::All: + if (tile->evilness_count[i] < embark_size) return false; + break; + + case embark_assist::defs::evil_savagery_values::Present: + if (tile->evilness_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Absent: + if (tile->evilness_count[i] > 256 - embark_size) return false; + break; + } + } + + // Aquifer + switch (finder->aquifer) { + case embark_assist::defs::aquifer_ranges::NA: + break; // No restriction + + case embark_assist::defs::aquifer_ranges::All: + if (tile->aquifer_count < 256 - embark_size) return false; + break; + + case embark_assist::defs::aquifer_ranges::Present: + if (tile->aquifer_count == 0) return false; + break; + + case embark_assist::defs::aquifer_ranges::Partial: + if (tile->aquifer_count == 0 || + tile->aquifer_count == 256) return false; + break; + + case embark_assist::defs::aquifer_ranges::Not_All: + if (tile->aquifer_count == 256) return false; + break; + + case embark_assist::defs::aquifer_ranges::Absent: + if (tile->aquifer_count > 256 - embark_size) return false; + break; + } + + // River size. Every tile has riverless tiles, so max rivers has to be checked on the detailed level. + switch (tile->river_size) { + case embark_assist::defs::river_sizes::None: + if (finder->min_river > embark_assist::defs::river_ranges::None) return false; + break; + + case embark_assist::defs::river_sizes::Brook: + if (finder->min_river > embark_assist::defs::river_ranges::Brook) return false; + break; + + case embark_assist::defs::river_sizes::Stream: + if (finder->min_river > embark_assist::defs::river_ranges::Stream) return false; + break; + + case embark_assist::defs::river_sizes::Minor: + if (finder->min_river > embark_assist::defs::river_ranges::Minor) return false; + break; + + case embark_assist::defs::river_sizes::Medium: + if (finder->min_river > embark_assist::defs::river_ranges::Medium) return false; + break; + + case embark_assist::defs::river_sizes::Major: + if (finder->max_river != embark_assist::defs::river_ranges::NA) return false; + break; + } + + // Waterfall + switch (finder->waterfall) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->waterfall) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->waterfall && + embark_size == 256) return false; + break; + } + + // Flat. No world tile checks. Need to look at the details + + // Clay + switch (finder->clay) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->clay_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->clay_count > 256 - embark_size) return false; + break; + } + + // Sand + switch (finder->sand) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->sand_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->sand_count > 256 - embark_size) return false; + break; + } + + // Flux + switch (finder->flux) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->flux_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->flux_count > 256 - embark_size) return false; + break; + } + + // Soil Min + switch (finder->soil_min) { + case embark_assist::defs::soil_ranges::NA: + case embark_assist::defs::soil_ranges::None: + break; // No restriction + + case embark_assist::defs::soil_ranges::Very_Shallow: + if (tile->max_region_soil < 1) return false; + break; + + case embark_assist::defs::soil_ranges::Shallow: + if (tile->max_region_soil < 2) return false; + break; + + case embark_assist::defs::soil_ranges::Deep: + if (tile->max_region_soil < 3) return false; + break; + + case embark_assist::defs::soil_ranges::Very_Deep: + if (tile->max_region_soil < 4) return false; + break; + } + + // soil_min_everywhere only applies on the detailed level + + // Soil Max + switch (finder->soil_max) { + case embark_assist::defs::soil_ranges::NA: + case embark_assist::defs::soil_ranges::Very_Deep: + break; // No restriction + + case embark_assist::defs::soil_ranges::None: + if (tile->min_region_soil > 0) return false; + break; + + case embark_assist::defs::soil_ranges::Very_Shallow: + if (tile->min_region_soil > 1) return false; + break; + + case embark_assist::defs::soil_ranges::Shallow: + if (tile->min_region_soil > 2) return false; + break; + + case embark_assist::defs::soil_ranges::Deep: + if (tile->min_region_soil > 3) return false; + break; + } + + // Evil Weather + switch (finder->evil_weather) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->evil_weather_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->evil_weather_full) return false; + break; + } + + // Reanimating + switch (finder->reanimation) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->reanimating_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->reanimating_full) return false; + break; + } + + // Thralling + switch (finder->thralling) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->thralling_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->thralling_full) return false; + break; + } + + // Biome Count Min (Can't do anything with Max at this level) + if (finder->biome_count_min > tile->biome_count) return false; + + // Region Type 1 + if (finder->region_type_1 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_1) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Region Type 2 + if (finder->region_type_2 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_2) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Region Type 3 + if (finder->region_type_3 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_3) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Biome 1 + if (finder->biome_1 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_1) { + found = true; + break; + } + } + + if (!found) return false; + } + + // Biome 2 + if (finder->biome_2 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_2) { + found = true; + break; + } + } + + if (!found) return false; + } + + // Biome 3 + if (finder->biome_3 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_3) { + found = true; + break; + } + } + + if (!found) return false; + } + + if (finder->metal_1 != -1 || + finder->metal_2 != -1 || + finder->metal_3 != -1 || + finder->economic_1 != -1 || + finder->economic_2 != -1 || + finder->economic_3 != -1 || + finder->mineral_1 != -1 || + finder->mineral_2 != -1 || + finder->mineral_3 != -1) { + count = 0; + 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; + + metal_1 = metal_1 || tile->metals[finder->metal_1]; + metal_2 = metal_2 || tile->metals[finder->metal_2]; + metal_3 = metal_3 || tile->metals[finder->metal_3]; + economic_1 = economic_1 || tile->economics[finder->economic_1]; + economic_2 = economic_2 || tile->economics[finder->economic_2]; + economic_3 = economic_3 || tile->economics[finder->economic_3]; + mineral_1 = mineral_1 || tile->minerals[finder->mineral_1]; + mineral_2 = mineral_2 || tile->minerals[finder->mineral_2]; + mineral_3 = mineral_3 || tile->minerals[finder->mineral_3]; + + if (!metal_1 || + !metal_2 || + !metal_3 || + !economic_1 || + !economic_2 || + !economic_3 || + !mineral_1 || + !mineral_2 || + !mineral_3) return false; + } + } + else { // Not surveyed + // Savagery + for (uint8_t i = 0; i < 3; i++) + { + switch (finder->savagery[i]) { + case embark_assist::defs::evil_savagery_values::NA: + break; // No restriction + + case embark_assist::defs::evil_savagery_values::All: + if (tile->savagery_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Present: + if (tile->savagery_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Absent: + if (tile->savagery_count[i] == 256) return false; + break; + } + } + + // Evilness + for (uint8_t i = 0; i < 3; i++) + { + switch (finder->evilness[i]) { + case embark_assist::defs::evil_savagery_values::NA: + break; // No restriction + + case embark_assist::defs::evil_savagery_values::All: + if (tile->evilness_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Present: + if (tile->evilness_count[i] == 0) return false; + break; + + case embark_assist::defs::evil_savagery_values::Absent: + if (tile->evilness_count[i] == 256) return false; + break; + } + } + + // Aquifer + switch (finder->aquifer) { + case embark_assist::defs::aquifer_ranges::NA: + break; // No restriction + + case embark_assist::defs::aquifer_ranges::All: + if (tile->aquifer_count == 0) return false; + break; + + case embark_assist::defs::aquifer_ranges::Present: + if (tile->aquifer_count == 0) return false; + break; + + case embark_assist::defs::aquifer_ranges::Partial: + if (tile->aquifer_count == 0 || + tile->aquifer_count == 256) return false; + break; + + case embark_assist::defs::aquifer_ranges::Not_All: + if (tile->aquifer_count == 256) return false; + break; + + case embark_assist::defs::aquifer_ranges::Absent: + if (tile->aquifer_count == 256) return false; + break; + } + + // River size + switch (tile->river_size) { + case embark_assist::defs::river_sizes::None: + if (finder->min_river > embark_assist::defs::river_ranges::None) return false; + break; + + case embark_assist::defs::river_sizes::Brook: + if (finder->min_river > embark_assist::defs::river_ranges::Brook) return false; + break; + + case embark_assist::defs::river_sizes::Stream: + if (finder->min_river > embark_assist::defs::river_ranges::Stream) return false; + break; + + case embark_assist::defs::river_sizes::Minor: + if (finder->min_river > embark_assist::defs::river_ranges::Minor) return false; + break; + + case embark_assist::defs::river_sizes::Medium: + if (finder->min_river > embark_assist::defs::river_ranges::Medium) return false; + break; + + case embark_assist::defs::river_sizes::Major: + if (finder->max_river != embark_assist::defs::river_ranges::NA) return false; + break; + } + + // Waterfall + if (finder->waterfall == embark_assist::defs::yes_no_ranges::Yes && + tile->river_size == embark_assist::defs::river_sizes::None) return false; + + // Flat. No world tile checks. Need to look at the details + + // Clay + switch (finder->clay) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->clay_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->clay_count == 256) return false; + break; + } + + // Sand + switch (finder->sand) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->sand_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->sand_count == 256) return false; + break; + } + + // Flux + switch (finder->flux) { + case embark_assist::defs::present_absent_ranges::NA: + break; // No restriction + + case embark_assist::defs::present_absent_ranges::Present: + if (tile->flux_count == 0) return false; + break; + case embark_assist::defs::present_absent_ranges::Absent: + if (tile->flux_count == 256) return false; + break; + } + + // Soil Min + switch (finder->soil_min) { + case embark_assist::defs::soil_ranges::NA: + case embark_assist::defs::soil_ranges::None: + break; // No restriction + + case embark_assist::defs::soil_ranges::Very_Shallow: + if (tile->max_region_soil < 1) return false; + break; + + case embark_assist::defs::soil_ranges::Shallow: + if (tile->max_region_soil < 2) return false; + break; + + case embark_assist::defs::soil_ranges::Deep: + if (tile->max_region_soil < 3) return false; + break; + + case embark_assist::defs::soil_ranges::Very_Deep: + if (tile->max_region_soil < 4) return false; + break; + } + + // soil_min_everywhere only applies on the detailed level + + // Soil Max + // Can't say anything as the preliminary data isn't reliable + + // Evil Weather + switch (finder->evil_weather) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->evil_weather_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->evil_weather_full) return false; + break; + } + + // Reanimating + switch (finder->reanimation) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->reanimating_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->reanimating_full) return false; + break; + } + + // Thralling + switch (finder->thralling) { + case embark_assist::defs::yes_no_ranges::NA: + break; // No restriction + + case embark_assist::defs::yes_no_ranges::Yes: + if (!tile->thralling_possible) return false; + break; + + case embark_assist::defs::yes_no_ranges::No: + if (tile->thralling_full) return false; + break; + } + + // Biome Count Min (Can't do anything with Max at this level) + if (finder->biome_count_min > tile->biome_count) return false; + + // Region Type 1 + if (finder->region_type_1 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_1) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Region Type 2 + if (finder->region_type_2 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_2) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Region Type 3 + if (finder->region_type_3 != -1) { + found = false; + + for (uint8_t k = 1; k < 10; k++) { + if (tile->biome_index[k] != -1) { + if (world_data->regions[tile->biome_index[k]]->type == finder->region_type_3) { + found = true; + break; + } + } + + if (found) break; + } + + if (!found) return false; + } + + // Biome 1 + if (finder->biome_1 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_1) { + found = true; + break; + } + } + + if (!found) return false; + } + + // Biome 2 + if (finder->biome_2 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_2) { + found = true; + break; + } + } + + if (!found) return false; + } + + // Biome 3 + if (finder->biome_3 != -1) { + found = false; + + for (uint8_t i = 1; i < 10; i++) { + if (tile->biome[i] == finder->biome_3) { + found = true; + break; + } + } + + if (!found) return false; + } + + if (finder->metal_1 != -1 || + finder->metal_2 != -1 || + finder->metal_3 != -1 || + finder->economic_1 != -1 || + finder->economic_2 != -1 || + finder->economic_3 != -1 || + finder->mineral_1 != -1 || + finder->mineral_2 != -1 || + finder->mineral_3 != -1) { + count = 0; + 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; + + metal_1 = metal_1 || tile->metals[finder->metal_1]; + metal_2 = metal_2 || tile->metals[finder->metal_2]; + metal_3 = metal_3 || tile->metals[finder->metal_3]; + economic_1 = economic_1 || tile->economics[finder->economic_1]; + economic_2 = economic_2 || tile->economics[finder->economic_2]; + economic_3 = economic_3 || tile->economics[finder->economic_3]; + mineral_1 = mineral_1 || tile->minerals[finder->mineral_1]; + mineral_2 = mineral_2 || tile->minerals[finder->mineral_2]; + mineral_3 = mineral_3 || tile->minerals[finder->mineral_3]; + + if (!metal_1 || + !metal_2 || + !metal_3 || + !economic_1 || + !economic_2 || + !economic_3 || + !mineral_1 || + !mineral_2 || + !mineral_3) return false; + } + } + return true; + } + + //======================================================================================= + + uint32_t preliminary_world_match(embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::finders *finder, + embark_assist::defs::match_results *match_results) { + // color_ostream_proxy out(Core::getInstance().getConsole()); + uint32_t count = 0; + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + match_results->at(i).at(k).preliminary_match = + world_tile_match(survey_results, i, k, finder); + if (match_results->at(i).at(k).preliminary_match) count++; + match_results->at(i).at(k).contains_match = false; + } + } + + return count; + } + + //======================================================================================= + + void match_world_tile(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::finders *finder, + embark_assist::defs::match_results *match_results, + uint16_t x, + uint16_t y) { + +// color_ostream_proxy out(Core::getInstance().getConsole()); + embark_assist::defs::mid_level_tiles mlt; + + embark_assist::survey::survey_mid_level_tile(geo_summary, + survey_results, + &mlt); + + mid_level_tile_match(survey_results, + &mlt, + x, + y, + finder, + match_results); + } + + //======================================================================================= + // Visible operations + //======================================================================================= + + void move_cursor(uint16_t x, uint16_t y) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + uint16_t original_x = screen->location.region_pos.x; + uint16_t original_y = screen->location.region_pos.y; + + uint16_t large_x = std::abs(original_x - x) / 10; + uint16_t small_x = std::abs(original_x - x) % 10; + uint16_t large_y = std::abs(original_y - y) / 10; + uint16_t small_y = std::abs(original_y - y) % 10; + + while (large_x > 0 || large_y > 0) { + if (large_x > 0 && large_y > 0) { + if (original_x - x > 0 && original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); + } + else if (original_x - x > 0 && original_y - y < 0) { + screen->feed_key(df::interface_key::CURSOR_DOWNLEFT_FAST); + } + else if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPRIGHT_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT_FAST); + } + large_x--; + large_y--; + } + else if (large_x > 0) { + if (original_x - x > 0) { + screen->feed_key(df::interface_key::CURSOR_LEFT_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_RIGHT_FAST); + } + large_x--; + } + else { + if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UP_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWN_FAST); + } + large_y--; + } + } + + while (small_x > 0 || small_y > 0) { + if (small_x > 0 && small_y > 0) { + if (original_x - x > 0 && original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT); + } + else if (original_x - x > 0 && original_y - y < 0) { + screen->feed_key(df::interface_key::CURSOR_DOWNLEFT); + } + else if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPRIGHT); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT); + } + small_x--; + small_y--; + } + else if (small_x > 0) { + if (original_x - x > 0) { + screen->feed_key(df::interface_key::CURSOR_LEFT); + } + else { + screen->feed_key(df::interface_key::CURSOR_RIGHT); + } + small_x--; + } + else { + if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UP); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + small_y--; + } + } + } + + //======================================================================================= + + uint16_t find(embark_assist::defs::match_iterators *iterator, + embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::match_results *match_results) { + + color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + uint16_t x_end; + uint16_t y_end; + bool turn; + uint16_t count; + uint16_t preliminary_matches; + + if (!iterator->active) { + embark_assist::survey::clear_results(match_results); + + // Static check for impossible requirements + // + count = 0; + for (uint8_t i = 0; i < 3; i++) { + if (iterator->finder.evilness[i] == embark_assist::defs::evil_savagery_values::All) { + count++; + } + } + + if (count > 1) { + out.printerr("matcher::find: Will never find any due to multiple All evilness requirements\n"); + return 0; + } + + count = 0; + for (uint8_t i = 0; i < 3; i++) { + if (iterator->finder.savagery[i] == embark_assist::defs::evil_savagery_values::All) { + count++; + } + } + + if (count > 1) { + out.printerr("matcher::find: Will never find any due to multiple All savagery requirements\n"); + return 0; + } + + if (iterator->finder.max_river < iterator->finder.min_river && + iterator->finder.max_river != embark_assist::defs::river_ranges::NA) { + out.printerr("matcher::find: Will never find any due to max river < min river\n"); + return 0; + } + + if (iterator->finder.waterfall == embark_assist::defs::yes_no_ranges::Yes && + iterator->finder.max_river == embark_assist::defs::river_ranges::None) { + out.printerr("matcher::find: Will never find any waterfalls with None as max river\n"); + return 0; + } + + if (iterator->finder.soil_max < iterator->finder.soil_min && + iterator->finder.soil_max != embark_assist::defs::soil_ranges::NA) { + out.printerr("matcher::find: Will never find any matches with max soil < min soil\n"); + return 0; + } + + if (iterator->finder.biome_count_max < iterator->finder.biome_count_min && + iterator->finder.biome_count_max != -1) { + out.printerr("matcher::find: Will never find any matches with max biomes < min biomes\n"); + return 0; + } + + preliminary_matches = preliminary_world_match(survey_results, &iterator->finder, match_results); + + if (preliminary_matches == 0) { + out.printerr("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); + return 0; + } + else { + out.print("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); + } + + while (screen->location.region_pos.x != 0 || screen->location.region_pos.y != 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); + } + iterator->active = true; + iterator->i = 0; + iterator->k = 0; + iterator->x_right = true; + iterator->y_down = true; + iterator->inhibit_x_turn = false; + iterator->inhibit_y_turn = false; + iterator->count = 0; + } + + if ((iterator->k == world->worldgen.worldgen_parms.dim_x / 16 && iterator->x_right) || + (iterator->k == 0 && !iterator->x_right)) { + x_end = 0; + } + else { + x_end = 15; + } + + if (iterator->i == world->worldgen.worldgen_parms.dim_y / 16) { + y_end = 0; + } + else { + y_end = 15; + } + + for (uint16_t l = 0; l <= x_end; l++) { + for (uint16_t m = 0; m <= y_end; m++) { + // This is where the payload goes + if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).preliminary_match) { + match_world_tile(geo_summary, + survey_results, + &iterator->finder, + match_results, + screen->location.region_pos.x, + screen->location.region_pos.y); + if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).contains_match) { + iterator->count++; + } + } + else { + for (uint16_t n = 0; n < 16; n++) { + for (uint16_t p = 0; p < 16; p++) { + match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match[n][p] = false; + } + } + } + // End of payload section + + if (m != y_end) { + if (iterator->y_down) { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + else { + screen->feed_key(df::interface_key::CURSOR_UP); + } + } + else { + if (screen->location.region_pos.x != 0 && + screen->location.region_pos.x != world->worldgen.worldgen_parms.dim_x - 1) { + turn = true; + } + else { + iterator->inhibit_y_turn = !iterator->inhibit_y_turn; + turn = iterator->inhibit_y_turn; + } + + if (turn) { + iterator->y_down = !iterator->y_down; + } + else { + if (iterator->y_down) { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + else { + screen->feed_key(df::interface_key::CURSOR_UP); + } + } + } + } + + if (iterator->x_right) { // Won't do anything at the edge, so we don't bother filter those cases. + screen->feed_key(df::interface_key::CURSOR_RIGHT); + } + else { + screen->feed_key(df::interface_key::CURSOR_LEFT); + } + + if (!iterator->x_right && + screen->location.region_pos.x == 0) { + turn = !turn; + + if (turn) { + iterator->x_right = true; + } + } + else if (iterator->x_right && + screen->location.region_pos.x == world->worldgen.worldgen_parms.dim_x - 1) { + turn = !turn; + + if (turn) { + iterator->x_right = false; + } + } + } + // } + + iterator->k++; + if (iterator->k > world->worldgen.worldgen_parms.dim_x / 16) + { + iterator->k = 0; + iterator->i++; + iterator->active = !(iterator->i > world->worldgen.worldgen_parms.dim_y / 16); + + if (!iterator->active) { + move_cursor(iterator->x, iterator->y); + } + } + + return iterator->count; + } + } +} diff --git a/plugins/embark-assistant/matcher.h b/plugins/embark-assistant/matcher.h new file mode 100644 index 000000000..9887ffbd0 --- /dev/null +++ b/plugins/embark-assistant/matcher.h @@ -0,0 +1,21 @@ +#pragma once + +#include "DataDefs.h" + +#include "defs.h" + +using namespace DFHack; + +namespace embark_assist { + namespace matcher { + void move_cursor(uint16_t x, uint16_t y); + + // Used to iterate over the whole world to generate a map of world tiles + // that contain matching embarks. + // + uint16_t find(embark_assist::defs::match_iterators *iterator, + embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::match_results *match_results); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/overlay.cpp b/plugins/embark-assistant/overlay.cpp new file mode 100644 index 000000000..6b63fa70d --- /dev/null +++ b/plugins/embark-assistant/overlay.cpp @@ -0,0 +1,439 @@ +#include + +#include "df/coord2d.h" +#include "df/inorganic_raw.h" +#include "df/dfhack_material_category.h" +#include "df/interface_key.h" +#include "df/viewscreen.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_raws.h" + +#include "finder_ui.h" +#include "help_ui.h" +#include "overlay.h" +#include "screen.h" + +using df::global::world; + +namespace embark_assist { + namespace overlay { + DFHack::Plugin *plugin_self; + const Screen::Pen empty_pen = Screen::Pen('\0', COLOR_YELLOW, COLOR_BLACK, false); + const Screen::Pen yellow_x_pen = Screen::Pen('X', COLOR_BLACK, COLOR_YELLOW, false); + const Screen::Pen green_x_pen = Screen::Pen('X', COLOR_BLACK, COLOR_GREEN, false); + + struct display_strings { + Screen::Pen pen; + std::string text; + }; + + typedef Screen::Pen *pen_column; + + struct states { + int blink_count = 0; + bool show = true; + + bool matching = false; + bool match_active = false; + + embark_update_callbacks embark_update; + match_callbacks match_callback; + clear_match_callbacks clear_match_callback; + embark_assist::defs::find_callbacks find_callback; + shutdown_callbacks shutdown_callback; + + Screen::Pen site_grid[16][16]; + uint8_t current_site_grid = 0; + + std::vector embark_info; + + Screen::Pen region_match_grid[16][16]; + + pen_column *world_match_grid = nullptr; + uint16_t match_count = 0; + + uint16_t max_inorganic; + }; + + static states *state = nullptr; + + //==================================================================== + +/* // Attempt to replicate the DF logic for sizing the right world map. This + // code seems to compute the values correctly, but the author hasn't been + // able to apply them at the same time as DF does to 100%. + // DF seems to round down on 0.5 values. + df::coord2d world_dimension_size(uint16_t available_screen, uint16_t map_size) { + uint16_t result; + + for (uint16_t factor = 1; factor < 17; factor++) { + result = map_size / factor; + if ((map_size - result * factor) * 2 != factor) { + result = (map_size + factor / 2) / factor; + } + + if (result <= available_screen) { + return {result, factor}; + } + } + return{16, 16}; // Should never get here. + } +*/ + //==================================================================== + + class ViewscreenOverlay : public df::viewscreen_choose_start_sitest + { + public: + typedef df::viewscreen_choose_start_sitest interpose_base; + + void send_key(const df::interface_key &key) + { + std::set< df::interface_key > keys; + keys.insert(key); + this->feed(&keys); + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { +// color_ostream_proxy out(Core::getInstance().getConsole()); + if (input->count(df::interface_key::CUSTOM_Q)) { + state->shutdown_callback(); + return; + + } + else if (input->count(df::interface_key::SETUP_LOCAL_X_MUP) || + input->count(df::interface_key::SETUP_LOCAL_X_MDOWN) || + input->count(df::interface_key::SETUP_LOCAL_Y_MUP) || + input->count(df::interface_key::SETUP_LOCAL_Y_MDOWN) || + input->count(df::interface_key::SETUP_LOCAL_X_UP) || + input->count(df::interface_key::SETUP_LOCAL_X_DOWN) || + input->count(df::interface_key::SETUP_LOCAL_Y_UP) || + input->count(df::interface_key::SETUP_LOCAL_Y_DOWN)) { + INTERPOSE_NEXT(feed)(input); + state->embark_update(); + } + else if (input->count(df::interface_key::CUSTOM_C)) { + state->match_active = false; + state->matching = false; + state->clear_match_callback(); + } + else if (input->count(df::interface_key::CUSTOM_F)) { + if (!state->match_active && !state->matching) { + embark_assist::finder_ui::init(embark_assist::overlay::plugin_self, state->find_callback, state->max_inorganic); + } + } + else if (input->count(df::interface_key::CUSTOM_I)) { + embark_assist::help_ui::init(embark_assist::overlay::plugin_self); + } + else { + INTERPOSE_NEXT(feed)(input); + } + } + + //==================================================================== + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); +// color_ostream_proxy out(Core::getInstance().getConsole()); + auto current_screen = Gui::getViewscreenByType(0); + int16_t x = current_screen->location.region_pos.x; + int16_t y = current_screen->location.region_pos.y; + auto width = Screen::getWindowSize().x; + auto height = Screen::getWindowSize().y; + + state->blink_count++; + if (state->blink_count == 35) { + state->blink_count = 0; + state->show = !state->show; + } + + if (state->matching) state->show = true; + + Screen::drawBorder("Embark Assistant"); + + Screen::Pen pen_lr(' ', COLOR_LIGHTRED); + Screen::Pen pen_w(' ', COLOR_WHITE); + + Screen::paintString(pen_lr, width - 28, 20, "i", false); + Screen::paintString(pen_w, width - 27, 20, ":Embark Assistant Info", false); + Screen::paintString(pen_lr, width - 28, 21, "f", false); + Screen::paintString(pen_w, width - 27, 21, ":Find Embark ", false); + Screen::paintString(pen_lr, width - 28, 22, "c", false); + Screen::paintString(pen_w, width - 27, 22, ":Cancel/Clear Find", false); + Screen::paintString(pen_lr, width - 28, 23, "q", false); + Screen::paintString(pen_w, width - 27, 23, ":Quit Embark Assistant", false); + Screen::paintString(pen_w, width - 28, 25, "Matching World Tiles", false); + Screen::paintString(empty_pen, width - 7, 25, to_string(state->match_count), false); + + if (height > 25) { // Mask the vanilla DF find help as it's overridden. + Screen::paintString(pen_w, 50, height - 2, " ", false); + } + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + if (state->site_grid[i][k].ch) { + Screen::paintTile(state->site_grid[i][k], i + 1, k + 2); + } + } + } + + for (auto i = 0; i < state->embark_info.size(); i++) { + embark_assist::screen::paintString(state->embark_info[i].pen, 1, i + 19, state->embark_info[i].text, false); + } + + if (state->show) { + int16_t left_x = x - (width / 2 - 7 - 18 + 1) / 2; + int16_t right_x; + int16_t top_y = y - (height - 8 - 2 + 1) / 2; + int16_t bottom_y; + + if (left_x < 0) { left_x = 0; } + + if (top_y < 0) { top_y = 0; } + + right_x = left_x + width / 2 - 7 - 18; + bottom_y = top_y + height - 8 - 2; + + if (right_x >= world->worldgen.worldgen_parms.dim_x) { + right_x = world->worldgen.worldgen_parms.dim_x - 1; + left_x = right_x - (width / 2 - 7 - 18); + } + + if (bottom_y >= world->worldgen.worldgen_parms.dim_y) { + bottom_y = world->worldgen.worldgen_parms.dim_y - 1; + top_y = bottom_y - (height - 8 - 2); + } + + if (left_x < 0) { left_x = 0; } + + if (top_y < 0) { top_y = 0; } + + + for (uint16_t i = left_x; i <= right_x; i++) { + for (uint16_t k = top_y; k <= bottom_y; k++) { + if (state->world_match_grid[i][k].ch) { + Screen::paintTile(state->world_match_grid[i][k], i - left_x + 18, k - top_y + 2); + } + } + } + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + if (state->region_match_grid[i][k].ch) { + Screen::paintTile(state->region_match_grid[i][k], i + 1, k + 2); + } + } + } + +/* // Stuff for trying to replicate the DF right world map sizing logic. Close, but not there. + Screen::Pen pen(' ', COLOR_YELLOW); + // Boundaries of the top level world map + Screen::paintString(pen, width / 2 - 5, 2, "X", false); // Marks UL corner of right world map. Constant +// Screen::paintString(pen, width - 30, 2, "X", false); // Marks UR corner of right world map area. +// Screen::paintString(pen, width / 2 - 5, height - 8, "X", false); // BL corner of right world map area. +// Screen::paintString(pen, width - 30, height - 8, "X", false); // BR corner of right world map area. + + uint16_t l_width = width - 30 - (width / 2 - 5) + 1; // Horizontal space available for right world map. + uint16_t l_height = height - 8 - 2 + 1; // Vertical space available for right world map. + df::coord2d size_factor_x = world_dimension_size(l_width, world->worldgen.worldgen_parms.dim_x); + df::coord2d size_factor_y = world_dimension_size(l_height, world->worldgen.worldgen_parms.dim_y); + + Screen::paintString(pen, width / 2 - 5 + size_factor_x.x - 1, 2, "X", false); + Screen::paintString(pen, width / 2 - 5, 2 + size_factor_y.x - 1, "X", false); + Screen::paintString(pen, width / 2 - 5 + size_factor_x.x - 1, 2 + size_factor_y.x - 1, "X", false); + */ + } + + if (state->matching) { + embark_assist::overlay::state->match_callback(); + } + } + }; + + IMPLEMENT_VMETHOD_INTERPOSE(embark_assist::overlay::ViewscreenOverlay, feed); + IMPLEMENT_VMETHOD_INTERPOSE(embark_assist::overlay::ViewscreenOverlay, render); + } +} + +//==================================================================== + +bool embark_assist::overlay::setup(DFHack::Plugin *plugin_self, + embark_update_callbacks embark_update_callback, + match_callbacks match_callback, + clear_match_callbacks clear_match_callback, + embark_assist::defs::find_callbacks find_callback, + shutdown_callbacks shutdown_callback, + uint16_t max_inorganic) +{ +// color_ostream_proxy out(Core::getInstance().getConsole()); + state = new(states); + + embark_assist::overlay::plugin_self = plugin_self; + embark_assist::overlay::state->embark_update = embark_update_callback; + embark_assist::overlay::state->match_callback = match_callback; + embark_assist::overlay::state->clear_match_callback = clear_match_callback; + embark_assist::overlay::state->find_callback = find_callback; + embark_assist::overlay::state->shutdown_callback = shutdown_callback; + embark_assist::overlay::state->max_inorganic = max_inorganic; + embark_assist::overlay::state->match_active = false; + + state->world_match_grid = new pen_column[world->worldgen.worldgen_parms.dim_x]; + if (!state->world_match_grid) { + return false; // Out of memory + } + + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + state->world_match_grid[i] = new Screen::Pen[world->worldgen.worldgen_parms.dim_y]; + if (!state->world_match_grid[i]) { // Out of memory. + return false; + } + } + + clear_match_results(); + + return INTERPOSE_HOOK(embark_assist::overlay::ViewscreenOverlay, feed).apply(true) && + INTERPOSE_HOOK(embark_assist::overlay::ViewscreenOverlay, render).apply(true); +} + +//==================================================================== + +void embark_assist::overlay::set_sites(embark_assist::defs::site_lists *site_list) { + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + state->site_grid[i][k] = empty_pen; + } + } + + for (uint16_t i = 0; i < site_list->size(); i++) { + state->site_grid[site_list->at(i).x][site_list->at(i).y].ch = site_list->at(i).type; + } +} + +//==================================================================== + +void embark_assist::overlay::initiate_match() { + embark_assist::overlay::state->matching = true; +} + +//==================================================================== + +void embark_assist::overlay::match_progress(uint16_t count, embark_assist::defs::match_results *match_results, bool done) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + state->matching = !done; + state->match_count = count; + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + if (match_results->at(i).at(k).preliminary_match) { + state->world_match_grid[i][k] = yellow_x_pen; + + } else if (match_results->at(i).at(k).contains_match) { + state->world_match_grid[i][k] = green_x_pen; + } + else { + state->world_match_grid[i][k] = empty_pen; + } + } + } +} + +//==================================================================== + +void embark_assist::overlay::set_embark(embark_assist::defs::site_infos *site_info) { + state->embark_info.clear(); + + if (site_info->sand) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_YELLOW), "Sand" }); + } + + if (site_info->clay) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_RED), "Clay" }); + } + + 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->flat) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_BROWN), "Flat" }); + } + + if (site_info->aquifer) { + if (site_info->aquifer_full) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_BLUE), "Aquifer" }); + + } + else { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_LIGHTBLUE), "Aquifer" }); + } + } + + if (site_info->waterfall) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_BLUE), "Waterfall" }); + } + + if (site_info->flux) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_WHITE), "Flux" }); + } + + for (auto const& i : site_info->metals) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_GREY), world->raws.inorganics[i]->id }); + } + + for (auto const& i : site_info->economics) { + state->embark_info.push_back({ Screen::Pen(' ', COLOR_WHITE), world->raws.inorganics[i]->id }); + } +} + +//==================================================================== + +void embark_assist::overlay::set_mid_level_tile_match(embark_assist::defs::mlt_matches mlt_matches) { + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + if (mlt_matches[i][k]) { + state->region_match_grid[i][k] = green_x_pen; + + } + else { + state->region_match_grid[i][k] = empty_pen; + } + } + } +} + +//==================================================================== + +void embark_assist::overlay::clear_match_results() { + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + state->world_match_grid[i][k] = empty_pen; + } + } + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + state->region_match_grid[i][k] = empty_pen; + } + } +} + +//==================================================================== + +void embark_assist::overlay::shutdown() { + if (state && + state->world_match_grid) { + INTERPOSE_HOOK(ViewscreenOverlay, render).remove(); + INTERPOSE_HOOK(ViewscreenOverlay, feed).remove(); + + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + delete[] state->world_match_grid[i]; + } + + delete[] state->world_match_grid; + } + + if (state) { + state->embark_info.clear(); + delete state; + state = nullptr; + } +} diff --git a/plugins/embark-assistant/overlay.h b/plugins/embark-assistant/overlay.h new file mode 100644 index 000000000..d66d6d7fd --- /dev/null +++ b/plugins/embark-assistant/overlay.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "PluginManager.h" + +#include "DataDefs.h" +#include "df/viewscreen_choose_start_sitest.h" + +#include "defs.h" + +using df::global::enabler; +using df::global::gps; + +namespace embark_assist { + namespace overlay { + typedef void(*embark_update_callbacks)(); + typedef void(*match_callbacks)(); + typedef void(*clear_match_callbacks)(); + typedef void(*shutdown_callbacks)(); + + bool setup(DFHack::Plugin *plugin_self, + embark_update_callbacks embark_update_callback, + match_callbacks match_callback, + clear_match_callbacks clear_match_callback, + embark_assist::defs::find_callbacks find_callback, + shutdown_callbacks shutdown_callback, + uint16_t max_inorganic); + + void set_sites(embark_assist::defs::site_lists *site_list); + void initiate_match(); + void match_progress(uint16_t count, embark_assist::defs::match_results *match_results, bool done); + void set_embark(embark_assist::defs::site_infos *site_info); + void set_mid_level_tile_match(embark_assist::defs::mlt_matches mlt_matches); + void clear_match_results(); + void shutdown(); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/screen.cpp b/plugins/embark-assistant/screen.cpp new file mode 100644 index 000000000..dc634049e --- /dev/null +++ b/plugins/embark-assistant/screen.cpp @@ -0,0 +1,26 @@ +#include "screen.h" + +namespace embark_assist { + namespace screen { + bool paintString(const DFHack::Screen::Pen &pen, int x, int y, const std::string &text, bool map) { + auto screen_size = DFHack::Screen::getWindowSize(); + + if (y < 1 || y + 1 >= screen_size.y || x < 1) + { + return false; // Won't paint outside of the screen or on the frame + } + + if (x + text.length() - 1 < screen_size.x - 2) { + DFHack::Screen::paintString(pen, x, y, text, map); + } + else if (x < screen_size.x - 2) { + DFHack::Screen::paintString(pen, x, y, text.substr(0, screen_size.x - 2 - x + 1), map); + } + else { + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/screen.h b/plugins/embark-assistant/screen.h new file mode 100644 index 000000000..06b723f24 --- /dev/null +++ b/plugins/embark-assistant/screen.h @@ -0,0 +1,7 @@ +#include "modules/Screen.h" + +namespace embark_assist { + namespace screen { + bool paintString(const DFHack::Screen::Pen &pen, int x, int y, const std::string &text, bool map = false); + } +} \ No newline at end of file diff --git a/plugins/embark-assistant/survey.cpp b/plugins/embark-assistant/survey.cpp new file mode 100644 index 000000000..308ee78d1 --- /dev/null +++ b/plugins/embark-assistant/survey.cpp @@ -0,0 +1,1080 @@ +#include + +#include "Core.h" +#include +#include +#include + +#include +#include "modules/Materials.h" + +#include "DataDefs.h" +#include "df/coord2d.h" +#include "df/creature_interaction_effect.h" +#include "df/creature_interaction_effect_display_symbolst.h" +#include "df/creature_interaction_effect_type.h" +#include "df/feature_init.h" +#include "df/inorganic_flags.h" +#include "df/inorganic_raw.h" +#include "df/interaction.h" +#include "df/interaction_instance.h" +#include "df/interaction_source.h" +#include "df/interaction_source_regionst.h" +#include "df/interaction_source_type.h" +#include "df/interaction_target.h" +#include "df/interaction_target_corpsest.h" +#include "df/interaction_target_materialst.h" +#include "df/material_common.h" +#include "df/reaction.h" +#include "df/region_map_entry.h" +#include "df/syndrome.h" +#include "df/viewscreen.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/world.h" +#include "df/world_data.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/world_raws.h" +#include "df/world_region.h" +#include "df/world_region_details.h" +#include "df/world_region_feature.h" +#include "df/world_river.h" +#include "df/world_site.h" +#include "df/world_site_type.h" +#include "df/world_underground_region.h" + +#include "biome_type.h" +#include "defs.h" +#include "survey.h" + +using namespace DFHack; +using namespace df::enums; +using namespace Gui; + +using df::global::world; + +namespace embark_assist { + namespace survey { + struct states { + uint16_t clay_reaction = -1; + uint16_t flux_reaction = -1; + uint16_t x; + uint16_t y; + uint8_t local_min_x; + uint8_t local_min_y; + uint8_t local_max_x; + uint8_t local_max_y; + uint16_t max_inorganic; + }; + + static states *state; + + //======================================================================================= + + bool geo_survey(embark_assist::defs::geo_data *geo_summary) { + color_ostream_proxy out(Core::getInstance().getConsole()); + df::world_data *world_data = world->world_data; + auto reactions = world->raws.reactions; + bool non_soil_found; + uint16_t size; + + for (uint16_t i = 0; i < reactions.size(); i++) { + if (reactions[i]->code == "MAKE_CLAY_BRICKS") { + state->clay_reaction = i; + } + + if (reactions[i]->code == "PIG_IRON_MAKING") { + state->flux_reaction = i; + } + } + + if (state->clay_reaction == -1) { + out.printerr("The reaction 'MAKE_CLAY_BRICKS' was not found, so clay can't be identified.\n"); + } + + if (state->flux_reaction == -1) { + out.printerr("The reaction 'PIG_IRON_MAKING' was not found, so flux can't be identified.\n"); + } + + for (uint16_t i = 0; i < world_data->geo_biomes.size(); i++) { + geo_summary->at(i).possible_metals.resize(state->max_inorganic); + geo_summary->at(i).possible_economics.resize(state->max_inorganic); + geo_summary->at(i).possible_minerals.resize(state->max_inorganic); + + non_soil_found = true; + df::world_geo_biome *geo = world_data->geo_biomes[i]; + + for (uint16_t k = 0; k < geo->layers.size() && k < 16; k++) { + df::world_geo_layer *layer = geo->layers[k]; + + if (layer->type == df::geo_layer_type::SOIL || + layer->type == df::geo_layer_type::SOIL_SAND) { + geo_summary->at(i).soil_size += layer->top_height - layer->bottom_height + 1; + + if (world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::SOIL_SAND)) { + geo_summary->at(i).sand_absent = false; + } + + if (non_soil_found) { + geo_summary->at(i).top_soil_only = false; + } + } + else { + non_soil_found = true; + } + + geo_summary->at(i).possible_minerals[layer->mat_index] = true; + + size = (uint16_t)world->raws.inorganics[layer->mat_index]->metal_ore.mat_index.size(); + + for (uint16_t l = 0; l < size; l++) { + geo_summary->at(i).possible_metals.at(world->raws.inorganics[layer->mat_index]->metal_ore.mat_index[l]) = true; + } + + size = (uint16_t)world->raws.inorganics[layer->mat_index]->economic_uses.size(); + if (size != 0) { + geo_summary->at(i).possible_economics[layer->mat_index] = true; + + for (uint16_t l = 0; l < size; l++) { + if (world->raws.inorganics[layer->mat_index]->economic_uses[l] == state->clay_reaction) { + geo_summary->at(i).clay_absent = false; + } + + if (world->raws.inorganics[layer->mat_index]->economic_uses[l] == state->flux_reaction) { + geo_summary->at(i).flux_absent = false; + } + } + } + + size = (uint16_t)layer->vein_mat.size(); + + for (uint16_t l = 0; l < size; l++) { + auto vein = layer->vein_mat[l]; + geo_summary->at(i).possible_minerals[vein] = true; + + for (uint16_t m = 0; m < world->raws.inorganics[vein]->metal_ore.mat_index.size(); m++) { + geo_summary->at(i).possible_metals.at(world->raws.inorganics[vein]->metal_ore.mat_index[m]) = true; + } + + if (world->raws.inorganics[vein]->economic_uses.size() != 0) { + geo_summary->at(i).possible_economics[vein] = true; + + for (uint16_t m = 0; m < world->raws.inorganics[vein]->economic_uses.size(); m++) { + if (world->raws.inorganics[vein]->economic_uses[m] == state->clay_reaction) { + geo_summary->at(i).clay_absent = false; + } + + if (world->raws.inorganics[vein]->economic_uses[m] == state->flux_reaction) { + geo_summary->at(i).flux_absent = false; + } + } + } + } + + if (layer->bottom_height <= -3 && + world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::AQUIFER)) { + geo_summary->at(i).aquifer_absent = false; + } + + if (non_soil_found == true) { + geo_summary->at(i).top_soil_aquifer_only = false; + } + } + } + return true; + } + + + //================================================================================= + + void survey_rivers(embark_assist::defs::world_tile_data *survey_results) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + df::world_data *world_data = world->world_data; + int16_t x; + int16_t y; + + for (uint16_t i = 0; i < world_data->rivers.size(); i++) { + for (uint16_t k = 0; k < world_data->rivers[i]->path.x.size(); k++) { + x = world_data->rivers[i]->path.x[k]; + y = world_data->rivers[i]->path.y[k]; + + if (world_data->rivers[i]->unk_8c[k] < 5000) { + if (world_data->region_map[x][y].flags.is_set(df::region_map_entry_flags::is_brook)) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Brook; + } + else { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Stream; + } + } + else if (world_data->rivers[i]->unk_8c[k] < 10000) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Minor; + } + else if (world_data->rivers[i]->unk_8c[k] < 20000) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Medium; + } + else { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Major; + } + } + + x = world_data->rivers[i]->end_pos.x; + y = world_data->rivers[i]->end_pos.y; + + // Make the guess the river size for the end is the same as the tile next to the end. Note that DF + // doesn't actually recognize this tile as part of the river in the pre embark river name display. + // We also assume the is_river/is_brook flags are actually set properly for the end tile. + // + if (x >= 0 && y >= 0 && x < world->worldgen.worldgen_parms.dim_x && y < world->worldgen.worldgen_parms.dim_y) { + if (survey_results->at(x).at(y).river_size == embark_assist::defs::river_sizes::None) { + if (world_data->rivers[i]->path.x.size() && + world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 5000) { + if (world_data->region_map[x][y].flags.is_set(df::region_map_entry_flags::is_brook)) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Brook; + } + else { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Stream; + } + } + else if (world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 10000) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Minor; + } + else if (world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 20000) { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Medium; + } + else { + survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Major; + } + } + } + } + } + + //================================================================================= + + void survey_evil_weather(embark_assist::defs::world_tile_data *survey_results) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + df::world_data *world_data = world->world_data; + + for (uint16_t i = 0; i < world->interaction_instances.all.size(); i++) { + auto interaction = world->raws.interactions[world->interaction_instances.all[i]->interaction_id]; + uint16_t region_index = world->interaction_instances.all[i]->region_index; + bool thralling = false; + bool reanimating = false; + + if (interaction->sources.size() && + interaction->sources[0]->getType() == df::interaction_source_type::REGION) { + for (uint16_t k = 0; k < interaction->targets.size(); k++) { + if (interaction->targets[k]->getType() == 0) { // Returns wrong type. Should be df::interaction_target_type::CORPSE + reanimating = true; + } + else if (interaction->targets[k]->getType() == 2) {// Returns wrong type.. Should be df::interaction_target_type::MATERIAL + df::interaction_target_materialst* material = static_cast(interaction->targets[k]); + if (DFHack::MaterialInfo::MaterialInfo(material->anon_1, material->anon_2).isInorganic()) { + for (uint16_t l = 0; l < world->raws.inorganics[material->anon_2]->material.syndrome.size(); l++) { + for (uint16_t m = 0; m < world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce.size(); m++) { + if (world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce[m]->getType() == df::creature_interaction_effect_type::FLASH_TILE) { + // Using this as a proxy. There seems to be a group of 4 effects for thralls: + // display symbol, flash symbol, phys att change and one more. + thralling = true; + } + } + } + } + } + } + } + + for (uint16_t k = 0; k < world_data->regions[region_index]->region_coords.size(); k++) { + survey_results->at(world_data->regions[region_index]->region_coords[k].x).at(world_data->regions[region_index]->region_coords[k].y).evil_weather[5] = true; + survey_results->at(world_data->regions[region_index]->region_coords[k].x).at(world_data->regions[region_index]->region_coords[k].y).reanimating[5] = reanimating; + survey_results->at(world_data->regions[region_index]->region_coords[k].x).at(world_data->regions[region_index]->region_coords[k].y).thralling[5] = thralling; + } + } + + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + survey_results->at(i).at(k).evil_weather_possible = false; + survey_results->at(i).at(k).reanimating_possible = false; + survey_results->at(i).at(k).thralling_possible = false; + survey_results->at(i).at(k).evil_weather_full = true; + survey_results->at(i).at(k).reanimating_full = true; + survey_results->at(i).at(k).thralling_full = true; + + for (uint8_t l = 1; l < 10; l++) { + if (survey_results->at(i).at(k).biome_index[l] != -1) { + df::coord2d adjusted = apply_offset(i, k, l); + survey_results->at(i).at(k).evil_weather[l] = survey_results->at(adjusted.x).at(adjusted.y).evil_weather[5]; + survey_results->at(i).at(k).reanimating[l] = survey_results->at(adjusted.x).at(adjusted.y).reanimating[5]; + survey_results->at(i).at(k).thralling[l] = survey_results->at(adjusted.x).at(adjusted.y).thralling[5]; + + if (survey_results->at(i).at(k).evil_weather[l]) { + survey_results->at(i).at(k).evil_weather_possible = true; + } + else { + survey_results->at(i).at(k).evil_weather_full = false; + } + + if (survey_results->at(i).at(k).reanimating[l]) { + survey_results->at(i).at(k).reanimating_possible = true; + } + else { + survey_results->at(i).at(k).reanimating_full = false; + } + + if (survey_results->at(i).at(k).thralling[l]) { + survey_results->at(i).at(k).thralling_possible = true; + } + else { + survey_results->at(i).at(k).thralling_full = false; + } + } + } + } + } + } + + //================================================================================= + // Exported operations + //================================================================================= + + void setup(uint16_t max_inorganic) { + state = new(states); + state->max_inorganic = max_inorganic; + } + + //================================================================================= + + df::coord2d get_last_pos() { + return{state->x, state->y}; + } + + //================================================================================= + + void initiate(embark_assist::defs::mid_level_tiles *mlt) { + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + mlt->at(i).at(k).metals.resize(state->max_inorganic); + mlt->at(i).at(k).economics.resize(state->max_inorganic); + mlt->at(i).at(k).minerals.resize(state->max_inorganic); + } + } + } + + //================================================================================= + + void clear_results(embark_assist::defs::match_results *match_results) { + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + match_results->at(i).at(k).preliminary_match = false; + match_results->at(i).at(k).contains_match = false; + + for (uint16_t l = 0; l < 16; l++) { + for (uint16_t m = 0; m < 16; m++) { + match_results->at(i).at(k).mlt_match[l][m] = false; + } + } + } + } + } + + //================================================================================= + + void high_level_world_survey(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + + geo_survey(geo_summary); + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + df::coord2d adjusted; + df::world_data *world_data = world->world_data; + uint16_t geo_index; + uint16_t sav_ev; + uint8_t offset_count = 0; + survey_results->at(i).at(k).surveyed = false; + survey_results->at(i).at(k).aquifer_count = 0; + survey_results->at(i).at(k).clay_count = 0; + survey_results->at(i).at(k).sand_count = 0; + survey_results->at(i).at(k).flux_count = 0; + survey_results->at(i).at(k).min_region_soil = 10; + survey_results->at(i).at(k).max_region_soil = 0; + survey_results->at(i).at(k).waterfall = false; + survey_results->at(i).at(k).savagery_count[0] = 0; + survey_results->at(i).at(k).savagery_count[1] = 0; + survey_results->at(i).at(k).savagery_count[2] = 0; + survey_results->at(i).at(k).evilness_count[0] = 0; + survey_results->at(i).at(k).evilness_count[1] = 0; + survey_results->at(i).at(k).evilness_count[2] = 0; + survey_results->at(i).at(k).metals.resize(state->max_inorganic); + survey_results->at(i).at(k).economics.resize(state->max_inorganic); + survey_results->at(i).at(k).minerals.resize(state->max_inorganic); + // Evil weather and rivers are handled in later operations. Should probably be merged into one. + + for (uint8_t l = 1; l < 10; l++) + { + adjusted = apply_offset(i, k, l); + if (adjusted.x != i || adjusted.y != k || l == 5) { + offset_count++; + + survey_results->at(i).at(k).biome_index[l] = world_data->region_map[adjusted.x][adjusted.y].region_id; + survey_results->at(i).at(k).biome[l] = get_biome_type(adjusted.x, adjusted.y, k); + geo_index = world_data->region_map[adjusted.x][adjusted.y].geo_index; + + if (!geo_summary->at(geo_index).aquifer_absent) survey_results->at(i).at(k).aquifer_count++; + if (!geo_summary->at(geo_index).clay_absent) survey_results->at(i).at(k).clay_count++; + if (!geo_summary->at(geo_index).sand_absent) survey_results->at(i).at(k).sand_count++; + if (!geo_summary->at(geo_index).flux_absent) survey_results->at(i).at(k).flux_count++; + + if (geo_summary->at(geo_index).soil_size < survey_results->at(i).at(k).min_region_soil) + survey_results->at(i).at(k).min_region_soil = geo_summary->at(geo_index).soil_size; + + if (geo_summary->at(geo_index).soil_size > survey_results->at(i).at(k).max_region_soil) + survey_results->at(i).at(k).max_region_soil = geo_summary->at(geo_index).soil_size; + + sav_ev = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; + if (sav_ev == 3) sav_ev = 2; + survey_results->at(i).at(k).savagery_count[sav_ev]++; + + sav_ev = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; + if (sav_ev == 3) sav_ev = 2; + survey_results->at(i).at(k).evilness_count[sav_ev]++; + + for (uint16_t m = 0; m < state->max_inorganic; m++) { + if (geo_summary->at(geo_index).possible_metals[m]) survey_results->at(i).at(k).metals[m] = true; + if (geo_summary->at(geo_index).possible_economics[m]) survey_results->at(i).at(k).economics[m] = true; + if (geo_summary->at(geo_index).possible_minerals[m]) survey_results->at(i).at(k).minerals[m] = true; + } + } + else { + survey_results->at(i).at(k).biome_index[l] = -1; + survey_results->at(i).at(k).biome[l] = -1; + } + } + + survey_results->at(i).at(k).biome_count = 0; + for (uint8_t l = 1; l < 10; l++) { + if (survey_results->at(i).at(k).biome[l] != -1) survey_results->at(i).at(k).biome_count++; + } + + if (survey_results->at(i).at(k).aquifer_count == offset_count) survey_results->at(i).at(k).aquifer_count = 256; + if (survey_results->at(i).at(k).clay_count == offset_count) survey_results->at(i).at(k).clay_count = 256; + if (survey_results->at(i).at(k).sand_count == offset_count) survey_results->at(i).at(k).sand_count = 256; + if (survey_results->at(i).at(k).flux_count == offset_count) survey_results->at(i).at(k).flux_count = 256; + for (uint8_t l = 0; l < 3; l++) { + if (survey_results->at(i).at(k).savagery_count[l] == offset_count) survey_results->at(i).at(k).savagery_count[l] = 256; + if (survey_results->at(i).at(k).evilness_count[l] == offset_count) survey_results->at(i).at(k).evilness_count[l] = 256; + } + } + } + + survey_rivers(survey_results); + survey_evil_weather(survey_results); + } + + //================================================================================= + + void survey_mid_level_tile(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt) { +// color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + int16_t x = screen->location.region_pos.x; + int16_t y = screen->location.region_pos.y; + embark_assist::defs::region_tile_datum *tile = &survey_results->at(x).at(y); + int8_t max_soil_depth; + int8_t offset; + int16_t elevation; + int16_t last_bottom; + int16_t top_z; + int16_t base_z; + int16_t min_z = 0; // Initialized to silence warning about potential usage of uninitialized data. + int16_t bottom_z; + df::coord2d adjusted; + df::world_data *world_data = world->world_data; + df::world_region_details *details = world_data->region_details[0]; + df::region_map_entry *world_tile = &world_data->region_map[x][y]; + std::vector features; + uint8_t soil_erosion; + uint16_t end_check_l; + uint16_t end_check_m; + uint16_t end_check_n; + + for (uint16_t i = 0; i < state->max_inorganic; i++) { + tile->metals[i] = 0; + tile->economics[i] = 0; + tile->minerals[i] = 0; + } + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + mlt->at(i).at(k).metals.resize(state->max_inorganic); + mlt->at(i).at(k).economics.resize(state->max_inorganic); + mlt->at(i).at(k).minerals.resize(state->max_inorganic); + } + } + + for (uint8_t i = 1; i < 10; i++) survey_results->at(x).at(y).biome_index[i] = -1; + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + max_soil_depth = -1; + + offset = details->biome[i][k]; + adjusted = apply_offset(x, y, offset); + + if (adjusted.x != x || adjusted.y != y) + { + mlt->at(i).at(k).biome_offset = offset; + } + else + { + mlt->at(i).at(k).biome_offset = 5; + }; + + survey_results->at(x).at(y).biome_index[mlt->at(i).at(k).biome_offset] = + world_data->region_map[adjusted.x][adjusted.y].region_id; + + mlt->at(i).at(k).savagery_level = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; + if (mlt->at(i).at(k).savagery_level == 3) { + mlt->at(i).at(k).savagery_level = 2; + } + mlt->at(i).at(k).evilness_level = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; + if (mlt->at(i).at(k).evilness_level == 3) { + mlt->at(i).at(k).evilness_level = 2; + } + + elevation = details->elevation[i][k]; + + // Special biome adjustments + if (!world_data->region_map[adjusted.x][adjusted.y].flags.is_set(region_map_entry_flags::is_lake)) { + if (world_data->region_map[adjusted.x][adjusted.y].elevation >= 150) { // Mountain + max_soil_depth = 0; + + } + else if (world_data->region_map[adjusted.x][adjusted.y].elevation < 100) { // Ocean + if (elevation == 99) { + elevation = 98; + } + + if ((world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 4 || + world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 5) && + details->unk12e8 < 500) { + max_soil_depth = 0; + } + } + } + + base_z = elevation - 1; + features = details->features[i][k]; + std::map layer_bottom, layer_top; + + end_check_l = static_cast(features.size()); + for (size_t l = 0; l < end_check_l; l++) { + auto feature = features[l]; + + if (feature->layer != -1 && + feature->min_z != -30000) { + auto layer = world_data->underground_regions[feature->layer]; + + layer_bottom[layer->layer_depth] = feature->min_z; + layer_top[layer->layer_depth] = feature->max_z; + base_z = std::min((int)base_z, (int)feature->min_z); + + if (layer->type == df::world_underground_region::MagmaSea) { + min_z = feature->min_z; // The features are individual per region tile + break; + } + } + } + + // Compute shifts for layers in the stack. + + if (max_soil_depth == -1) { // Not set to zero by the biome + max_soil_depth = std::max((154 - elevation) / 5, 1); + } + + soil_erosion = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - + std::min((int)geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size, (int)max_soil_depth); + int16_t layer_shift[16]; + int16_t cur_shift = elevation + soil_erosion - 1; + + mlt->at(i).at(k).aquifer = false; + mlt->at(i).at(k).clay = false; + mlt->at(i).at(k).sand = false; + mlt->at(i).at(k).flux = false; + if (max_soil_depth == 0) { + mlt->at(i).at(k).soil_depth = 0; + } + else { + mlt->at(i).at(k).soil_depth = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - soil_erosion; + } + mlt->at(i).at(k).offset = offset; + mlt->at(i).at(k).elevation = details->elevation[i][k]; + mlt->at(i).at(k).river_present = false; + mlt->at(i).at(k).river_elevation = 100; + + if (details->rivers_vertical.active[i][k] == 1) { + mlt->at(i).at(k).river_present = true; + mlt->at(i).at(k).river_elevation = details->rivers_vertical.elevation[i][k]; + } + else if (details->rivers_horizontal.active[i][k] == 1) { + mlt->at(i).at(k).river_present = true; + mlt->at(i).at(k).river_elevation = details->rivers_horizontal.elevation[i][k]; + } + + if (tile->min_region_soil > mlt->at(i).at(k).soil_depth) { + tile->min_region_soil = mlt->at(i).at(k).soil_depth; + } + + if (tile->max_region_soil < mlt->at(i).at(k).soil_depth) { + tile->max_region_soil = mlt->at(i).at(k).soil_depth; + } + + end_check_l = static_cast(world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers.size()); + if (end_check_l > 16) end_check_l = 16; + + for (uint16_t l = 0; l < end_check_l; l++) { + auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; + layer_shift[l] = cur_shift; + + if (layer->type == df::geo_layer_type::SOIL || + layer->type == df::geo_layer_type::SOIL_SAND) { + int16_t size = layer->top_height - layer->bottom_height - 1; + // Comment copied from prospector.cpp(like the logic)... + // This is to replicate the behavior of a probable bug in the + // map generation code : if a layer is partially eroded, the + // removed levels are in fact transferred to the layer below, + // because unlike the case of removing the whole layer, the code + // does not execute a loop to shift the lower part of the stack up. + if (size > soil_erosion) { + cur_shift = cur_shift - soil_erosion; + } + + soil_erosion -= std::min((int)soil_erosion, (int)size); + } + } + + last_bottom = elevation; + // Don't have to set up the end_check as we can reuse the one above. + + for (uint16_t l = 0; l < end_check_l; l++) { + auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; + top_z = last_bottom - 1; + bottom_z = std::max((int)layer->bottom_height + layer_shift[l], (int)min_z); + + if (l == 15) { + bottom_z = min_z; // stretch layer if needed + } + + if (top_z >= bottom_z) { + mlt->at(i).at(k).minerals[layer->mat_index] = true; + + end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->metal_ore.mat_index.size()); + + for (uint16_t m = 0; m < end_check_m; m++) { + mlt->at(i).at(k).metals[world->raws.inorganics[layer->mat_index]->metal_ore.mat_index[m]] = true; + } + + if (layer->type == df::geo_layer_type::SOIL || + layer->type == df::geo_layer_type::SOIL_SAND) { + if (world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::SOIL_SAND)) { + mlt->at(i).at(k).sand = true; + } + } + + if (world->raws.inorganics[layer->mat_index]->economic_uses.size() > 0) { + mlt->at(i).at(k).economics[layer->mat_index] = true; + + end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->economic_uses.size()); + for (uint16_t m = 0; m < end_check_m; m++) { + if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->clay_reaction) { + mlt->at(i).at(k).clay = true; + } + + else if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->flux_reaction) { + mlt->at(i).at(k).flux = true; + } + } + } + + end_check_m = static_cast(layer->vein_mat.size()); + + for (uint16_t m = 0; m < end_check_m; m++) { + mlt->at(i).at(k).minerals[layer->vein_mat[m]] = true; + + end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index.size()); + + for (uint16_t n = 0; n < end_check_n; n++) { + mlt->at(i).at(k).metals[world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index[n]] = true; + } + + if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size() > 0) { + mlt->at(i).at(k).economics[layer->vein_mat[m]] = true; + + end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size()); + for (uint16_t n = 0; n < end_check_n; n++) { + if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->clay_reaction) { + mlt->at(i).at(k).clay = true; + } + + else if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->flux_reaction) { + mlt->at(i).at(k).flux = true; + } + } + } + } + + if (bottom_z <= elevation - 3 && + world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::AQUIFER)) { + mlt->at(i).at(k).aquifer = true; + } + } + } + } + } + + survey_results->at(x).at(y).aquifer_count = 0; + survey_results->at(x).at(y).clay_count = 0; + survey_results->at(x).at(y).sand_count = 0; + survey_results->at(x).at(y).flux_count = 0; + survey_results->at(x).at(y).min_region_soil = 10; + survey_results->at(x).at(y).max_region_soil = 0; + survey_results->at(x).at(y).savagery_count[0] = 0; + survey_results->at(x).at(y).savagery_count[1] = 0; + survey_results->at(x).at(y).savagery_count[2] = 0; + survey_results->at(x).at(y).evilness_count[0] = 0; + survey_results->at(x).at(y).evilness_count[1] = 0; + survey_results->at(x).at(y).evilness_count[2] = 0; + + bool river_elevation_found = false; + int16_t river_elevation; + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + if (mlt->at(i).at(k).aquifer) { survey_results->at(x).at(y).aquifer_count++; } + if (mlt->at(i).at(k).clay) { survey_results->at(x).at(y).clay_count++; } + if (mlt->at(i).at(k).sand) { survey_results->at(x).at(y).sand_count++; } + if (mlt->at(i).at(k).flux) { survey_results->at(x).at(y).flux_count++; } + + if (mlt->at(i).at(k).soil_depth < survey_results->at(x).at(y).min_region_soil) { + survey_results->at(x).at(y).min_region_soil = mlt->at(i).at(k).soil_depth; + } + + if (mlt->at(i).at(k).soil_depth > survey_results->at(x).at(y).max_region_soil) { + survey_results->at(x).at(y).max_region_soil = mlt->at(i).at(k).soil_depth; + } + + if (mlt->at(i).at(k).river_present) { + if (river_elevation_found) { + if (mlt->at(i).at(k).river_elevation != river_elevation) + { + survey_results->at(x).at(y).waterfall = true; + } + } + else { + river_elevation_found = true; + river_elevation = mlt->at(i).at(k).river_elevation; + } + } + + // River size surveyed separately + // biome_index handled above + // biome handled below + // evil weather handled separately + // reanimating handled separately + // thralling handled separately + + survey_results->at(x).at(y).savagery_count[mlt->at(i).at(k).savagery_level]++; + survey_results->at(x).at(y).evilness_count[mlt->at(i).at(k).evilness_level]++; + + for (uint16_t l = 0; l < state->max_inorganic; l++) { + if (mlt->at(i).at(k).metals[l]) { survey_results->at(x).at(y).metals[l] = true; } + if (mlt->at(i).at(k).economics[l]) { survey_results->at(x).at(y).economics[l] = true; } + if (mlt->at(i).at(k).minerals[l]) { survey_results->at(x).at(y).minerals[l] = true; } + } + } + } + + for (uint8_t i = 1; i < 10; i++) { + if (survey_results->at(x).at(y).biome_index[i] == -1) { + survey_results->at(x).at(y).biome[i] = -1; + } + } + + bool biomes[ENUM_LAST_ITEM(biome_type) + 1]; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { + biomes[i] = false; + } + + for (uint8_t i = 1; i < 10; i++) + { + if (survey_results->at(x).at(y).biome[i] != -1) { + biomes[survey_results->at(x).at(y).biome[i]] = true; + } + } + int count = 0; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { + if (biomes[i]) count++; + } + + tile->biome_count = count; + tile->surveyed = true; + } + //================================================================================= + + df::coord2d apply_offset(uint16_t x, uint16_t y, int8_t offset) { + df::coord2d result; + result.x = x; + result.y = y; + + switch (offset) { + case 1: + result.x--; + result.y++; + break; + + case 2: + result.y++; + break; + + case 3: + result.x++; + result.y++; + break; + + case 4: + result.x--; + break; + + case 5: + break; // Center. No change + + case 6: + result.x++; + break; + + case 7: + result.x--; + result.y--; + break; + + case 8: + result.y--; + break; + + case 9: + result.x++; + result.y--; + break; + + default: + // Bug. Just act as if it's the center... + break; + } + + if (result.x < 0) { + result.x = 0; + } + else if (result.x >= world->worldgen.worldgen_parms.dim_x) { + result.x = world->worldgen.worldgen_parms.dim_x - 1; + } + + if (result.y < 0) { + result.y = 0; + } + else if (result.y >= world->worldgen.worldgen_parms.dim_y) { + result.y = world->worldgen.worldgen_parms.dim_y - 1; + } + + return result; + } + + //================================================================================= + + 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); + df::world_data *world_data = world->world_data; + int8_t index = 0; + + site_list->clear(); + + for (uint32_t i = 0; i < world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites.size(); i++) { + auto site = world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites[i]; + switch (site->type) { + case df::world_site_type::PlayerFortress: + case df::world_site_type::DarkFortress: + case df::world_site_type::MountainHalls: + case df::world_site_type::ForestRetreat: + case df::world_site_type::Town: + case df::world_site_type::Fortress: + break; // Already visible + + case df::world_site_type::Cave: + if (!world->worldgen.worldgen_parms.all_caves_visible) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'c' }); // Cave + } + break; + + case df::world_site_type::Monument: + if (site->subtype_info->lair_type != -1 || + site->subtype_info->is_monument == 0) { // Not Tomb, which is visible already + } + else if (site->subtype_info->lair_type == -1) { + site_list->push_back( { (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'V' }); // Vault + } + else { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'M' }); // Any other Monument type. Pyramid? + } + break; + + case df::world_site_type::ImportantLocation: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'i' }); // Don't really know what that is... + break; + + case df::world_site_type::LairShrine: + if (site->subtype_info->lair_type == 0 || + site->subtype_info->lair_type == 1 || + site->subtype_info->lair_type == 4) { // Only Rocs seen. Mountain lair? + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'l' }); // Lair + } + else if (site->subtype_info->lair_type == 2) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'L' }); // Labyrinth + } + else if (site->subtype_info->lair_type == 3) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'S' }); // Shrine + } + else { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '?' }); // Can these exist? + } + break; + + case df::world_site_type::Camp: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'C' }); // Camp + break; + + default: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '!' }); // Not even in the enum... + break; + } + } + } + + //================================================================================= + + void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles *mlt, + embark_assist::defs::site_infos *site_info, + bool use_cache) { + +// color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + int16_t elevation; + uint16_t x = screen->location.region_pos.x; + uint16_t y = screen->location.region_pos.y; + bool river_found = false; + int16_t river_elevation; + std::vector metals(state->max_inorganic); + std::vector economics(state->max_inorganic); + std::vector minerals(state->max_inorganic); + + 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; + state->local_min_y = screen->location.embark_pos_min.y; + state->local_max_x = screen->location.embark_pos_max.x; + state->local_max_y = screen->location.embark_pos_max.y; + } + + state->x = x; + state->y = y; + + site_info->aquifer = false; + site_info->aquifer_full = true; + site_info->min_soil = 10; + site_info->max_soil = 0; + site_info->flat = true; + site_info->waterfall = false; + site_info->clay = false; + site_info->sand = false; + site_info->flux = false; + site_info->metals.clear(); + site_info->economics.clear(); + site_info->metals.clear(); + + for (uint8_t i = state->local_min_x; i <= state->local_max_x; i++) { + for (uint8_t k = state->local_min_y; k <= state->local_max_y; k++) { + if (mlt->at(i).at(k).aquifer) { + site_info->aquifer = true; + } + else { + site_info->aquifer_full = false; + } + + if (mlt->at(i).at(k).soil_depth < site_info->min_soil) { + site_info->min_soil = mlt->at(i).at(k).soil_depth; + } + + if (mlt->at(i).at(k).soil_depth > site_info->max_soil) { + site_info->max_soil = mlt->at(i).at(k).soil_depth; + } + + if (i == state->local_min_x && k == state->local_min_y) { + elevation = mlt->at(i).at(k).elevation; + + } + else if (elevation != mlt->at(i).at(k).elevation) { + site_info->flat = false; + } + + if (mlt->at(i).at(k).river_present) { + if (river_found) { + if (river_elevation != mlt->at(i).at(k).river_elevation) { + site_info->waterfall = true; + } + } + else { + river_elevation = mlt->at(i).at(k).river_elevation; + river_found = true; + } + } + + if (mlt->at(i).at(k).clay) { + site_info->clay = true; + } + + if (mlt->at(i).at(k).sand) { + site_info->sand = true; + } + + if (mlt->at(i).at(k).flux) { + site_info->flux = 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]; + } + } + } + for (uint16_t l = 0; l < state->max_inorganic; l++) { + if (metals[l]) { + site_info->metals.push_back(l); + } + + if (economics[l]) { + site_info->economics.push_back(l); + } + + if (minerals[l]) { + site_info->minerals.push_back(l); + } + } + } + + //================================================================================= + + void embark_assist::survey::shutdown() { + delete state; + } + } +} diff --git a/plugins/embark-assistant/survey.h b/plugins/embark-assistant/survey.h new file mode 100644 index 000000000..03d2d9a03 --- /dev/null +++ b/plugins/embark-assistant/survey.h @@ -0,0 +1,38 @@ +#pragma once +#include + +#include "DataDefs.h" +#include "df/coord2d.h" + +#include "defs.h" + +using namespace DFHack; + +namespace embark_assist { + namespace survey { + void setup(uint16_t max_inorganic); + + df::coord2d get_last_pos(); + + void initiate(embark_assist::defs::mid_level_tiles *mlt); + + void clear_results(embark_assist::defs::match_results *match_results); + + void high_level_world_survey(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results); + + void survey_mid_level_tile(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt); + + df::coord2d apply_offset(uint16_t x, uint16_t y, int8_t offset); + + void survey_region_sites(embark_assist::defs::site_lists *site_list); + + void survey_embark(embark_assist::defs::mid_level_tiles *mlt, + embark_assist::defs::site_infos *site_info, + bool use_cache); + + void shutdown(); + } +} \ No newline at end of file From 831fa07fb2fdd29c432bb0478e0f3b3e9484f43b Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 15:10:53 +0200 Subject: [PATCH 002/170] Removed path from dfhack.h include. --- plugins/embark-assistant/biome_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/embark-assistant/biome_type.cpp b/plugins/embark-assistant/biome_type.cpp index 82603a004..20ae086bf 100644 --- a/plugins/embark-assistant/biome_type.cpp +++ b/plugins/embark-assistant/biome_type.cpp @@ -29,7 +29,7 @@ misrepresented as being the original software. // You can always find the latest version of this plugin in Github // https://github.com/ragundo/exportmaps -#include "../../include/dfhack.h" +#include "dfhack.h" #include #include #include From 83061cffcae347b941b92b02409c6836e3545b09 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 15:37:40 +0200 Subject: [PATCH 003/170] Replaced include of dfhack.h with and DataDefs.h --- plugins/embark-assistant/biome_type.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/embark-assistant/biome_type.cpp b/plugins/embark-assistant/biome_type.cpp index 20ae086bf..01bc0044a 100644 --- a/plugins/embark-assistant/biome_type.cpp +++ b/plugins/embark-assistant/biome_type.cpp @@ -29,7 +29,9 @@ misrepresented as being the original software. // You can always find the latest version of this plugin in Github // https://github.com/ragundo/exportmaps -#include "dfhack.h" +#include + +#include "DataDefs.h" #include #include #include From 84eaf0414870826fb6a925794cf1a39c881f80d6 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 16:22:10 +0200 Subject: [PATCH 004/170] Removed function qualifications to make Travis happy and Visual Studio unhappy. --- plugins/embark-assistant/finder_ui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp index 3ebaa9e0f..bdf460270 100644 --- a/plugins/embark-assistant/finder_ui.cpp +++ b/plugins/embark-assistant/finder_ui.cpp @@ -959,7 +959,7 @@ namespace embark_assist { class ViewscreenFindUi : public dfhack_viewscreen { public: - ViewscreenFindUi::ViewscreenFindUi(); + ViewscreenFindUi(); void feed(std::set *input); @@ -1115,7 +1115,7 @@ namespace embark_assist { //=============================================================================== - void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { + void init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { if (!state) { // First call. Have to do the setup ui_setup(find_callback, max_inorganic); } @@ -1124,12 +1124,12 @@ namespace embark_assist { //=============================================================================== - void embark_assist::finder_ui::activate() { + void activate() { } //=============================================================================== - void embark_assist::finder_ui::shutdown() { + void shutdown() { if (embark_assist::finder_ui::state) { for (uint16_t i = 0; i < state->ui.size(); i++) { delete state->ui[i]; From 596296358fc1fce58e43685b36a6c2d53d779e85 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 17:00:14 +0200 Subject: [PATCH 005/170] Moved all externally visible operation implementations out of name spaces to satisfy both Travis and Visual Studio. --- plugins/embark-assistant/finder_ui.cpp | 44 +- plugins/embark-assistant/help_ui.cpp | 16 +- plugins/embark-assistant/matcher.cpp | 506 +++++----- plugins/embark-assistant/screen.cpp | 37 +- plugins/embark-assistant/survey.cpp | 1237 ++++++++++++------------ 5 files changed, 922 insertions(+), 918 deletions(-) diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp index bdf460270..feea89199 100644 --- a/plugins/embark-assistant/finder_ui.cpp +++ b/plugins/embark-assistant/finder_ui.cpp @@ -1112,32 +1112,34 @@ namespace embark_assist { ViewscreenFindUi::ViewscreenFindUi() { } + } +} - //=============================================================================== - - void init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { - if (!state) { // First call. Have to do the setup - ui_setup(find_callback, max_inorganic); - } - Screen::show(new ViewscreenFindUi(), plugin_self); - } +//=============================================================================== +// Exported operations +//=============================================================================== - //=============================================================================== +void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist::defs::find_callbacks find_callback, uint16_t max_inorganic) { + if (!embark_assist::finder_ui::state) { // First call. Have to do the setup + embark_assist::finder_ui::ui_setup(find_callback, max_inorganic); + } + Screen::show(new ViewscreenFindUi(), plugin_self); +} - void activate() { - } +//=============================================================================== - //=============================================================================== +void embark_assist::finder_ui::activate() { +} - void shutdown() { - if (embark_assist::finder_ui::state) { - for (uint16_t i = 0; i < state->ui.size(); i++) { - delete state->ui[i]; - } +//=============================================================================== - delete state; - state = nullptr; - } +void embark_assist::finder_ui::shutdown() { + if (embark_assist::finder_ui::state) { + for (uint16_t i = 0; i < embark_assist::finder_ui::state->ui.size(); i++) { + delete embark_assist::finder_ui::state->ui[i]; } + + delete embark_assist::finder_ui::state; + embark_assist::finder_ui::state = nullptr; } -} \ No newline at end of file +} diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp index e1830883a..9fe79e210 100644 --- a/plugins/embark-assistant/help_ui.cpp +++ b/plugins/embark-assistant/help_ui.cpp @@ -302,13 +302,13 @@ namespace embark_assist{ ViewscreenHelpUi::ViewscreenHelpUi() { } + } +} - //=============================================================================== - // Exported operations - //=============================================================================== +//=============================================================================== +// Exported operations +//=============================================================================== - void init(DFHack::Plugin *plugin_self) { - Screen::show(new ViewscreenHelpUi(), plugin_self); - } - } -} \ No newline at end of file +void embark_assist::help_ui::init(DFHack::Plugin *plugin_self) { + Screen::show(new embark_assist::help_ui::ViewscreenHelpUi(), plugin_self); +} diff --git a/plugins/embark-assistant/matcher.cpp b/plugins/embark-assistant/matcher.cpp index b4d3f438e..484ee3cf8 100644 --- a/plugins/embark-assistant/matcher.cpp +++ b/plugins/embark-assistant/matcher.cpp @@ -1149,297 +1149,297 @@ namespace embark_assist { finder, match_results); } + } +} - //======================================================================================= - // Visible operations - //======================================================================================= - - void move_cursor(uint16_t x, uint16_t y) { -// color_ostream_proxy out(Core::getInstance().getConsole()); - auto screen = Gui::getViewscreenByType(0); - uint16_t original_x = screen->location.region_pos.x; - uint16_t original_y = screen->location.region_pos.y; - - uint16_t large_x = std::abs(original_x - x) / 10; - uint16_t small_x = std::abs(original_x - x) % 10; - uint16_t large_y = std::abs(original_y - y) / 10; - uint16_t small_y = std::abs(original_y - y) % 10; - - while (large_x > 0 || large_y > 0) { - if (large_x > 0 && large_y > 0) { - if (original_x - x > 0 && original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); - } - else if (original_x - x > 0 && original_y - y < 0) { - screen->feed_key(df::interface_key::CURSOR_DOWNLEFT_FAST); - } - else if (original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UPRIGHT_FAST); - } - else { - screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT_FAST); - } - large_x--; - large_y--; - } - else if (large_x > 0) { - if (original_x - x > 0) { - screen->feed_key(df::interface_key::CURSOR_LEFT_FAST); - } - else { - screen->feed_key(df::interface_key::CURSOR_RIGHT_FAST); - } - large_x--; - } - else { - if (original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UP_FAST); - } - else { - screen->feed_key(df::interface_key::CURSOR_DOWN_FAST); - } - large_y--; - } +//======================================================================================= +// Visible operations +//======================================================================================= + +void embark_assist::matcher::move_cursor(uint16_t x, uint16_t y) { + // color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + uint16_t original_x = screen->location.region_pos.x; + uint16_t original_y = screen->location.region_pos.y; + + uint16_t large_x = std::abs(original_x - x) / 10; + uint16_t small_x = std::abs(original_x - x) % 10; + uint16_t large_y = std::abs(original_y - y) / 10; + uint16_t small_y = std::abs(original_y - y) % 10; + + while (large_x > 0 || large_y > 0) { + if (large_x > 0 && large_y > 0) { + if (original_x - x > 0 && original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); + } + else if (original_x - x > 0 && original_y - y < 0) { + screen->feed_key(df::interface_key::CURSOR_DOWNLEFT_FAST); + } + else if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPRIGHT_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT_FAST); } + large_x--; + large_y--; + } + else if (large_x > 0) { + if (original_x - x > 0) { + screen->feed_key(df::interface_key::CURSOR_LEFT_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_RIGHT_FAST); + } + large_x--; + } + else { + if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UP_FAST); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWN_FAST); + } + large_y--; + } + } - while (small_x > 0 || small_y > 0) { - if (small_x > 0 && small_y > 0) { - if (original_x - x > 0 && original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UPLEFT); - } - else if (original_x - x > 0 && original_y - y < 0) { - screen->feed_key(df::interface_key::CURSOR_DOWNLEFT); - } - else if (original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UPRIGHT); - } - else { - screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT); - } - small_x--; - small_y--; - } - else if (small_x > 0) { - if (original_x - x > 0) { - screen->feed_key(df::interface_key::CURSOR_LEFT); - } - else { - screen->feed_key(df::interface_key::CURSOR_RIGHT); - } - small_x--; - } - else { - if (original_y - y > 0) { - screen->feed_key(df::interface_key::CURSOR_UP); - } - else { - screen->feed_key(df::interface_key::CURSOR_DOWN); - } - small_y--; - } + while (small_x > 0 || small_y > 0) { + if (small_x > 0 && small_y > 0) { + if (original_x - x > 0 && original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT); + } + else if (original_x - x > 0 && original_y - y < 0) { + screen->feed_key(df::interface_key::CURSOR_DOWNLEFT); + } + else if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UPRIGHT); } + else { + screen->feed_key(df::interface_key::CURSOR_DOWNRIGHT); + } + small_x--; + small_y--; } + else if (small_x > 0) { + if (original_x - x > 0) { + screen->feed_key(df::interface_key::CURSOR_LEFT); + } + else { + screen->feed_key(df::interface_key::CURSOR_RIGHT); + } + small_x--; + } + else { + if (original_y - y > 0) { + screen->feed_key(df::interface_key::CURSOR_UP); + } + else { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + small_y--; + } + } +} - //======================================================================================= +//======================================================================================= + +uint16_t embark_assist::matcher::find(embark_assist::defs::match_iterators *iterator, + embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::match_results *match_results) { + + color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + uint16_t x_end; + uint16_t y_end; + bool turn; + uint16_t count; + uint16_t preliminary_matches; + + if (!iterator->active) { + embark_assist::survey::clear_results(match_results); + + // Static check for impossible requirements + // + count = 0; + for (uint8_t i = 0; i < 3; i++) { + if (iterator->finder.evilness[i] == embark_assist::defs::evil_savagery_values::All) { + count++; + } + } - uint16_t find(embark_assist::defs::match_iterators *iterator, - embark_assist::defs::geo_data *geo_summary, - embark_assist::defs::world_tile_data *survey_results, - embark_assist::defs::match_results *match_results) { - - color_ostream_proxy out(Core::getInstance().getConsole()); - auto screen = Gui::getViewscreenByType(0); - uint16_t x_end; - uint16_t y_end; - bool turn; - uint16_t count; - uint16_t preliminary_matches; + if (count > 1) { + out.printerr("matcher::find: Will never find any due to multiple All evilness requirements\n"); + return 0; + } - if (!iterator->active) { - embark_assist::survey::clear_results(match_results); + count = 0; + for (uint8_t i = 0; i < 3; i++) { + if (iterator->finder.savagery[i] == embark_assist::defs::evil_savagery_values::All) { + count++; + } + } - // Static check for impossible requirements - // - count = 0; - for (uint8_t i = 0; i < 3; i++) { - if (iterator->finder.evilness[i] == embark_assist::defs::evil_savagery_values::All) { - count++; - } - } + if (count > 1) { + out.printerr("matcher::find: Will never find any due to multiple All savagery requirements\n"); + return 0; + } - if (count > 1) { - out.printerr("matcher::find: Will never find any due to multiple All evilness requirements\n"); - return 0; - } + if (iterator->finder.max_river < iterator->finder.min_river && + iterator->finder.max_river != embark_assist::defs::river_ranges::NA) { + out.printerr("matcher::find: Will never find any due to max river < min river\n"); + return 0; + } - count = 0; - for (uint8_t i = 0; i < 3; i++) { - if (iterator->finder.savagery[i] == embark_assist::defs::evil_savagery_values::All) { - count++; - } - } + if (iterator->finder.waterfall == embark_assist::defs::yes_no_ranges::Yes && + iterator->finder.max_river == embark_assist::defs::river_ranges::None) { + out.printerr("matcher::find: Will never find any waterfalls with None as max river\n"); + return 0; + } - if (count > 1) { - out.printerr("matcher::find: Will never find any due to multiple All savagery requirements\n"); - return 0; - } + if (iterator->finder.soil_max < iterator->finder.soil_min && + iterator->finder.soil_max != embark_assist::defs::soil_ranges::NA) { + out.printerr("matcher::find: Will never find any matches with max soil < min soil\n"); + return 0; + } - if (iterator->finder.max_river < iterator->finder.min_river && - iterator->finder.max_river != embark_assist::defs::river_ranges::NA) { - out.printerr("matcher::find: Will never find any due to max river < min river\n"); - return 0; - } + if (iterator->finder.biome_count_max < iterator->finder.biome_count_min && + iterator->finder.biome_count_max != -1) { + out.printerr("matcher::find: Will never find any matches with max biomes < min biomes\n"); + return 0; + } - if (iterator->finder.waterfall == embark_assist::defs::yes_no_ranges::Yes && - iterator->finder.max_river == embark_assist::defs::river_ranges::None) { - out.printerr("matcher::find: Will never find any waterfalls with None as max river\n"); - return 0; - } + preliminary_matches = preliminary_world_match(survey_results, &iterator->finder, match_results); - if (iterator->finder.soil_max < iterator->finder.soil_min && - iterator->finder.soil_max != embark_assist::defs::soil_ranges::NA) { - out.printerr("matcher::find: Will never find any matches with max soil < min soil\n"); - return 0; - } + if (preliminary_matches == 0) { + out.printerr("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); + return 0; + } + else { + out.print("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); + } - if (iterator->finder.biome_count_max < iterator->finder.biome_count_min && - iterator->finder.biome_count_max != -1) { - out.printerr("matcher::find: Will never find any matches with max biomes < min biomes\n"); - return 0; - } + while (screen->location.region_pos.x != 0 || screen->location.region_pos.y != 0) { + screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); + } + iterator->active = true; + iterator->i = 0; + iterator->k = 0; + iterator->x_right = true; + iterator->y_down = true; + iterator->inhibit_x_turn = false; + iterator->inhibit_y_turn = false; + iterator->count = 0; + } - preliminary_matches = preliminary_world_match(survey_results, &iterator->finder, match_results); + if ((iterator->k == world->worldgen.worldgen_parms.dim_x / 16 && iterator->x_right) || + (iterator->k == 0 && !iterator->x_right)) { + x_end = 0; + } + else { + x_end = 15; + } - if (preliminary_matches == 0) { - out.printerr("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); - return 0; - } - else { - out.print("matcher::find: Preliminarily matching world tiles: %i\n", preliminary_matches); - } + if (iterator->i == world->worldgen.worldgen_parms.dim_y / 16) { + y_end = 0; + } + else { + y_end = 15; + } - while (screen->location.region_pos.x != 0 || screen->location.region_pos.y != 0) { - screen->feed_key(df::interface_key::CURSOR_UPLEFT_FAST); + for (uint16_t l = 0; l <= x_end; l++) { + for (uint16_t m = 0; m <= y_end; m++) { + // This is where the payload goes + if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).preliminary_match) { + match_world_tile(geo_summary, + survey_results, + &iterator->finder, + match_results, + screen->location.region_pos.x, + screen->location.region_pos.y); + if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).contains_match) { + iterator->count++; } - iterator->active = true; - iterator->i = 0; - iterator->k = 0; - iterator->x_right = true; - iterator->y_down = true; - iterator->inhibit_x_turn = false; - iterator->inhibit_y_turn = false; - iterator->count = 0; - } - - if ((iterator->k == world->worldgen.worldgen_parms.dim_x / 16 && iterator->x_right) || - (iterator->k == 0 && !iterator->x_right)) { - x_end = 0; } else { - x_end = 15; + for (uint16_t n = 0; n < 16; n++) { + for (uint16_t p = 0; p < 16; p++) { + match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match[n][p] = false; + } + } } + // End of payload section - if (iterator->i == world->worldgen.worldgen_parms.dim_y / 16) { - y_end = 0; + if (m != y_end) { + if (iterator->y_down) { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + else { + screen->feed_key(df::interface_key::CURSOR_UP); + } } else { - y_end = 15; - } - - for (uint16_t l = 0; l <= x_end; l++) { - for (uint16_t m = 0; m <= y_end; m++) { - // This is where the payload goes - if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).preliminary_match) { - match_world_tile(geo_summary, - survey_results, - &iterator->finder, - match_results, - screen->location.region_pos.x, - screen->location.region_pos.y); - if (match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).contains_match) { - iterator->count++; - } - } - else { - for (uint16_t n = 0; n < 16; n++) { - for (uint16_t p = 0; p < 16; p++) { - match_results->at(screen->location.region_pos.x).at(screen->location.region_pos.y).mlt_match[n][p] = false; - } - } - } - // End of payload section - - if (m != y_end) { - if (iterator->y_down) { - screen->feed_key(df::interface_key::CURSOR_DOWN); - } - else { - screen->feed_key(df::interface_key::CURSOR_UP); - } - } - else { - if (screen->location.region_pos.x != 0 && - screen->location.region_pos.x != world->worldgen.worldgen_parms.dim_x - 1) { - turn = true; - } - else { - iterator->inhibit_y_turn = !iterator->inhibit_y_turn; - turn = iterator->inhibit_y_turn; - } - - if (turn) { - iterator->y_down = !iterator->y_down; - } - else { - if (iterator->y_down) { - screen->feed_key(df::interface_key::CURSOR_DOWN); - } - else { - screen->feed_key(df::interface_key::CURSOR_UP); - } - } - } - } - - if (iterator->x_right) { // Won't do anything at the edge, so we don't bother filter those cases. - screen->feed_key(df::interface_key::CURSOR_RIGHT); + if (screen->location.region_pos.x != 0 && + screen->location.region_pos.x != world->worldgen.worldgen_parms.dim_x - 1) { + turn = true; } else { - screen->feed_key(df::interface_key::CURSOR_LEFT); + iterator->inhibit_y_turn = !iterator->inhibit_y_turn; + turn = iterator->inhibit_y_turn; } - if (!iterator->x_right && - screen->location.region_pos.x == 0) { - turn = !turn; - - if (turn) { - iterator->x_right = true; - } + if (turn) { + iterator->y_down = !iterator->y_down; } - else if (iterator->x_right && - screen->location.region_pos.x == world->worldgen.worldgen_parms.dim_x - 1) { - turn = !turn; - - if (turn) { - iterator->x_right = false; + else { + if (iterator->y_down) { + screen->feed_key(df::interface_key::CURSOR_DOWN); + } + else { + screen->feed_key(df::interface_key::CURSOR_UP); } } } - // } + } - iterator->k++; - if (iterator->k > world->worldgen.worldgen_parms.dim_x / 16) - { - iterator->k = 0; - iterator->i++; - iterator->active = !(iterator->i > world->worldgen.worldgen_parms.dim_y / 16); + if (iterator->x_right) { // Won't do anything at the edge, so we don't bother filter those cases. + screen->feed_key(df::interface_key::CURSOR_RIGHT); + } + else { + screen->feed_key(df::interface_key::CURSOR_LEFT); + } - if (!iterator->active) { - move_cursor(iterator->x, iterator->y); - } + if (!iterator->x_right && + screen->location.region_pos.x == 0) { + turn = !turn; + + if (turn) { + iterator->x_right = true; } + } + else if (iterator->x_right && + screen->location.region_pos.x == world->worldgen.worldgen_parms.dim_x - 1) { + turn = !turn; - return iterator->count; + if (turn) { + iterator->x_right = false; + } } } + // } + + iterator->k++; + if (iterator->k > world->worldgen.worldgen_parms.dim_x / 16) + { + iterator->k = 0; + iterator->i++; + iterator->active = !(iterator->i > world->worldgen.worldgen_parms.dim_y / 16); + + if (!iterator->active) { + embark_assist::matcher::move_cursor(iterator->x, iterator->y); + } + } + + return iterator->count; } diff --git a/plugins/embark-assistant/screen.cpp b/plugins/embark-assistant/screen.cpp index dc634049e..477e5c63c 100644 --- a/plugins/embark-assistant/screen.cpp +++ b/plugins/embark-assistant/screen.cpp @@ -2,25 +2,26 @@ namespace embark_assist { namespace screen { - bool paintString(const DFHack::Screen::Pen &pen, int x, int y, const std::string &text, bool map) { - auto screen_size = DFHack::Screen::getWindowSize(); + } +} - if (y < 1 || y + 1 >= screen_size.y || x < 1) - { - return false; // Won't paint outside of the screen or on the frame - } +bool embark_assist::screen::paintString(const DFHack::Screen::Pen &pen, int x, int y, const std::string &text, bool map) { + auto screen_size = DFHack::Screen::getWindowSize(); - if (x + text.length() - 1 < screen_size.x - 2) { - DFHack::Screen::paintString(pen, x, y, text, map); - } - else if (x < screen_size.x - 2) { - DFHack::Screen::paintString(pen, x, y, text.substr(0, screen_size.x - 2 - x + 1), map); - } - else { - return false; - } + if (y < 1 || y + 1 >= screen_size.y || x < 1) + { + return false; // Won't paint outside of the screen or on the frame + } - return true; - } + if (x + text.length() - 1 < screen_size.x - 2) { + DFHack::Screen::paintString(pen, x, y, text, map); + } + else if (x < screen_size.x - 2) { + DFHack::Screen::paintString(pen, x, y, text.substr(0, screen_size.x - 2 - x + 1), map); } -} \ No newline at end of file + else { + return false; + } + + return true; +} diff --git a/plugins/embark-assistant/survey.cpp b/plugins/embark-assistant/survey.cpp index 308ee78d1..5c0ff95af 100644 --- a/plugins/embark-assistant/survey.cpp +++ b/plugins/embark-assistant/survey.cpp @@ -332,749 +332,750 @@ namespace embark_assist { } } } + } +} - //================================================================================= - // Exported operations - //================================================================================= +//================================================================================= +// Exported operations +//================================================================================= - void setup(uint16_t max_inorganic) { - state = new(states); - state->max_inorganic = max_inorganic; - } +void embark_assist::survey::setup(uint16_t max_inorganic) { + embark_assist::survey::state = new(embark_assist::survey::states); + embark_assist::survey::state->max_inorganic = max_inorganic; +} - //================================================================================= +//================================================================================= - df::coord2d get_last_pos() { - return{state->x, state->y}; - } +df::coord2d embark_assist::survey::get_last_pos() { + return{ embark_assist::survey::state->x, embark_assist::survey::state->y }; +} - //================================================================================= +//================================================================================= - void initiate(embark_assist::defs::mid_level_tiles *mlt) { - for (uint8_t i = 0; i < 16; i++) { - for (uint8_t k = 0; k < 16; k++) { - mlt->at(i).at(k).metals.resize(state->max_inorganic); - mlt->at(i).at(k).economics.resize(state->max_inorganic); - mlt->at(i).at(k).minerals.resize(state->max_inorganic); - } - } +void embark_assist::survey::initiate(embark_assist::defs::mid_level_tiles *mlt) { + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + mlt->at(i).at(k).metals.resize(state->max_inorganic); + mlt->at(i).at(k).economics.resize(state->max_inorganic); + mlt->at(i).at(k).minerals.resize(state->max_inorganic); } + } +} - //================================================================================= +//================================================================================= - void clear_results(embark_assist::defs::match_results *match_results) { - for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { - for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { - match_results->at(i).at(k).preliminary_match = false; - match_results->at(i).at(k).contains_match = false; +void embark_assist::survey::clear_results(embark_assist::defs::match_results *match_results) { + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + match_results->at(i).at(k).preliminary_match = false; + match_results->at(i).at(k).contains_match = false; - for (uint16_t l = 0; l < 16; l++) { - for (uint16_t m = 0; m < 16; m++) { - match_results->at(i).at(k).mlt_match[l][m] = false; - } - } + for (uint16_t l = 0; l < 16; l++) { + for (uint16_t m = 0; m < 16; m++) { + match_results->at(i).at(k).mlt_match[l][m] = false; } } } + } +} - //================================================================================= - - void high_level_world_survey(embark_assist::defs::geo_data *geo_summary, - embark_assist::defs::world_tile_data *survey_results) { -// color_ostream_proxy out(Core::getInstance().getConsole()); - - geo_survey(geo_summary); - for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { - for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { - df::coord2d adjusted; - df::world_data *world_data = world->world_data; - uint16_t geo_index; - uint16_t sav_ev; - uint8_t offset_count = 0; - survey_results->at(i).at(k).surveyed = false; - survey_results->at(i).at(k).aquifer_count = 0; - survey_results->at(i).at(k).clay_count = 0; - survey_results->at(i).at(k).sand_count = 0; - survey_results->at(i).at(k).flux_count = 0; - survey_results->at(i).at(k).min_region_soil = 10; - survey_results->at(i).at(k).max_region_soil = 0; - survey_results->at(i).at(k).waterfall = false; - survey_results->at(i).at(k).savagery_count[0] = 0; - survey_results->at(i).at(k).savagery_count[1] = 0; - survey_results->at(i).at(k).savagery_count[2] = 0; - survey_results->at(i).at(k).evilness_count[0] = 0; - survey_results->at(i).at(k).evilness_count[1] = 0; - survey_results->at(i).at(k).evilness_count[2] = 0; - survey_results->at(i).at(k).metals.resize(state->max_inorganic); - survey_results->at(i).at(k).economics.resize(state->max_inorganic); - survey_results->at(i).at(k).minerals.resize(state->max_inorganic); - // Evil weather and rivers are handled in later operations. Should probably be merged into one. - - for (uint8_t l = 1; l < 10; l++) - { - adjusted = apply_offset(i, k, l); - if (adjusted.x != i || adjusted.y != k || l == 5) { - offset_count++; +//================================================================================= - survey_results->at(i).at(k).biome_index[l] = world_data->region_map[adjusted.x][adjusted.y].region_id; - survey_results->at(i).at(k).biome[l] = get_biome_type(adjusted.x, adjusted.y, k); - geo_index = world_data->region_map[adjusted.x][adjusted.y].geo_index; +void embark_assist::survey::high_level_world_survey(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results) { + // color_ostream_proxy out(Core::getInstance().getConsole()); - if (!geo_summary->at(geo_index).aquifer_absent) survey_results->at(i).at(k).aquifer_count++; - if (!geo_summary->at(geo_index).clay_absent) survey_results->at(i).at(k).clay_count++; - if (!geo_summary->at(geo_index).sand_absent) survey_results->at(i).at(k).sand_count++; - if (!geo_summary->at(geo_index).flux_absent) survey_results->at(i).at(k).flux_count++; + embark_assist::survey::geo_survey(geo_summary); + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { + for (uint16_t k = 0; k < world->worldgen.worldgen_parms.dim_y; k++) { + df::coord2d adjusted; + df::world_data *world_data = world->world_data; + uint16_t geo_index; + uint16_t sav_ev; + uint8_t offset_count = 0; + survey_results->at(i).at(k).surveyed = false; + survey_results->at(i).at(k).aquifer_count = 0; + survey_results->at(i).at(k).clay_count = 0; + survey_results->at(i).at(k).sand_count = 0; + survey_results->at(i).at(k).flux_count = 0; + survey_results->at(i).at(k).min_region_soil = 10; + survey_results->at(i).at(k).max_region_soil = 0; + survey_results->at(i).at(k).waterfall = false; + survey_results->at(i).at(k).savagery_count[0] = 0; + survey_results->at(i).at(k).savagery_count[1] = 0; + survey_results->at(i).at(k).savagery_count[2] = 0; + survey_results->at(i).at(k).evilness_count[0] = 0; + survey_results->at(i).at(k).evilness_count[1] = 0; + survey_results->at(i).at(k).evilness_count[2] = 0; + survey_results->at(i).at(k).metals.resize(state->max_inorganic); + survey_results->at(i).at(k).economics.resize(state->max_inorganic); + survey_results->at(i).at(k).minerals.resize(state->max_inorganic); + // Evil weather and rivers are handled in later operations. Should probably be merged into one. + + for (uint8_t l = 1; l < 10; l++) + { + adjusted = apply_offset(i, k, l); + if (adjusted.x != i || adjusted.y != k || l == 5) { + offset_count++; - if (geo_summary->at(geo_index).soil_size < survey_results->at(i).at(k).min_region_soil) - survey_results->at(i).at(k).min_region_soil = geo_summary->at(geo_index).soil_size; + survey_results->at(i).at(k).biome_index[l] = world_data->region_map[adjusted.x][adjusted.y].region_id; + survey_results->at(i).at(k).biome[l] = get_biome_type(adjusted.x, adjusted.y, k); + geo_index = world_data->region_map[adjusted.x][adjusted.y].geo_index; - if (geo_summary->at(geo_index).soil_size > survey_results->at(i).at(k).max_region_soil) - survey_results->at(i).at(k).max_region_soil = geo_summary->at(geo_index).soil_size; + if (!geo_summary->at(geo_index).aquifer_absent) survey_results->at(i).at(k).aquifer_count++; + if (!geo_summary->at(geo_index).clay_absent) survey_results->at(i).at(k).clay_count++; + if (!geo_summary->at(geo_index).sand_absent) survey_results->at(i).at(k).sand_count++; + if (!geo_summary->at(geo_index).flux_absent) survey_results->at(i).at(k).flux_count++; - sav_ev = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; - if (sav_ev == 3) sav_ev = 2; - survey_results->at(i).at(k).savagery_count[sav_ev]++; + if (geo_summary->at(geo_index).soil_size < survey_results->at(i).at(k).min_region_soil) + survey_results->at(i).at(k).min_region_soil = geo_summary->at(geo_index).soil_size; - sav_ev = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; - if (sav_ev == 3) sav_ev = 2; - survey_results->at(i).at(k).evilness_count[sav_ev]++; + if (geo_summary->at(geo_index).soil_size > survey_results->at(i).at(k).max_region_soil) + survey_results->at(i).at(k).max_region_soil = geo_summary->at(geo_index).soil_size; - for (uint16_t m = 0; m < state->max_inorganic; m++) { - if (geo_summary->at(geo_index).possible_metals[m]) survey_results->at(i).at(k).metals[m] = true; - if (geo_summary->at(geo_index).possible_economics[m]) survey_results->at(i).at(k).economics[m] = true; - if (geo_summary->at(geo_index).possible_minerals[m]) survey_results->at(i).at(k).minerals[m] = true; - } - } - else { - survey_results->at(i).at(k).biome_index[l] = -1; - survey_results->at(i).at(k).biome[l] = -1; - } - } + sav_ev = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; + if (sav_ev == 3) sav_ev = 2; + survey_results->at(i).at(k).savagery_count[sav_ev]++; - survey_results->at(i).at(k).biome_count = 0; - for (uint8_t l = 1; l < 10; l++) { - if (survey_results->at(i).at(k).biome[l] != -1) survey_results->at(i).at(k).biome_count++; - } + sav_ev = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; + if (sav_ev == 3) sav_ev = 2; + survey_results->at(i).at(k).evilness_count[sav_ev]++; - if (survey_results->at(i).at(k).aquifer_count == offset_count) survey_results->at(i).at(k).aquifer_count = 256; - if (survey_results->at(i).at(k).clay_count == offset_count) survey_results->at(i).at(k).clay_count = 256; - if (survey_results->at(i).at(k).sand_count == offset_count) survey_results->at(i).at(k).sand_count = 256; - if (survey_results->at(i).at(k).flux_count == offset_count) survey_results->at(i).at(k).flux_count = 256; - for (uint8_t l = 0; l < 3; l++) { - if (survey_results->at(i).at(k).savagery_count[l] == offset_count) survey_results->at(i).at(k).savagery_count[l] = 256; - if (survey_results->at(i).at(k).evilness_count[l] == offset_count) survey_results->at(i).at(k).evilness_count[l] = 256; + for (uint16_t m = 0; m < state->max_inorganic; m++) { + if (geo_summary->at(geo_index).possible_metals[m]) survey_results->at(i).at(k).metals[m] = true; + if (geo_summary->at(geo_index).possible_economics[m]) survey_results->at(i).at(k).economics[m] = true; + if (geo_summary->at(geo_index).possible_minerals[m]) survey_results->at(i).at(k).minerals[m] = true; } } + else { + survey_results->at(i).at(k).biome_index[l] = -1; + survey_results->at(i).at(k).biome[l] = -1; + } } - survey_rivers(survey_results); - survey_evil_weather(survey_results); - } - - //================================================================================= - - void survey_mid_level_tile(embark_assist::defs::geo_data *geo_summary, - embark_assist::defs::world_tile_data *survey_results, - embark_assist::defs::mid_level_tiles *mlt) { -// color_ostream_proxy out(Core::getInstance().getConsole()); - auto screen = Gui::getViewscreenByType(0); - int16_t x = screen->location.region_pos.x; - int16_t y = screen->location.region_pos.y; - embark_assist::defs::region_tile_datum *tile = &survey_results->at(x).at(y); - int8_t max_soil_depth; - int8_t offset; - int16_t elevation; - int16_t last_bottom; - int16_t top_z; - int16_t base_z; - int16_t min_z = 0; // Initialized to silence warning about potential usage of uninitialized data. - int16_t bottom_z; - df::coord2d adjusted; - df::world_data *world_data = world->world_data; - df::world_region_details *details = world_data->region_details[0]; - df::region_map_entry *world_tile = &world_data->region_map[x][y]; - std::vector features; - uint8_t soil_erosion; - uint16_t end_check_l; - uint16_t end_check_m; - uint16_t end_check_n; - - for (uint16_t i = 0; i < state->max_inorganic; i++) { - tile->metals[i] = 0; - tile->economics[i] = 0; - tile->minerals[i] = 0; + survey_results->at(i).at(k).biome_count = 0; + for (uint8_t l = 1; l < 10; l++) { + if (survey_results->at(i).at(k).biome[l] != -1) survey_results->at(i).at(k).biome_count++; } - for (uint8_t i = 0; i < 16; i++) { - for (uint8_t k = 0; k < 16; k++) { - mlt->at(i).at(k).metals.resize(state->max_inorganic); - mlt->at(i).at(k).economics.resize(state->max_inorganic); - mlt->at(i).at(k).minerals.resize(state->max_inorganic); - } + if (survey_results->at(i).at(k).aquifer_count == offset_count) survey_results->at(i).at(k).aquifer_count = 256; + if (survey_results->at(i).at(k).clay_count == offset_count) survey_results->at(i).at(k).clay_count = 256; + if (survey_results->at(i).at(k).sand_count == offset_count) survey_results->at(i).at(k).sand_count = 256; + if (survey_results->at(i).at(k).flux_count == offset_count) survey_results->at(i).at(k).flux_count = 256; + for (uint8_t l = 0; l < 3; l++) { + if (survey_results->at(i).at(k).savagery_count[l] == offset_count) survey_results->at(i).at(k).savagery_count[l] = 256; + if (survey_results->at(i).at(k).evilness_count[l] == offset_count) survey_results->at(i).at(k).evilness_count[l] = 256; } + } + } - for (uint8_t i = 1; i < 10; i++) survey_results->at(x).at(y).biome_index[i] = -1; - - for (uint8_t i = 0; i < 16; i++) { - for (uint8_t k = 0; k < 16; k++) { - max_soil_depth = -1; - - offset = details->biome[i][k]; - adjusted = apply_offset(x, y, offset); - - if (adjusted.x != x || adjusted.y != y) - { - mlt->at(i).at(k).biome_offset = offset; - } - else - { - mlt->at(i).at(k).biome_offset = 5; - }; + embark_assist::survey::survey_rivers(survey_results); + embark_assist::survey::survey_evil_weather(survey_results); +} - survey_results->at(x).at(y).biome_index[mlt->at(i).at(k).biome_offset] = - world_data->region_map[adjusted.x][adjusted.y].region_id; +//================================================================================= + +void embark_assist::survey::survey_mid_level_tile(embark_assist::defs::geo_data *geo_summary, + embark_assist::defs::world_tile_data *survey_results, + embark_assist::defs::mid_level_tiles *mlt) { + // color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + int16_t x = screen->location.region_pos.x; + int16_t y = screen->location.region_pos.y; + embark_assist::defs::region_tile_datum *tile = &survey_results->at(x).at(y); + int8_t max_soil_depth; + int8_t offset; + int16_t elevation; + int16_t last_bottom; + int16_t top_z; + int16_t base_z; + int16_t min_z = 0; // Initialized to silence warning about potential usage of uninitialized data. + int16_t bottom_z; + df::coord2d adjusted; + df::world_data *world_data = world->world_data; + df::world_region_details *details = world_data->region_details[0]; + df::region_map_entry *world_tile = &world_data->region_map[x][y]; + std::vector features; + uint8_t soil_erosion; + uint16_t end_check_l; + uint16_t end_check_m; + uint16_t end_check_n; + + for (uint16_t i = 0; i < state->max_inorganic; i++) { + tile->metals[i] = 0; + tile->economics[i] = 0; + tile->minerals[i] = 0; + } - mlt->at(i).at(k).savagery_level = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; - if (mlt->at(i).at(k).savagery_level == 3) { - mlt->at(i).at(k).savagery_level = 2; - } - mlt->at(i).at(k).evilness_level = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; - if (mlt->at(i).at(k).evilness_level == 3) { - mlt->at(i).at(k).evilness_level = 2; - } + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + mlt->at(i).at(k).metals.resize(state->max_inorganic); + mlt->at(i).at(k).economics.resize(state->max_inorganic); + mlt->at(i).at(k).minerals.resize(state->max_inorganic); + } + } - elevation = details->elevation[i][k]; + for (uint8_t i = 1; i < 10; i++) survey_results->at(x).at(y).biome_index[i] = -1; - // Special biome adjustments - if (!world_data->region_map[adjusted.x][adjusted.y].flags.is_set(region_map_entry_flags::is_lake)) { - if (world_data->region_map[adjusted.x][adjusted.y].elevation >= 150) { // Mountain - max_soil_depth = 0; + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + max_soil_depth = -1; - } - else if (world_data->region_map[adjusted.x][adjusted.y].elevation < 100) { // Ocean - if (elevation == 99) { - elevation = 98; - } + offset = details->biome[i][k]; + adjusted = apply_offset(x, y, offset); - if ((world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 4 || - world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 5) && - details->unk12e8 < 500) { - max_soil_depth = 0; - } - } - } + if (adjusted.x != x || adjusted.y != y) + { + mlt->at(i).at(k).biome_offset = offset; + } + else + { + mlt->at(i).at(k).biome_offset = 5; + }; - base_z = elevation - 1; - features = details->features[i][k]; - std::map layer_bottom, layer_top; + survey_results->at(x).at(y).biome_index[mlt->at(i).at(k).biome_offset] = + world_data->region_map[adjusted.x][adjusted.y].region_id; - end_check_l = static_cast(features.size()); - for (size_t l = 0; l < end_check_l; l++) { - auto feature = features[l]; + mlt->at(i).at(k).savagery_level = world_data->region_map[adjusted.x][adjusted.y].savagery / 33; + if (mlt->at(i).at(k).savagery_level == 3) { + mlt->at(i).at(k).savagery_level = 2; + } + mlt->at(i).at(k).evilness_level = world_data->region_map[adjusted.x][adjusted.y].evilness / 33; + if (mlt->at(i).at(k).evilness_level == 3) { + mlt->at(i).at(k).evilness_level = 2; + } - if (feature->layer != -1 && - feature->min_z != -30000) { - auto layer = world_data->underground_regions[feature->layer]; + elevation = details->elevation[i][k]; - layer_bottom[layer->layer_depth] = feature->min_z; - layer_top[layer->layer_depth] = feature->max_z; - base_z = std::min((int)base_z, (int)feature->min_z); + // Special biome adjustments + if (!world_data->region_map[adjusted.x][adjusted.y].flags.is_set(region_map_entry_flags::is_lake)) { + if (world_data->region_map[adjusted.x][adjusted.y].elevation >= 150) { // Mountain + max_soil_depth = 0; - if (layer->type == df::world_underground_region::MagmaSea) { - min_z = feature->min_z; // The features are individual per region tile - break; - } - } + } + else if (world_data->region_map[adjusted.x][adjusted.y].elevation < 100) { // Ocean + if (elevation == 99) { + elevation = 98; } - // Compute shifts for layers in the stack. - - if (max_soil_depth == -1) { // Not set to zero by the biome - max_soil_depth = std::max((154 - elevation) / 5, 1); + if ((world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 4 || + world_data->geo_biomes[world_data->region_map[x][y].geo_index]->unk1 == 5) && + details->unk12e8 < 500) { + max_soil_depth = 0; } + } + } - soil_erosion = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - - std::min((int)geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size, (int)max_soil_depth); - int16_t layer_shift[16]; - int16_t cur_shift = elevation + soil_erosion - 1; - - mlt->at(i).at(k).aquifer = false; - mlt->at(i).at(k).clay = false; - mlt->at(i).at(k).sand = false; - mlt->at(i).at(k).flux = false; - if (max_soil_depth == 0) { - mlt->at(i).at(k).soil_depth = 0; - } - else { - mlt->at(i).at(k).soil_depth = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - soil_erosion; - } - mlt->at(i).at(k).offset = offset; - mlt->at(i).at(k).elevation = details->elevation[i][k]; - mlt->at(i).at(k).river_present = false; - mlt->at(i).at(k).river_elevation = 100; - - if (details->rivers_vertical.active[i][k] == 1) { - mlt->at(i).at(k).river_present = true; - mlt->at(i).at(k).river_elevation = details->rivers_vertical.elevation[i][k]; - } - else if (details->rivers_horizontal.active[i][k] == 1) { - mlt->at(i).at(k).river_present = true; - mlt->at(i).at(k).river_elevation = details->rivers_horizontal.elevation[i][k]; - } + base_z = elevation - 1; + features = details->features[i][k]; + std::map layer_bottom, layer_top; - if (tile->min_region_soil > mlt->at(i).at(k).soil_depth) { - tile->min_region_soil = mlt->at(i).at(k).soil_depth; - } + end_check_l = static_cast(features.size()); + for (size_t l = 0; l < end_check_l; l++) { + auto feature = features[l]; - if (tile->max_region_soil < mlt->at(i).at(k).soil_depth) { - tile->max_region_soil = mlt->at(i).at(k).soil_depth; - } + if (feature->layer != -1 && + feature->min_z != -30000) { + auto layer = world_data->underground_regions[feature->layer]; - end_check_l = static_cast(world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers.size()); - if (end_check_l > 16) end_check_l = 16; - - for (uint16_t l = 0; l < end_check_l; l++) { - auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; - layer_shift[l] = cur_shift; - - if (layer->type == df::geo_layer_type::SOIL || - layer->type == df::geo_layer_type::SOIL_SAND) { - int16_t size = layer->top_height - layer->bottom_height - 1; - // Comment copied from prospector.cpp(like the logic)... - // This is to replicate the behavior of a probable bug in the - // map generation code : if a layer is partially eroded, the - // removed levels are in fact transferred to the layer below, - // because unlike the case of removing the whole layer, the code - // does not execute a loop to shift the lower part of the stack up. - if (size > soil_erosion) { - cur_shift = cur_shift - soil_erosion; - } + layer_bottom[layer->layer_depth] = feature->min_z; + layer_top[layer->layer_depth] = feature->max_z; + base_z = std::min((int)base_z, (int)feature->min_z); - soil_erosion -= std::min((int)soil_erosion, (int)size); - } + if (layer->type == df::world_underground_region::MagmaSea) { + min_z = feature->min_z; // The features are individual per region tile + break; } + } + } - last_bottom = elevation; - // Don't have to set up the end_check as we can reuse the one above. - - for (uint16_t l = 0; l < end_check_l; l++) { - auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; - top_z = last_bottom - 1; - bottom_z = std::max((int)layer->bottom_height + layer_shift[l], (int)min_z); + // Compute shifts for layers in the stack. - if (l == 15) { - bottom_z = min_z; // stretch layer if needed - } + if (max_soil_depth == -1) { // Not set to zero by the biome + max_soil_depth = std::max((154 - elevation) / 5, 1); + } - if (top_z >= bottom_z) { - mlt->at(i).at(k).minerals[layer->mat_index] = true; + soil_erosion = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - + std::min((int)geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size, (int)max_soil_depth); + int16_t layer_shift[16]; + int16_t cur_shift = elevation + soil_erosion - 1; + + mlt->at(i).at(k).aquifer = false; + mlt->at(i).at(k).clay = false; + mlt->at(i).at(k).sand = false; + mlt->at(i).at(k).flux = false; + if (max_soil_depth == 0) { + mlt->at(i).at(k).soil_depth = 0; + } + else { + mlt->at(i).at(k).soil_depth = geo_summary->at(world_data->region_map[adjusted.x][adjusted.y].geo_index).soil_size - soil_erosion; + } + mlt->at(i).at(k).offset = offset; + mlt->at(i).at(k).elevation = details->elevation[i][k]; + mlt->at(i).at(k).river_present = false; + mlt->at(i).at(k).river_elevation = 100; + + if (details->rivers_vertical.active[i][k] == 1) { + mlt->at(i).at(k).river_present = true; + mlt->at(i).at(k).river_elevation = details->rivers_vertical.elevation[i][k]; + } + else if (details->rivers_horizontal.active[i][k] == 1) { + mlt->at(i).at(k).river_present = true; + mlt->at(i).at(k).river_elevation = details->rivers_horizontal.elevation[i][k]; + } - end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->metal_ore.mat_index.size()); + if (tile->min_region_soil > mlt->at(i).at(k).soil_depth) { + tile->min_region_soil = mlt->at(i).at(k).soil_depth; + } - for (uint16_t m = 0; m < end_check_m; m++) { - mlt->at(i).at(k).metals[world->raws.inorganics[layer->mat_index]->metal_ore.mat_index[m]] = true; - } + if (tile->max_region_soil < mlt->at(i).at(k).soil_depth) { + tile->max_region_soil = mlt->at(i).at(k).soil_depth; + } - if (layer->type == df::geo_layer_type::SOIL || - layer->type == df::geo_layer_type::SOIL_SAND) { - if (world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::SOIL_SAND)) { - mlt->at(i).at(k).sand = true; - } - } + end_check_l = static_cast(world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers.size()); + if (end_check_l > 16) end_check_l = 16; + + for (uint16_t l = 0; l < end_check_l; l++) { + auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; + layer_shift[l] = cur_shift; + + if (layer->type == df::geo_layer_type::SOIL || + layer->type == df::geo_layer_type::SOIL_SAND) { + int16_t size = layer->top_height - layer->bottom_height - 1; + // Comment copied from prospector.cpp(like the logic)... + // This is to replicate the behavior of a probable bug in the + // map generation code : if a layer is partially eroded, the + // removed levels are in fact transferred to the layer below, + // because unlike the case of removing the whole layer, the code + // does not execute a loop to shift the lower part of the stack up. + if (size > soil_erosion) { + cur_shift = cur_shift - soil_erosion; + } - if (world->raws.inorganics[layer->mat_index]->economic_uses.size() > 0) { - mlt->at(i).at(k).economics[layer->mat_index] = true; + soil_erosion -= std::min((int)soil_erosion, (int)size); + } + } - end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->economic_uses.size()); - for (uint16_t m = 0; m < end_check_m; m++) { - if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->clay_reaction) { - mlt->at(i).at(k).clay = true; - } + last_bottom = elevation; + // Don't have to set up the end_check as we can reuse the one above. - else if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->flux_reaction) { - mlt->at(i).at(k).flux = true; - } - } - } + for (uint16_t l = 0; l < end_check_l; l++) { + auto layer = world_data->geo_biomes[world_data->region_map[adjusted.x][adjusted.y].geo_index]->layers[l]; + top_z = last_bottom - 1; + bottom_z = std::max((int)layer->bottom_height + layer_shift[l], (int)min_z); - end_check_m = static_cast(layer->vein_mat.size()); + if (l == 15) { + bottom_z = min_z; // stretch layer if needed + } - for (uint16_t m = 0; m < end_check_m; m++) { - mlt->at(i).at(k).minerals[layer->vein_mat[m]] = true; + if (top_z >= bottom_z) { + mlt->at(i).at(k).minerals[layer->mat_index] = true; - end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index.size()); + end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->metal_ore.mat_index.size()); - for (uint16_t n = 0; n < end_check_n; n++) { - mlt->at(i).at(k).metals[world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index[n]] = true; - } + for (uint16_t m = 0; m < end_check_m; m++) { + mlt->at(i).at(k).metals[world->raws.inorganics[layer->mat_index]->metal_ore.mat_index[m]] = true; + } - if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size() > 0) { - mlt->at(i).at(k).economics[layer->vein_mat[m]] = true; + if (layer->type == df::geo_layer_type::SOIL || + layer->type == df::geo_layer_type::SOIL_SAND) { + if (world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::SOIL_SAND)) { + mlt->at(i).at(k).sand = true; + } + } - end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size()); - for (uint16_t n = 0; n < end_check_n; n++) { - if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->clay_reaction) { - mlt->at(i).at(k).clay = true; - } + if (world->raws.inorganics[layer->mat_index]->economic_uses.size() > 0) { + mlt->at(i).at(k).economics[layer->mat_index] = true; - else if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->flux_reaction) { - mlt->at(i).at(k).flux = true; - } - } - } + end_check_m = static_cast(world->raws.inorganics[layer->mat_index]->economic_uses.size()); + for (uint16_t m = 0; m < end_check_m; m++) { + if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->clay_reaction) { + mlt->at(i).at(k).clay = true; } - if (bottom_z <= elevation - 3 && - world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::AQUIFER)) { - mlt->at(i).at(k).aquifer = true; + else if (world->raws.inorganics[layer->mat_index]->economic_uses[m] == state->flux_reaction) { + mlt->at(i).at(k).flux = true; } } } - } - } - survey_results->at(x).at(y).aquifer_count = 0; - survey_results->at(x).at(y).clay_count = 0; - survey_results->at(x).at(y).sand_count = 0; - survey_results->at(x).at(y).flux_count = 0; - survey_results->at(x).at(y).min_region_soil = 10; - survey_results->at(x).at(y).max_region_soil = 0; - survey_results->at(x).at(y).savagery_count[0] = 0; - survey_results->at(x).at(y).savagery_count[1] = 0; - survey_results->at(x).at(y).savagery_count[2] = 0; - survey_results->at(x).at(y).evilness_count[0] = 0; - survey_results->at(x).at(y).evilness_count[1] = 0; - survey_results->at(x).at(y).evilness_count[2] = 0; - - bool river_elevation_found = false; - int16_t river_elevation; - - for (uint8_t i = 0; i < 16; i++) { - for (uint8_t k = 0; k < 16; k++) { - if (mlt->at(i).at(k).aquifer) { survey_results->at(x).at(y).aquifer_count++; } - if (mlt->at(i).at(k).clay) { survey_results->at(x).at(y).clay_count++; } - if (mlt->at(i).at(k).sand) { survey_results->at(x).at(y).sand_count++; } - if (mlt->at(i).at(k).flux) { survey_results->at(x).at(y).flux_count++; } - - if (mlt->at(i).at(k).soil_depth < survey_results->at(x).at(y).min_region_soil) { - survey_results->at(x).at(y).min_region_soil = mlt->at(i).at(k).soil_depth; - } + end_check_m = static_cast(layer->vein_mat.size()); - if (mlt->at(i).at(k).soil_depth > survey_results->at(x).at(y).max_region_soil) { - survey_results->at(x).at(y).max_region_soil = mlt->at(i).at(k).soil_depth; - } + for (uint16_t m = 0; m < end_check_m; m++) { + mlt->at(i).at(k).minerals[layer->vein_mat[m]] = true; - if (mlt->at(i).at(k).river_present) { - if (river_elevation_found) { - if (mlt->at(i).at(k).river_elevation != river_elevation) - { - survey_results->at(x).at(y).waterfall = true; - } - } - else { - river_elevation_found = true; - river_elevation = mlt->at(i).at(k).river_elevation; + end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index.size()); + + for (uint16_t n = 0; n < end_check_n; n++) { + mlt->at(i).at(k).metals[world->raws.inorganics[layer->vein_mat[m]]->metal_ore.mat_index[n]] = true; } - } - // River size surveyed separately - // biome_index handled above - // biome handled below - // evil weather handled separately - // reanimating handled separately - // thralling handled separately + if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size() > 0) { + mlt->at(i).at(k).economics[layer->vein_mat[m]] = true; - survey_results->at(x).at(y).savagery_count[mlt->at(i).at(k).savagery_level]++; - survey_results->at(x).at(y).evilness_count[mlt->at(i).at(k).evilness_level]++; + end_check_n = static_cast(world->raws.inorganics[layer->vein_mat[m]]->economic_uses.size()); + for (uint16_t n = 0; n < end_check_n; n++) { + if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->clay_reaction) { + mlt->at(i).at(k).clay = true; + } - for (uint16_t l = 0; l < state->max_inorganic; l++) { - if (mlt->at(i).at(k).metals[l]) { survey_results->at(x).at(y).metals[l] = true; } - if (mlt->at(i).at(k).economics[l]) { survey_results->at(x).at(y).economics[l] = true; } - if (mlt->at(i).at(k).minerals[l]) { survey_results->at(x).at(y).minerals[l] = true; } + else if (world->raws.inorganics[layer->vein_mat[m]]->economic_uses[n] == state->flux_reaction) { + mlt->at(i).at(k).flux = true; + } + } + } + } + + if (bottom_z <= elevation - 3 && + world->raws.inorganics[layer->mat_index]->flags.is_set(df::inorganic_flags::AQUIFER)) { + mlt->at(i).at(k).aquifer = true; } } } + } + } - for (uint8_t i = 1; i < 10; i++) { - if (survey_results->at(x).at(y).biome_index[i] == -1) { - survey_results->at(x).at(y).biome[i] = -1; - } + survey_results->at(x).at(y).aquifer_count = 0; + survey_results->at(x).at(y).clay_count = 0; + survey_results->at(x).at(y).sand_count = 0; + survey_results->at(x).at(y).flux_count = 0; + survey_results->at(x).at(y).min_region_soil = 10; + survey_results->at(x).at(y).max_region_soil = 0; + survey_results->at(x).at(y).savagery_count[0] = 0; + survey_results->at(x).at(y).savagery_count[1] = 0; + survey_results->at(x).at(y).savagery_count[2] = 0; + survey_results->at(x).at(y).evilness_count[0] = 0; + survey_results->at(x).at(y).evilness_count[1] = 0; + survey_results->at(x).at(y).evilness_count[2] = 0; + + bool river_elevation_found = false; + int16_t river_elevation; + + for (uint8_t i = 0; i < 16; i++) { + for (uint8_t k = 0; k < 16; k++) { + if (mlt->at(i).at(k).aquifer) { survey_results->at(x).at(y).aquifer_count++; } + if (mlt->at(i).at(k).clay) { survey_results->at(x).at(y).clay_count++; } + if (mlt->at(i).at(k).sand) { survey_results->at(x).at(y).sand_count++; } + if (mlt->at(i).at(k).flux) { survey_results->at(x).at(y).flux_count++; } + + if (mlt->at(i).at(k).soil_depth < survey_results->at(x).at(y).min_region_soil) { + survey_results->at(x).at(y).min_region_soil = mlt->at(i).at(k).soil_depth; } - bool biomes[ENUM_LAST_ITEM(biome_type) + 1]; - for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { - biomes[i] = false; + if (mlt->at(i).at(k).soil_depth > survey_results->at(x).at(y).max_region_soil) { + survey_results->at(x).at(y).max_region_soil = mlt->at(i).at(k).soil_depth; } - for (uint8_t i = 1; i < 10; i++) - { - if (survey_results->at(x).at(y).biome[i] != -1) { - biomes[survey_results->at(x).at(y).biome[i]] = true; + if (mlt->at(i).at(k).river_present) { + if (river_elevation_found) { + if (mlt->at(i).at(k).river_elevation != river_elevation) + { + survey_results->at(x).at(y).waterfall = true; + } + } + else { + river_elevation_found = true; + river_elevation = mlt->at(i).at(k).river_elevation; } } - int count = 0; - for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { - if (biomes[i]) count++; - } - - tile->biome_count = count; - tile->surveyed = true; - } - //================================================================================= - df::coord2d apply_offset(uint16_t x, uint16_t y, int8_t offset) { - df::coord2d result; - result.x = x; - result.y = y; - - switch (offset) { - case 1: - result.x--; - result.y++; - break; - - case 2: - result.y++; - break; - - case 3: - result.x++; - result.y++; - break; - - case 4: - result.x--; - break; - - case 5: - break; // Center. No change - - case 6: - result.x++; - break; - - case 7: - result.x--; - result.y--; - break; - - case 8: - result.y--; - break; - - case 9: - result.x++; - result.y--; - break; - - default: - // Bug. Just act as if it's the center... - break; - } + // River size surveyed separately + // biome_index handled above + // biome handled below + // evil weather handled separately + // reanimating handled separately + // thralling handled separately - if (result.x < 0) { - result.x = 0; - } - else if (result.x >= world->worldgen.worldgen_parms.dim_x) { - result.x = world->worldgen.worldgen_parms.dim_x - 1; - } + survey_results->at(x).at(y).savagery_count[mlt->at(i).at(k).savagery_level]++; + survey_results->at(x).at(y).evilness_count[mlt->at(i).at(k).evilness_level]++; - if (result.y < 0) { - result.y = 0; - } - else if (result.y >= world->worldgen.worldgen_parms.dim_y) { - result.y = world->worldgen.worldgen_parms.dim_y - 1; + for (uint16_t l = 0; l < state->max_inorganic; l++) { + if (mlt->at(i).at(k).metals[l]) { survey_results->at(x).at(y).metals[l] = true; } + if (mlt->at(i).at(k).economics[l]) { survey_results->at(x).at(y).economics[l] = true; } + if (mlt->at(i).at(k).minerals[l]) { survey_results->at(x).at(y).minerals[l] = true; } } + } + } - return result; + for (uint8_t i = 1; i < 10; i++) { + if (survey_results->at(x).at(y).biome_index[i] == -1) { + survey_results->at(x).at(y).biome[i] = -1; } + } - //================================================================================= + bool biomes[ENUM_LAST_ITEM(biome_type) + 1]; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { + biomes[i] = false; + } - 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); - df::world_data *world_data = world->world_data; - int8_t index = 0; - - site_list->clear(); - - for (uint32_t i = 0; i < world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites.size(); i++) { - auto site = world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites[i]; - switch (site->type) { - case df::world_site_type::PlayerFortress: - case df::world_site_type::DarkFortress: - case df::world_site_type::MountainHalls: - case df::world_site_type::ForestRetreat: - case df::world_site_type::Town: - case df::world_site_type::Fortress: - break; // Already visible - - case df::world_site_type::Cave: - if (!world->worldgen.worldgen_parms.all_caves_visible) { - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'c' }); // Cave - } - break; + for (uint8_t i = 1; i < 10; i++) + { + if (survey_results->at(x).at(y).biome[i] != -1) { + biomes[survey_results->at(x).at(y).biome[i]] = true; + } + } + int count = 0; + for (uint8_t i = 0; i <= ENUM_LAST_ITEM(biome_type); i++) { + if (biomes[i]) count++; + } - case df::world_site_type::Monument: - if (site->subtype_info->lair_type != -1 || - site->subtype_info->is_monument == 0) { // Not Tomb, which is visible already - } - else if (site->subtype_info->lair_type == -1) { - site_list->push_back( { (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'V' }); // Vault - } - else { - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'M' }); // Any other Monument type. Pyramid? - } - break; + tile->biome_count = count; + tile->surveyed = true; +} +//================================================================================= + +df::coord2d embark_assist::survey::apply_offset(uint16_t x, uint16_t y, int8_t offset) { + df::coord2d result; + result.x = x; + result.y = y; + + switch (offset) { + case 1: + result.x--; + result.y++; + break; + + case 2: + result.y++; + break; + + case 3: + result.x++; + result.y++; + break; + + case 4: + result.x--; + break; + + case 5: + break; // Center. No change + + case 6: + result.x++; + break; + + case 7: + result.x--; + result.y--; + break; + + case 8: + result.y--; + break; + + case 9: + result.x++; + result.y--; + break; + + default: + // Bug. Just act as if it's the center... + break; + } - case df::world_site_type::ImportantLocation: - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'i' }); // Don't really know what that is... - break; + if (result.x < 0) { + result.x = 0; + } + else if (result.x >= world->worldgen.worldgen_parms.dim_x) { + result.x = world->worldgen.worldgen_parms.dim_x - 1; + } - case df::world_site_type::LairShrine: - if (site->subtype_info->lair_type == 0 || - site->subtype_info->lair_type == 1 || - site->subtype_info->lair_type == 4) { // Only Rocs seen. Mountain lair? - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'l' }); // Lair - } - else if (site->subtype_info->lair_type == 2) { - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'L' }); // Labyrinth - } - else if (site->subtype_info->lair_type == 3) { - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'S' }); // Shrine - } - else { - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '?' }); // Can these exist? - } - break; + if (result.y < 0) { + result.y = 0; + } + else if (result.y >= world->worldgen.worldgen_parms.dim_y) { + result.y = world->worldgen.worldgen_parms.dim_y - 1; + } - case df::world_site_type::Camp: - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'C' }); // Camp - break; + return result; +} - default: - site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '!' }); // Not even in the enum... - break; - } +//================================================================================= + +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); + df::world_data *world_data = world->world_data; + int8_t index = 0; + + site_list->clear(); + + for (uint32_t i = 0; i < world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites.size(); i++) { + auto site = world_data->region_map[screen->location.region_pos.x][screen->location.region_pos.y].sites[i]; + switch (site->type) { + case df::world_site_type::PlayerFortress: + case df::world_site_type::DarkFortress: + case df::world_site_type::MountainHalls: + case df::world_site_type::ForestRetreat: + case df::world_site_type::Town: + case df::world_site_type::Fortress: + break; // Already visible + + case df::world_site_type::Cave: + if (!world->worldgen.worldgen_parms.all_caves_visible) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'c' }); // Cave } - } + break; - //================================================================================= + case df::world_site_type::Monument: + if (site->subtype_info->lair_type != -1 || + site->subtype_info->is_monument == 0) { // Not Tomb, which is visible already + } + else if (site->subtype_info->lair_type == -1) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'V' }); // Vault + } + else { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'M' }); // Any other Monument type. Pyramid? + } + break; - void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles *mlt, - embark_assist::defs::site_infos *site_info, - bool use_cache) { + case df::world_site_type::ImportantLocation: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'i' }); // Don't really know what that is... + break; -// color_ostream_proxy out(Core::getInstance().getConsole()); - auto screen = Gui::getViewscreenByType(0); - int16_t elevation; - uint16_t x = screen->location.region_pos.x; - uint16_t y = screen->location.region_pos.y; - bool river_found = false; - int16_t river_elevation; - std::vector metals(state->max_inorganic); - std::vector economics(state->max_inorganic); - std::vector minerals(state->max_inorganic); - - 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; - state->local_min_y = screen->location.embark_pos_min.y; - state->local_max_x = screen->location.embark_pos_max.x; - state->local_max_y = screen->location.embark_pos_max.y; + case df::world_site_type::LairShrine: + if (site->subtype_info->lair_type == 0 || + site->subtype_info->lair_type == 1 || + site->subtype_info->lair_type == 4) { // Only Rocs seen. Mountain lair? + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'l' }); // Lair } + else if (site->subtype_info->lair_type == 2) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'L' }); // Labyrinth + } + else if (site->subtype_info->lair_type == 3) { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'S' }); // Shrine + } + else { + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '?' }); // Can these exist? + } + break; - state->x = x; - state->y = y; - - site_info->aquifer = false; - site_info->aquifer_full = true; - site_info->min_soil = 10; - site_info->max_soil = 0; - site_info->flat = true; - site_info->waterfall = false; - site_info->clay = false; - site_info->sand = false; - site_info->flux = false; - site_info->metals.clear(); - site_info->economics.clear(); - site_info->metals.clear(); - - for (uint8_t i = state->local_min_x; i <= state->local_max_x; i++) { - for (uint8_t k = state->local_min_y; k <= state->local_max_y; k++) { - if (mlt->at(i).at(k).aquifer) { - site_info->aquifer = true; - } - else { - site_info->aquifer_full = false; - } - - if (mlt->at(i).at(k).soil_depth < site_info->min_soil) { - site_info->min_soil = mlt->at(i).at(k).soil_depth; - } + case df::world_site_type::Camp: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, 'C' }); // Camp + break; - if (mlt->at(i).at(k).soil_depth > site_info->max_soil) { - site_info->max_soil = mlt->at(i).at(k).soil_depth; - } + default: + site_list->push_back({ (uint8_t)site->rgn_min_x , (uint8_t)site->rgn_min_y, '!' }); // Not even in the enum... + break; + } + } +} - if (i == state->local_min_x && k == state->local_min_y) { - elevation = mlt->at(i).at(k).elevation; +//================================================================================= + +void embark_assist::survey::survey_embark(embark_assist::defs::mid_level_tiles *mlt, + embark_assist::defs::site_infos *site_info, + bool use_cache) { + + // color_ostream_proxy out(Core::getInstance().getConsole()); + auto screen = Gui::getViewscreenByType(0); + int16_t elevation; + uint16_t x = screen->location.region_pos.x; + uint16_t y = screen->location.region_pos.y; + bool river_found = false; + int16_t river_elevation; + std::vector metals(state->max_inorganic); + std::vector economics(state->max_inorganic); + std::vector minerals(state->max_inorganic); + + 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; + state->local_min_y = screen->location.embark_pos_min.y; + state->local_max_x = screen->location.embark_pos_max.x; + state->local_max_y = screen->location.embark_pos_max.y; + } - } - else if (elevation != mlt->at(i).at(k).elevation) { - site_info->flat = false; - } + state->x = x; + state->y = y; + + site_info->aquifer = false; + site_info->aquifer_full = true; + site_info->min_soil = 10; + site_info->max_soil = 0; + site_info->flat = true; + site_info->waterfall = false; + site_info->clay = false; + site_info->sand = false; + site_info->flux = false; + site_info->metals.clear(); + site_info->economics.clear(); + site_info->metals.clear(); + + for (uint8_t i = state->local_min_x; i <= state->local_max_x; i++) { + for (uint8_t k = state->local_min_y; k <= state->local_max_y; k++) { + if (mlt->at(i).at(k).aquifer) { + site_info->aquifer = true; + } + else { + site_info->aquifer_full = false; + } - if (mlt->at(i).at(k).river_present) { - if (river_found) { - if (river_elevation != mlt->at(i).at(k).river_elevation) { - site_info->waterfall = true; - } - } - else { - river_elevation = mlt->at(i).at(k).river_elevation; - river_found = true; - } - } + if (mlt->at(i).at(k).soil_depth < site_info->min_soil) { + site_info->min_soil = mlt->at(i).at(k).soil_depth; + } - if (mlt->at(i).at(k).clay) { - site_info->clay = true; - } + if (mlt->at(i).at(k).soil_depth > site_info->max_soil) { + site_info->max_soil = mlt->at(i).at(k).soil_depth; + } - if (mlt->at(i).at(k).sand) { - site_info->sand = true; - } + if (i == state->local_min_x && k == state->local_min_y) { + elevation = mlt->at(i).at(k).elevation; - if (mlt->at(i).at(k).flux) { - site_info->flux = true; - } + } + else if (elevation != mlt->at(i).at(k).elevation) { + site_info->flat = false; + } - 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 (mlt->at(i).at(k).river_present) { + if (river_found) { + if (river_elevation != mlt->at(i).at(k).river_elevation) { + site_info->waterfall = true; } } - } - for (uint16_t l = 0; l < state->max_inorganic; l++) { - if (metals[l]) { - site_info->metals.push_back(l); + else { + river_elevation = mlt->at(i).at(k).river_elevation; + river_found = true; } + } - if (economics[l]) { - site_info->economics.push_back(l); - } + if (mlt->at(i).at(k).clay) { + site_info->clay = true; + } - if (minerals[l]) { - site_info->minerals.push_back(l); - } + if (mlt->at(i).at(k).sand) { + site_info->sand = true; + } + + if (mlt->at(i).at(k).flux) { + site_info->flux = 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]; + } + } + } + for (uint16_t l = 0; l < state->max_inorganic; l++) { + if (metals[l]) { + site_info->metals.push_back(l); } - //================================================================================= + if (economics[l]) { + site_info->economics.push_back(l); + } - void embark_assist::survey::shutdown() { - delete state; + if (minerals[l]) { + site_info->minerals.push_back(l); } } } + +//================================================================================= + +void embark_assist::survey::shutdown() { + delete state; +} + From 8a81f6b5f717ad65f0f658c9c3a8ad36086c4eba Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 17:14:21 +0200 Subject: [PATCH 006/170] Removed extra qualification to make Travis happy. --- plugins/embark-assistant/help_ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp index 9fe79e210..d75d00ce2 100644 --- a/plugins/embark-assistant/help_ui.cpp +++ b/plugins/embark-assistant/help_ui.cpp @@ -24,7 +24,7 @@ namespace embark_assist{ class ViewscreenHelpUi : public dfhack_viewscreen { public: - ViewscreenHelpUi::ViewscreenHelpUi(); + ViewscreenHelpUi(); void feed(std::set *input); From c2b36f0979b9ffefdbc933fb514ec59a69e5614b Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 1 Sep 2017 17:29:55 +0200 Subject: [PATCH 007/170] Removed extra qualification to make Travis happy. --- plugins/embark-assistant/survey.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/embark-assistant/survey.cpp b/plugins/embark-assistant/survey.cpp index 5c0ff95af..ace97e5b1 100644 --- a/plugins/embark-assistant/survey.cpp +++ b/plugins/embark-assistant/survey.cpp @@ -269,7 +269,7 @@ namespace embark_assist { } else if (interaction->targets[k]->getType() == 2) {// Returns wrong type.. Should be df::interaction_target_type::MATERIAL df::interaction_target_materialst* material = static_cast(interaction->targets[k]); - if (DFHack::MaterialInfo::MaterialInfo(material->anon_1, material->anon_2).isInorganic()) { + if (DFHack::MaterialInfo(material->anon_1, material->anon_2).isInorganic()) { for (uint16_t l = 0; l < world->raws.inorganics[material->anon_2]->material.syndrome.size(); l++) { for (uint16_t m = 0; m < world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce.size(); m++) { if (world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce[m]->getType() == df::creature_interaction_effect_type::FLASH_TILE) { From d0090223113823b759681b46f30ecf12f7574723 Mon Sep 17 00:00:00 2001 From: David Timm Date: Tue, 17 Oct 2017 13:43:20 -0600 Subject: [PATCH 008/170] Add tree product exclusions to autochop --- plugins/autochop.cpp | 162 ++++++++++++++++++++++++++++++------------- 1 file changed, 112 insertions(+), 50 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index dbc79af42..48f0a7626 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -16,6 +16,7 @@ #include "df/items_other_id.h" #include "df/job.h" #include "df/map_block.h" +#include "df/material.h" #include "df/plant.h" #include "df/plant_raw.h" #include "df/tile_dig_designation.h" @@ -48,6 +49,9 @@ static bool autochop_enabled = false; static int min_logs, max_logs; static const int LOG_CAP_MAX = 99999; static bool wait_for_threshold; +static bool skip_fruit_trees; +static bool skip_food_trees; +static bool skip_cook_trees; static PersistentDataItem config_autochop; @@ -179,6 +183,9 @@ static void save_config() config_autochop.ival(1) = min_logs; config_autochop.ival(2) = max_logs; config_autochop.ival(3) = wait_for_threshold; + config_autochop.ival(5) = skip_fruit_trees; + config_autochop.ival(6) = skip_food_trees; + config_autochop.ival(7) = skip_cook_trees; } static void initialize() @@ -188,6 +195,9 @@ static void initialize() min_logs = 80; max_logs = 100; wait_for_threshold = false; + skip_fruit_trees = false; + skip_food_trees = false; + skip_cook_trees = false; config_autochop = World::GetPersistentData("autochop/config"); if (config_autochop.isValid()) @@ -197,6 +207,9 @@ static void initialize() min_logs = config_autochop.ival(1); max_logs = config_autochop.ival(2); wait_for_threshold = config_autochop.ival(3); + skip_fruit_trees = config_autochop.ival(4); + skip_food_trees = config_autochop.ival(5); + skip_cook_trees = config_autochop.ival(6); } else { @@ -206,29 +219,63 @@ static void initialize() } } +static bool skip_plant(const df::plant * plant) +{ + // Skip all non-trees immediately. + if (plant->flags.bits.is_shrub) + return true; + + // Skip plants with invalid tile. + df::map_block *cur = Maps::getTileBlock(plant->pos); + if (!cur) + return true; + + int x = plant->pos.x % 16; + int y = plant->pos.y % 16; + + // Skip all unrevealed plants. + if (cur->designation[x][y].bits.hidden) + return true; + + const df::plant_raw *plant_raw = df::plant_raw::find(plant->material); + + // Skip fruit trees if set. + if (skip_fruit_trees && plant_raw->material_defs.type_drink != -1) + return true; + + if (skip_food_trees || skip_cook_trees) + { + df::material * mat; + for (int idx = 0; idx < plant_raw->material.size(); idx++) + { + mat = plant_raw->material[idx]; + if (skip_food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) + return true; + + if (skip_cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) + return true; + } + } + + df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); + if (material != tiletype_material::TREE) + return true; + + return false; +} + static int do_chop_designation(bool chop, bool count_only) { int count = 0; for (size_t i = 0; i < world->plants.all.size(); i++) { const df::plant *plant = world->plants.all[i]; - df::map_block *cur = Maps::getTileBlock(plant->pos); - if (!cur) - continue; - int x = plant->pos.x % 16; - int y = plant->pos.y % 16; - - if (plant->flags.bits.is_shrub) - continue; - if (cur->designation[x][y].bits.hidden) - continue; - df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); - if (material != tiletype_material::TREE) - continue; + if (skip_plant(plant)) + continue; - if (!count_only && !watchedBurrows.isValidPos(plant->pos)) - continue; + if (!count_only && !watchedBurrows.isValidPos(plant->pos)) + continue; if (chop && !Designations::isPlantMarked(plant)) { @@ -554,6 +601,18 @@ public: { change_max_logs(10); } + else if (input->count(interface_key::CUSTOM_F)) + { + skip_fruit_trees = !skip_fruit_trees; + } + else if (input->count(interface_key::CUSTOM_E)) + { + skip_food_trees = !skip_food_trees; + } + else if (input->count(interface_key::CUSTOM_C)) + { + skip_cook_trees = !skip_cook_trees; + } else if (enabler->tracking_on && enabler->mouse_lbut) { if (burrows_column.setHighlightByMouse()) @@ -602,41 +661,44 @@ public: OutputHotkeyString(x, y, "Designate Now", "d", true, left_margin); OutputHotkeyString(x, y, "Undesignate Now", "u", true, left_margin); OutputHotkeyString(x, y, "Toggle Burrow", "Enter", true, left_margin); - if (autochop_enabled) - { - using namespace df::enums::interface_key; - const struct { - const char *caption; - int count; - bool in_edit; - df::interface_key key; - df::interface_key skeys[4]; - } rows[] = { - {"Min Logs: ", min_logs, edit_mode == EDIT_MIN, CUSTOM_N, {CUSTOM_H, CUSTOM_J, CUSTOM_SHIFT_H, CUSTOM_SHIFT_J}}, - {"Max Logs: ", max_logs, edit_mode == EDIT_MAX, CUSTOM_M, {CUSTOM_K, CUSTOM_L, CUSTOM_SHIFT_K, CUSTOM_SHIFT_L}} - }; - for (size_t i = 0; i < sizeof(rows)/sizeof(rows[0]); ++i) - { - auto row = rows[i]; - OutputHotkeyString(x, y, row.caption, row.key); - auto prev_x = x; - if (row.in_edit) - OutputString(COLOR_LIGHTCYAN, x, y, int_to_string(row.count) + "_"); - else if (row.count <= LOG_CAP_MAX) - OutputString(COLOR_LIGHTGREEN, x, y, int_to_string(row.count)); - else - OutputString(COLOR_LIGHTBLUE, x, y, "Unlimited"); - if (edit_mode == EDIT_NONE) - { - x = std::max(x, prev_x + 10); - for (size_t j = 0; j < sizeof(row.skeys)/sizeof(row.skeys[0]); ++j) - OutputString(COLOR_LIGHTGREEN, x, y, DFHack::Screen::getKeyDisplay(row.skeys[j])); - OutputString(COLOR_WHITE, x, y, ": Step"); - } - OutputString(COLOR_WHITE, x, y, "", true, left_margin); - } - OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); - } + if (autochop_enabled) + { + using namespace df::enums::interface_key; + const struct { + const char *caption; + int count; + bool in_edit; + df::interface_key key; + df::interface_key skeys[4]; + } rows[] = { + {"Min Logs: ", min_logs, edit_mode == EDIT_MIN, CUSTOM_N, {CUSTOM_H, CUSTOM_J, CUSTOM_SHIFT_H, CUSTOM_SHIFT_J}}, + {"Max Logs: ", max_logs, edit_mode == EDIT_MAX, CUSTOM_M, {CUSTOM_K, CUSTOM_L, CUSTOM_SHIFT_K, CUSTOM_SHIFT_L}} + }; + for (size_t i = 0; i < sizeof(rows) / sizeof(rows[0]); ++i) + { + auto row = rows[i]; + OutputHotkeyString(x, y, row.caption, row.key); + auto prev_x = x; + if (row.in_edit) + OutputString(COLOR_LIGHTCYAN, x, y, int_to_string(row.count) + "_"); + else if (row.count <= LOG_CAP_MAX) + OutputString(COLOR_LIGHTGREEN, x, y, int_to_string(row.count)); + else + OutputString(COLOR_LIGHTBLUE, x, y, "Unlimited"); + if (edit_mode == EDIT_NONE) + { + x = std::max(x, prev_x + 10); + for (size_t j = 0; j < sizeof(row.skeys) / sizeof(row.skeys[0]); ++j) + OutputString(COLOR_LIGHTGREEN, x, y, DFHack::Screen::getKeyDisplay(row.skeys[j])); + OutputString(COLOR_WHITE, x, y, ": Step"); + } + OutputString(COLOR_WHITE, x, y, "", true, left_margin); + } + OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); + OutputToggleString(x, y, "Skip Fruit Trees: ", "f", skip_fruit_trees, true, left_margin); + OutputToggleString(x, y, "Skip Edible Product Trees: ", "e", skip_food_trees, true, left_margin); + OutputToggleString(x, y, "Skip Cookable Product Trees: ", "c", skip_cook_trees, true, left_margin); + } ++y; OutputString(COLOR_BROWN, x, y, "Current Counts", true, left_margin); From 3c564c64ba85f1dab9e13eb4b2bc2d9ebe7e3c04 Mon Sep 17 00:00:00 2001 From: David Timm Date: Tue, 17 Oct 2017 15:17:35 -0600 Subject: [PATCH 009/170] Fix tabs. --- plugins/autochop.cpp | 178 +++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 48f0a7626..312f5ba42 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -195,9 +195,9 @@ static void initialize() min_logs = 80; max_logs = 100; wait_for_threshold = false; - skip_fruit_trees = false; - skip_food_trees = false; - skip_cook_trees = false; + skip_fruit_trees = false; + skip_food_trees = false; + skip_cook_trees = false; config_autochop = World::GetPersistentData("autochop/config"); if (config_autochop.isValid()) @@ -221,47 +221,47 @@ static void initialize() static bool skip_plant(const df::plant * plant) { - // Skip all non-trees immediately. - if (plant->flags.bits.is_shrub) - return true; - - // Skip plants with invalid tile. - df::map_block *cur = Maps::getTileBlock(plant->pos); - if (!cur) - return true; - - int x = plant->pos.x % 16; - int y = plant->pos.y % 16; - - // Skip all unrevealed plants. - if (cur->designation[x][y].bits.hidden) - return true; - - const df::plant_raw *plant_raw = df::plant_raw::find(plant->material); - - // Skip fruit trees if set. - if (skip_fruit_trees && plant_raw->material_defs.type_drink != -1) - return true; - - if (skip_food_trees || skip_cook_trees) - { - df::material * mat; - for (int idx = 0; idx < plant_raw->material.size(); idx++) - { - mat = plant_raw->material[idx]; - if (skip_food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) - return true; - - if (skip_cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) - return true; - } - } - - df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); - if (material != tiletype_material::TREE) - return true; - - return false; + // Skip all non-trees immediately. + if (plant->flags.bits.is_shrub) + return true; + + // Skip plants with invalid tile. + df::map_block *cur = Maps::getTileBlock(plant->pos); + if (!cur) + return true; + + int x = plant->pos.x % 16; + int y = plant->pos.y % 16; + + // Skip all unrevealed plants. + if (cur->designation[x][y].bits.hidden) + return true; + + const df::plant_raw *plant_raw = df::plant_raw::find(plant->material); + + // Skip fruit trees if set. + if (skip_fruit_trees && plant_raw->material_defs.type_drink != -1) + return true; + + if (skip_food_trees || skip_cook_trees) + { + df::material * mat; + for (int idx = 0; idx < plant_raw->material.size(); idx++) + { + mat = plant_raw->material[idx]; + if (skip_food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) + return true; + + if (skip_cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) + return true; + } + } + + df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); + if (material != tiletype_material::TREE) + return true; + + return false; } static int do_chop_designation(bool chop, bool count_only) @@ -271,11 +271,11 @@ static int do_chop_designation(bool chop, bool count_only) { const df::plant *plant = world->plants.all[i]; - if (skip_plant(plant)) - continue; + if (skip_plant(plant)) + continue; - if (!count_only && !watchedBurrows.isValidPos(plant->pos)) - continue; + if (!count_only && !watchedBurrows.isValidPos(plant->pos)) + continue; if (chop && !Designations::isPlantMarked(plant)) { @@ -603,15 +603,15 @@ public: } else if (input->count(interface_key::CUSTOM_F)) { - skip_fruit_trees = !skip_fruit_trees; + skip_fruit_trees = !skip_fruit_trees; } else if (input->count(interface_key::CUSTOM_E)) { - skip_food_trees = !skip_food_trees; + skip_food_trees = !skip_food_trees; } else if (input->count(interface_key::CUSTOM_C)) { - skip_cook_trees = !skip_cook_trees; + skip_cook_trees = !skip_cook_trees; } else if (enabler->tracking_on && enabler->mouse_lbut) { @@ -661,44 +661,44 @@ public: OutputHotkeyString(x, y, "Designate Now", "d", true, left_margin); OutputHotkeyString(x, y, "Undesignate Now", "u", true, left_margin); OutputHotkeyString(x, y, "Toggle Burrow", "Enter", true, left_margin); - if (autochop_enabled) - { - using namespace df::enums::interface_key; - const struct { - const char *caption; - int count; - bool in_edit; - df::interface_key key; - df::interface_key skeys[4]; - } rows[] = { - {"Min Logs: ", min_logs, edit_mode == EDIT_MIN, CUSTOM_N, {CUSTOM_H, CUSTOM_J, CUSTOM_SHIFT_H, CUSTOM_SHIFT_J}}, - {"Max Logs: ", max_logs, edit_mode == EDIT_MAX, CUSTOM_M, {CUSTOM_K, CUSTOM_L, CUSTOM_SHIFT_K, CUSTOM_SHIFT_L}} - }; - for (size_t i = 0; i < sizeof(rows) / sizeof(rows[0]); ++i) - { - auto row = rows[i]; - OutputHotkeyString(x, y, row.caption, row.key); - auto prev_x = x; - if (row.in_edit) - OutputString(COLOR_LIGHTCYAN, x, y, int_to_string(row.count) + "_"); - else if (row.count <= LOG_CAP_MAX) - OutputString(COLOR_LIGHTGREEN, x, y, int_to_string(row.count)); - else - OutputString(COLOR_LIGHTBLUE, x, y, "Unlimited"); - if (edit_mode == EDIT_NONE) - { - x = std::max(x, prev_x + 10); - for (size_t j = 0; j < sizeof(row.skeys) / sizeof(row.skeys[0]); ++j) - OutputString(COLOR_LIGHTGREEN, x, y, DFHack::Screen::getKeyDisplay(row.skeys[j])); - OutputString(COLOR_WHITE, x, y, ": Step"); - } - OutputString(COLOR_WHITE, x, y, "", true, left_margin); - } - OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); - OutputToggleString(x, y, "Skip Fruit Trees: ", "f", skip_fruit_trees, true, left_margin); - OutputToggleString(x, y, "Skip Edible Product Trees: ", "e", skip_food_trees, true, left_margin); - OutputToggleString(x, y, "Skip Cookable Product Trees: ", "c", skip_cook_trees, true, left_margin); - } + if (autochop_enabled) + { + using namespace df::enums::interface_key; + const struct { + const char *caption; + int count; + bool in_edit; + df::interface_key key; + df::interface_key skeys[4]; + } rows[] = { + {"Min Logs: ", min_logs, edit_mode == EDIT_MIN, CUSTOM_N, {CUSTOM_H, CUSTOM_J, CUSTOM_SHIFT_H, CUSTOM_SHIFT_J}}, + {"Max Logs: ", max_logs, edit_mode == EDIT_MAX, CUSTOM_M, {CUSTOM_K, CUSTOM_L, CUSTOM_SHIFT_K, CUSTOM_SHIFT_L}} + }; + for (size_t i = 0; i < sizeof(rows) / sizeof(rows[0]); ++i) + { + auto row = rows[i]; + OutputHotkeyString(x, y, row.caption, row.key); + auto prev_x = x; + if (row.in_edit) + OutputString(COLOR_LIGHTCYAN, x, y, int_to_string(row.count) + "_"); + else if (row.count <= LOG_CAP_MAX) + OutputString(COLOR_LIGHTGREEN, x, y, int_to_string(row.count)); + else + OutputString(COLOR_LIGHTBLUE, x, y, "Unlimited"); + if (edit_mode == EDIT_NONE) + { + x = std::max(x, prev_x + 10); + for (size_t j = 0; j < sizeof(row.skeys) / sizeof(row.skeys[0]); ++j) + OutputString(COLOR_LIGHTGREEN, x, y, DFHack::Screen::getKeyDisplay(row.skeys[j])); + OutputString(COLOR_WHITE, x, y, ": Step"); + } + OutputString(COLOR_WHITE, x, y, "", true, left_margin); + } + OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); + OutputToggleString(x, y, "Skip Fruit Trees: ", "f", skip_fruit_trees, true, left_margin); + OutputToggleString(x, y, "Skip Edible Product Trees: ", "e", skip_food_trees, true, left_margin); + OutputToggleString(x, y, "Skip Cookable Product Trees: ", "c", skip_cook_trees, true, left_margin); + } ++y; OutputString(COLOR_BROWN, x, y, "Current Counts", true, left_margin); From 322964f0e6349c0da71ea5f89ebe04afe61c2e44 Mon Sep 17 00:00:00 2001 From: David Timm Date: Tue, 17 Oct 2017 16:06:33 -0600 Subject: [PATCH 010/170] Switch to explicit `interface_key` values instead of char. --- plugins/autochop.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 312f5ba42..3b75068f6 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -657,13 +657,14 @@ public: } ++y; - OutputToggleString(x, y, "Autochop", "a", autochop_enabled, true, left_margin); - OutputHotkeyString(x, y, "Designate Now", "d", true, left_margin); - OutputHotkeyString(x, y, "Undesignate Now", "u", true, left_margin); + + using namespace df::enums::interface_key; + OutputToggleString(x, y, "Autochop", CUSTOM_A, autochop_enabled, true, left_margin); + OutputHotkeyString(x, y, "Designate Now", CUSTOM_D, true, left_margin); + OutputHotkeyString(x, y, "Undesignate Now", CUSTOM_U, true, left_margin); OutputHotkeyString(x, y, "Toggle Burrow", "Enter", true, left_margin); if (autochop_enabled) { - using namespace df::enums::interface_key; const struct { const char *caption; int count; @@ -695,9 +696,9 @@ public: OutputString(COLOR_WHITE, x, y, "", true, left_margin); } OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); - OutputToggleString(x, y, "Skip Fruit Trees: ", "f", skip_fruit_trees, true, left_margin); - OutputToggleString(x, y, "Skip Edible Product Trees: ", "e", skip_food_trees, true, left_margin); - OutputToggleString(x, y, "Skip Cookable Product Trees: ", "c", skip_cook_trees, true, left_margin); + OutputToggleString(x, y, "Skip Fruit Trees: ", CUSTOM_F, skip_fruit_trees, true, left_margin); + OutputToggleString(x, y, "Skip Edible Product Trees: ", CUSTOM_E, skip_food_trees, true, left_margin); + OutputToggleString(x, y, "Skip Cookable Product Trees: ", CUSTOM_C, skip_cook_trees, true, left_margin); } ++y; From 7e55efa3f7eeffbaab216a234ffd260fc2c67cae Mon Sep 17 00:00:00 2001 From: Phillip Spiess Date: Mon, 27 Nov 2017 13:10:09 -0800 Subject: [PATCH 011/170] Autocomplete built in commands (die, etc.) --- library/Core.cpp | 29 +++++++++-------------------- library/include/Core.h | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 62d605fe6..4472fe9f4 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -433,6 +433,11 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std:: { std::vector possible; + // Check for possible built in commands to autocomplete first + for (auto iter = built_in_commands.begin(); iter != built_in_commands.end(); ++iter) + if (iter->substr(0, first.size()) == first) + possible.push_back(*iter); + auto plug_mgr = Core::getInstance().getPluginManager(); for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) { @@ -612,28 +617,12 @@ static std::string sc_event_name (state_change_event id) { string getBuiltinCommand(std::string cmd) { std::string builtin = ""; - if (cmd == "ls" || - cmd == "help" || - cmd == "type" || - cmd == "load" || - cmd == "unload" || - cmd == "reload" || - cmd == "enable" || - cmd == "disable" || - cmd == "plug" || - cmd == "keybinding" || - cmd == "alias" || - cmd == "fpause" || - cmd == "cls" || - cmd == "die" || - cmd == "kill-lua" || - cmd == "script" || - cmd == "hide" || - cmd == "show" || - cmd == "sc-script" - ) + + // Check our list of builtin commands from the header + if (built_in_commands.count(cmd)) builtin = cmd; + // Check for some common aliases for built in commands else if (cmd == "?" || cmd == "man") builtin = "help"; diff --git a/library/include/Core.h b/library/include/Core.h index fa65645a1..ef90550b4 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -30,6 +30,7 @@ distribution. #include #include #include +#include #include #include "Console.h" #include "modules/Graphic.h" @@ -84,6 +85,29 @@ namespace DFHack SC_UNPAUSED = 8 }; + // List of built in commands + const std::set built_in_commands = { + "ls" , + "help" , + "type" , + "load" , + "unload" , + "reload" , + "enable" , + "disable" , + "plug" , + "keybinding" , + "alias" , + "fpause" , + "cls" , + "die" , + "kill-lua" , + "script" , + "hide" , + "show" , + "sc-script" + }; + class DFHACK_EXPORT StateChangeScript { public: From bbdf157a5257ec3e92df1db69d80f54f3d4e7c4f Mon Sep 17 00:00:00 2001 From: Phillip Spiess Date: Mon, 27 Nov 2017 13:45:58 -0800 Subject: [PATCH 012/170] Fixup autocomplete built ins per IRC --- library/Core.cpp | 29 ++++++++++++++++++++++++++--- library/include/Core.h | 24 ------------------------ 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4472fe9f4..47bddbab8 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -429,14 +429,37 @@ command_result Core::runCommand(color_ostream &out, const std::string &command) return CR_NOT_IMPLEMENTED; } +// List of built in commands +static const std::set built_in_commands = { + "ls" , + "help" , + "type" , + "load" , + "unload" , + "reload" , + "enable" , + "disable" , + "plug" , + "keybinding" , + "alias" , + "fpause" , + "cls" , + "die" , + "kill-lua" , + "script" , + "hide" , + "show" , + "sc-script" +}; + static bool try_autocomplete(color_ostream &con, const std::string &first, std::string &completed) { std::vector possible; // Check for possible built in commands to autocomplete first - for (auto iter = built_in_commands.begin(); iter != built_in_commands.end(); ++iter) - if (iter->substr(0, first.size()) == first) - possible.push_back(*iter); + for (auto const &command : built_in_commands) + if (command.substr(0, first.size()) == first) + possible.push_back(command); auto plug_mgr = Core::getInstance().getPluginManager(); for (auto it = plug_mgr->begin(); it != plug_mgr->end(); ++it) diff --git a/library/include/Core.h b/library/include/Core.h index ef90550b4..fa65645a1 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -30,7 +30,6 @@ distribution. #include #include #include -#include #include #include "Console.h" #include "modules/Graphic.h" @@ -85,29 +84,6 @@ namespace DFHack SC_UNPAUSED = 8 }; - // List of built in commands - const std::set built_in_commands = { - "ls" , - "help" , - "type" , - "load" , - "unload" , - "reload" , - "enable" , - "disable" , - "plug" , - "keybinding" , - "alias" , - "fpause" , - "cls" , - "die" , - "kill-lua" , - "script" , - "hide" , - "show" , - "sc-script" - }; - class DFHACK_EXPORT StateChangeScript { public: From e174135133172b7875ba33cde7c133bc54242e99 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 2 Dec 2017 21:06:29 -0600 Subject: [PATCH 013/170] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 24b87c746..c1e116acc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 24b87c74675df5059b848c4a1b8764a293fdda1b +Subproject commit c1e116acc0cb6f4a968503215237310d29947502 From 4edc7a6f43959758250c17d4322960c038785984 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 2 Dec 2017 21:41:44 -0600 Subject: [PATCH 014/170] update DataFuncs to support vmethods with 12-13 parameters (#1192) --- library/include/DataFuncs.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h index bf8e6b244..6541ae900 100644 --- a/library/include/DataFuncs.h +++ b/library/include/DataFuncs.h @@ -221,6 +221,29 @@ INSTANTIATE_WRAPPERS(11, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11), LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11);) #undef FW_TARGS +#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11, class A12 +INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12)) +INSTANTIATE_WRAPPERS(12, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12), + (OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12), + (vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12), + (out,vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4); + LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7); LOAD_ARG(A8); + LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11); LOAD_ARG(A12);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11, class A12, class A13 +INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13)) +INSTANTIATE_WRAPPERS(13, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13), + (OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13), + (vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12,vA13), + (out,vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11,vA12,vA13), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4); + LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7); LOAD_ARG(A8); + LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11); LOAD_ARG(A12); + LOAD_ARG(A13);) +#undef FW_TARGS + #undef FW_TARGSC #undef INSTANTIATE_WRAPPERS #undef INSTANTIATE_WRAPPERS2 From 1489e7db824cc6323de14772fbf0f121ecd0860b Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 2 Dec 2017 22:14:04 -0600 Subject: [PATCH 015/170] update structures - fix unit_personality and historical_figure_info.personality --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index c1e116acc..487eb45e2 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c1e116acc0cb6f4a968503215237310d29947502 +Subproject commit 487eb45e2d083aee1ca104c6fb1a33942b2448d2 From ec06ed09c900a9381cb3a72ff7829bfcd5b835be Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 3 Dec 2017 13:49:57 -0600 Subject: [PATCH 016/170] update structures - add remaining Linux 64-bit offsets --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 487eb45e2..3abfb36a1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 487eb45e2d083aee1ca104c6fb1a33942b2448d2 +Subproject commit 3abfb36a129add730599cf27684b2c65ff7ba6bb From c72ae8d8a77958cbe8bc9447ae0e14fff53b9f8b Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 3 Dec 2017 20:05:08 -0600 Subject: [PATCH 017/170] Merge "announcements" global into d_init where it belongs --- library/modules/Gui.cpp | 8 ++++---- library/xml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 7de9a5e11..c3fad806f 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -48,12 +48,12 @@ using namespace DFHack; #include "DataDefs.h" #include "df/announcement_flags.h" -#include "df/announcements.h" #include "df/assign_trade_status.h" #include "df/building_civzonest.h" #include "df/building_furnacest.h" #include "df/building_trapst.h" #include "df/building_workshopst.h" +#include "df/d_init.h" #include "df/game_mode.h" #include "df/general_ref.h" #include "df/global_objects.h" @@ -1428,13 +1428,13 @@ void Gui::showAutoAnnouncement( df::announcement_type type, df::coord pos, std::string message, int color, bool bright, df::unit *unit1, df::unit *unit2 ) { - using df::global::announcements; + using df::global::d_init; df::announcement_flags flags; flags.bits.D_DISPLAY = flags.bits.A_DISPLAY = true; - if (is_valid_enum_item(type) && announcements) - flags = announcements->flags[type]; + if (is_valid_enum_item(type) && d_init) + flags = d_init->announcements.flags[type]; int id = makeAnnouncement(type, flags, pos, message, color, bright); diff --git a/library/xml b/library/xml index 3abfb36a1..9ffd5971b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3abfb36a129add730599cf27684b2c65ff7ba6bb +Subproject commit 9ffd5971bd4709abec914715cee1a23963b7ee91 From 88c7e493b8c4ed4c1449e047a466556e05f5c9f4 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sun, 3 Dec 2017 20:34:59 -0600 Subject: [PATCH 018/170] Merge ui_area_map_width into ui_menu_width, now a 2-byte array --- library/lua/gui/dwarfmode.lua | 4 ++-- library/modules/Gui.cpp | 13 ++++++------- library/xml | 2 +- plugins/fix-armory.cpp | 2 -- plugins/rendermax/renderer_light.cpp | 4 ++-- plugins/rendermax/rendermax.cpp | 2 -- plugins/ruby/ui.rb | 6 +++--- plugins/tweak/tweak.cpp | 2 -- plugins/zone.cpp | 5 ++--- 9 files changed, 16 insertions(+), 24 deletions(-) diff --git a/library/lua/gui/dwarfmode.lua b/library/lua/gui/dwarfmode.lua index 3764c4df7..e98ba2080 100644 --- a/library/lua/gui/dwarfmode.lua +++ b/library/lua/gui/dwarfmode.lua @@ -18,8 +18,8 @@ refreshSidebar = dfhack.gui.refreshSidebar function getPanelLayout() local dims = dfhack.gui.getDwarfmodeViewDims() - local area_pos = df.global.ui_area_map_width - local menu_pos = df.global.ui_menu_width + local area_pos = df.global.ui_menu_width[1] + local menu_pos = df.global.ui_menu_width[0] if dims.menu_forced then menu_pos = area_pos - 1 diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index c3fad806f..0631e0ed7 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -108,7 +108,6 @@ using df::global::ui; using df::global::world; using df::global::selection_rect; using df::global::ui_menu_width; -using df::global::ui_area_map_width; using df::global::gamemode; static df::layer_object_listst *getLayerList(df::viewscreen_layer *layer, int idx) @@ -1508,8 +1507,8 @@ Gui::DwarfmodeDims getDwarfmodeViewDims_default() dims.area_x1 = dims.area_x2 = dims.menu_x1 = dims.menu_x2 = -1; dims.menu_forced = false; - int menu_pos = (ui_menu_width ? *ui_menu_width : 2); - int area_pos = (ui_area_map_width ? *ui_area_map_width : 3); + int menu_pos = (ui_menu_width ? (*ui_menu_width)[0] : 2); + int area_pos = (ui_menu_width ? (*ui_menu_width)[1] : 3); if (ui && ui->main.mode && menu_pos >= area_pos) { @@ -1715,14 +1714,14 @@ bool Gui::getWindowSize (int32_t &width, int32_t &height) bool Gui::getMenuWidth(uint8_t &menu_width, uint8_t &area_map_width) { - menu_width = *df::global::ui_menu_width; - area_map_width = *df::global::ui_area_map_width; + menu_width = (*df::global::ui_menu_width)[0]; + area_map_width = (*df::global::ui_menu_width)[1]; return true; } bool Gui::setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width) { - *df::global::ui_menu_width = menu_width; - *df::global::ui_area_map_width = area_map_width; + (*df::global::ui_menu_width)[0] = menu_width; + (*df::global::ui_menu_width)[1] = area_map_width; return true; } diff --git a/library/xml b/library/xml index 9ffd5971b..0a9a57154 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9ffd5971bd4709abec914715cee1a23963b7ee91 +Subproject commit 0a9a571545eaf1fd960366fd12dffe6b30add756 diff --git a/plugins/fix-armory.cpp b/plugins/fix-armory.cpp index 8b062290b..0f63b4d93 100644 --- a/plugins/fix-armory.cpp +++ b/plugins/fix-armory.cpp @@ -57,8 +57,6 @@ using df::global::ui; using df::global::world; using df::global::gamemode; using df::global::ui_build_selector; -using df::global::ui_menu_width; -using df::global::ui_area_map_width; using namespace DFHack::Gui; using Screen::Pen; diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index f0f3c92cf..199e174af 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -88,8 +88,8 @@ rect2d getMapViewport() int menu_x1=area_x2-MENU_WIDTH-1; int view_rb=w-1; - int area_pos=*df::global::ui_area_map_width; - int menu_pos=*df::global::ui_menu_width; + int area_pos=(*df::global::ui_menu_width)[1]; + int menu_pos=(*df::global::ui_menu_width)[0]; if(area_pos<3) { view_rb=area_x2; diff --git a/plugins/rendermax/rendermax.cpp b/plugins/rendermax/rendermax.cpp index 2140743ca..be8be07ba 100644 --- a/plugins/rendermax/rendermax.cpp +++ b/plugins/rendermax/rendermax.cpp @@ -36,8 +36,6 @@ REQUIRE_GLOBAL(enabler); REQUIRE_GLOBAL(gametype); REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(ui); -REQUIRE_GLOBAL(ui_area_map_width); -REQUIRE_GLOBAL(ui_menu_width); REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_z); diff --git a/plugins/ruby/ui.rb b/plugins/ruby/ui.rb index a9dd05437..9268dcb9e 100644 --- a/plugins/ruby/ui.rb +++ b/plugins/ruby/ui.rb @@ -15,15 +15,15 @@ module DFHack x, y, z = x.x, x.y, x.z if x.respond_to?(:x) # compute screen 'map' size (tiles) - menuwidth = ui_menu_width + menuwidth = ui_menu_width[0] # ui_menu_width shows only the 'tab' status - menuwidth = 1 if menuwidth == 2 and ui_area_map_width == 2 and cursor.x != -30000 + menuwidth = 1 if menuwidth == 2 and ui_menu_width[1] == 2 and cursor.x != -30000 menuwidth = 2 if menuwidth == 3 and cursor.x != -30000 w_w = gps.dimx - 2 w_h = gps.dimy - 2 case menuwidth when 1; w_w -= 55 - when 2; w_w -= (ui_area_map_width == 2 ? 24 : 31) + when 2; w_w -= (ui_menu_width[1] == 2 ? 24 : 31) end # center view diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index bf044dd58..2970f3792 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -117,12 +117,10 @@ DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(enabler); REQUIRE_GLOBAL(ui); -REQUIRE_GLOBAL(ui_area_map_width); REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_building_in_resize); REQUIRE_GLOBAL(ui_building_item_cursor); -REQUIRE_GLOBAL(ui_menu_width); REQUIRE_GLOBAL(ui_look_cursor); REQUIRE_GLOBAL(ui_sidebar_menus); REQUIRE_GLOBAL(ui_unit_view_mode); diff --git a/plugins/zone.cpp b/plugins/zone.cpp index e41704044..608216092 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -108,7 +108,6 @@ REQUIRE_GLOBAL(ui_building_assign_items); REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_menu_width); -REQUIRE_GLOBAL(ui_area_map_width); using namespace DFHack::Gui; @@ -3926,8 +3925,8 @@ public: return; int left_margin = gps->dimx - 30; - int8_t a = *ui_menu_width; - int8_t b = *ui_area_map_width; + int8_t a = (*ui_menu_width)[0]; + int8_t b = (*ui_menu_width)[1]; if ((a == 1 && b > 1) || (a == 2 && b == 2)) left_margin -= 24; From 5c9318654d56089abb221a65ba48537f9a52b561 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Dec 2017 13:31:42 -0500 Subject: [PATCH 019/170] Change release to alpha0 to avoid error from prerelease-warning --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c7838949..b43de8400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ endif() # set up versioning. set(DF_VERSION "0.44.02") -SET(DFHACK_RELEASE "r0") +SET(DFHACK_RELEASE "alpha0") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From fc952bc67f47f3298d45b20cce29f54df565ff9f Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 7 Dec 2017 14:36:44 -0500 Subject: [PATCH 020/170] Update NEWS-dev.rst --- docs/NEWS-dev.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 2be774672..2f0c3ea97 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,23 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.02-alpha1 +===================== + +Fixes +----- +- Fixed a crash that could occur if a symbol table in symbols.xml had no content +- The Lua API can now wrap functions with 12 or 13 parameters + +Structures +---------- +- The ``ui_menu_width`` global is now a 2-byte array; the second item is the + former ``ui_area_map_width`` global, which is now removed +- The former ``announcements`` global is now a field in ``d_init`` +- ``world`` fields formerly beginning with ``job_`` are now fields of + ``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list`` + + DFHack 0.43.05-beta2 ==================== From 23bb8c4f3ddb5814acfdd49b08a01da16e70db67 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 7 Dec 2017 14:37:15 -0500 Subject: [PATCH 021/170] Restore REQUIRE_GLOBAL(ui_menu_width) - used in tweak stable-cursor --- plugins/tweak/tweak.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 2970f3792..417784efb 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -122,6 +122,7 @@ REQUIRE_GLOBAL(ui_building_in_assign); REQUIRE_GLOBAL(ui_building_in_resize); REQUIRE_GLOBAL(ui_building_item_cursor); REQUIRE_GLOBAL(ui_look_cursor); +REQUIRE_GLOBAL(ui_menu_width); REQUIRE_GLOBAL(ui_sidebar_menus); REQUIRE_GLOBAL(ui_unit_view_mode); REQUIRE_GLOBAL(ui_workshop_in_add); From 622a8dacb61d7eb5165784e5a98c8512db495760 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 7 Dec 2017 14:39:15 -0500 Subject: [PATCH 022/170] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 0a9a57154..e2e256066 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0a9a571545eaf1fd960366fd12dffe6b30add756 +Subproject commit e2e256066cc4a5c427172d9d27db25b7823e4e86 diff --git a/scripts b/scripts index 09cf8dde9..252a5adbf 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 09cf8dde929e0478a869fa09ec329a27c9631113 +Subproject commit 252a5adbf1a5cae45cf7e623d3c5ce6f3aa1195d From 7721a142d8c18562ce0b7223e38240be8620cfe5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 7 Dec 2017 14:43:27 -0500 Subject: [PATCH 023/170] Add a basic Lua console API --- NEWS.rst | 7 +++++++ docs/Lua API.rst | 12 ++++++++++++ docs/NEWS-dev.rst | 3 +++ library/LuaApi.cpp | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index e55ca92c5..673ae31f9 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,6 +36,13 @@ Changelog .. contents:: :depth: 2 +DFHack future +============= + +Lua +--- +- Added a new ``dfhack.console`` API + DFHack 0.43.05-r3 ================= diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 66c2a5a07..a6a2ab8cd 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1966,6 +1966,18 @@ unless otherwise noted. ``listdir_recursive()`` returns the initial path and all components following it for each entry. +Console API +----------- + +* ``dfhack.console.clear()`` + + Clears the console; equivalent to the ``cls`` built-in command. + +* ``dfhack.console.flush()`` + + Flushes all output to the console. This can be useful when printing text that + does not end in a newline but should still be displayed. + Internal API ------------ diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 2f0c3ea97..8dfe2866b 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -53,6 +53,9 @@ Structures - ``world`` fields formerly beginning with ``job_`` are now fields of ``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list`` +API Changes +----------- +- Lua: Added a new ``dfhack.console`` API DFHack 0.43.05-beta2 ==================== diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 39b4b41cb..0bf19e93e 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2429,6 +2429,23 @@ static const luaL_Reg dfhack_designations_funcs[] = { {NULL, NULL} }; +/***** Console module *****/ + +namespace console { + void clear() { + Core::getInstance().getConsole().clear(); + } + void flush() { + Core::getInstance().getConsole() << std::flush; + } +} + +static const LuaWrapper::FunctionReg dfhack_console_module[] = { + WRAPM(console, clear), + WRAPM(console, flush), + { NULL, NULL } +}; + /***** Internal module *****/ static void *checkaddr(lua_State *L, int idx, bool allow_null = false) @@ -2964,5 +2981,6 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "screen", dfhack_screen_module, dfhack_screen_funcs); OpenModule(state, "filesystem", dfhack_filesystem_module, dfhack_filesystem_funcs); OpenModule(state, "designations", dfhack_designations_module, dfhack_designations_funcs); + OpenModule(state, "console", dfhack_console_module); OpenModule(state, "internal", dfhack_internal_module, dfhack_internal_funcs); } From 43b19c893aed218d3abb75ba3960402dc700fa49 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 7 Dec 2017 14:43:50 -0500 Subject: [PATCH 024/170] Bump version to alpha1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b43de8400..d55cd9e43 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ endif() # set up versioning. set(DF_VERSION "0.44.02") -SET(DFHACK_RELEASE "alpha0") +SET(DFHACK_RELEASE "alpha1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From ad2c939fea4292efc45abb9ff29b4f97bed3eb2b Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 8 Dec 2017 01:19:36 -0500 Subject: [PATCH 025/170] Update Authors.rst: dfhack/scripts#33 --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index a693646bf..2537abfd1 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -84,6 +84,7 @@ Patrik Lundell PatrikLundell Paul Fenwick pjf PeridexisErrant PeridexisErrant Petr Mrázek peterix +Pfhreak Pfhreak potato Priit Laes plaes Putnam Putnam3145 From cf7dbd478aac33f23d752b9075cb9e0f6eb35885 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 14 Dec 2017 12:45:35 +0100 Subject: [PATCH 026/170] Made prompt respect color reset --- library/Console-windows.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 28d98309b..99f7ace39 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -214,8 +214,11 @@ namespace DFHack { COORD pos = { (SHORT)x, (SHORT)y }; DWORD count = 0; - WriteConsoleOutputCharacterA(console_out, str, len, pos, &count); - } + CONSOLE_SCREEN_BUFFER_INFO inf = { 0 }; + GetConsoleScreenBufferInfo(console_out, &inf); + SetConsoleCursorPosition(console_out, pos); + WriteConsoleA(console_out, str, len, &count, NULL); + } void prompt_refresh() { From 14996a9d6794a8f3ecf4fc056f5662240a481b35 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Thu, 14 Dec 2017 12:46:52 +0100 Subject: [PATCH 027/170] Made prompt respect color reset --- library/Console-windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 99f7ace39..3dc687642 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -218,7 +218,7 @@ namespace DFHack GetConsoleScreenBufferInfo(console_out, &inf); SetConsoleCursorPosition(console_out, pos); WriteConsoleA(console_out, str, len, &count, NULL); - } + } void prompt_refresh() { From b1e77fa2601e6ad76c0f495e4f5a9b647e73dc5f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 16 Dec 2017 16:04:32 -0500 Subject: [PATCH 028/170] createitem: fix an issue with items teleporting to the location of another unit This was due to moveToGround() being called twice, first with the location of world.units.active[0], which caused the item to teleport to that location later. Fixes #1198 --- plugins/createitem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index e65d19793..18ce7674a 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -114,10 +114,10 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it if (!Items::moveToBuilding(mc, out_items[i], (df::building_actual *)building, 0)) out_items[i]->moveToGround(building->centerx, building->centery, building->z); } - if (on_ground) - out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z); if (move_to_cursor) out_items[i]->moveToGround(cursor->x, cursor->y, cursor->z); + else if (on_ground) + out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z); if (is_gloves) { // if the reaction creates gloves without handedness, then create 2 sets (left and right) From f59a91a0dbdce7884b6c10affdcd0441c06d799d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 16 Dec 2017 16:17:11 -0500 Subject: [PATCH 029/170] Add more warnings about Lua's delete() Closes #1170 --- docs/Lua API.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index a6a2ab8cd..520ac243a 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -125,12 +125,18 @@ All typed objects have the following built-in features: * ``ref:delete()`` - Destroys the object with the C++ ``delete`` operator. - If destructor is not available, returns *false*. + Destroys the object with the C++ ``delete`` operator. If the destructor is not + available, returns *false*. (This typically only occurs when trying to delete + an instance of a DF class with virtual methods whose vtable address has not + been found; it is impossible for ``delete()`` to determine the validity of + ``ref``.) .. warning:: - the lua reference object remains as a dangling - pointer, like a raw C++ pointer would. + ``ref`` **must** be an object allocated with ``new``, like in C++. Calling + ``obj.field:delete()`` where ``obj`` was allocated with ``new`` will not + work. After ``delete()`` returns, ``ref`` remains as a dangling pointer, + like a raw C++ pointer would. Any accesses to ``ref`` after ``ref:delete()`` + has been called are undefined behavior. * ``ref:assign(object)`` From bbd823f5b072ce93664f80d7019a78c0fb08c55f Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 16 Dec 2017 15:40:39 -0600 Subject: [PATCH 030/170] Simplify logic in createitem, to avoid similar errors in the future --- plugins/createitem.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index 18ce7674a..1f2e8a5c4 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -99,24 +99,21 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it for (size_t i = 0; i < out_items.size(); i++) { - bool on_ground = true; if (container) { - on_ground = false; out_items[i]->flags.bits.removed = 1; if (!Items::moveToContainer(mc, out_items[i], container)) out_items[i]->moveToGround(container->pos.x, container->pos.y, container->pos.z); } - if (building) + else if (building) { - on_ground = false; out_items[i]->flags.bits.removed = 1; if (!Items::moveToBuilding(mc, out_items[i], (df::building_actual *)building, 0)) out_items[i]->moveToGround(building->centerx, building->centery, building->z); } - if (move_to_cursor) + else if (move_to_cursor) out_items[i]->moveToGround(cursor->x, cursor->y, cursor->z); - else if (on_ground) + else out_items[i]->moveToGround(unit->pos.x, unit->pos.y, unit->pos.z); if (is_gloves) { From 29282a238ba02f74356a70fdde8893c1d4d5359f Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 17 Dec 2017 18:05:38 +0530 Subject: [PATCH 031/170] Bring in changes from the remoteServerUnsafe branch. --- plugins/proto/RemoteFortressReader.proto | 26 +- plugins/remotefortressreader/df_version_int.h | 2 +- .../remotefortressreader.cpp | 4590 +++++++++-------- 3 files changed, 2359 insertions(+), 2259 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 88fd03c64..62ea5ee54 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -397,6 +397,9 @@ message UnitDefinition repeated string noble_positions = 18; optional int32 rider_id = 19; repeated InventoryItem inventory = 20; + optional float subpos_x = 21; + optional float subpos_y = 22; + optional float subpos_z = 23; } message UnitList @@ -842,4 +845,25 @@ message ListRequest { optional int32 list_start = 1; optional int32 list_end = 2; -} \ No newline at end of file +} + +message Report +{ + optional int32 type = 1; + optional string text = 2; + optional ColorDefinition color = 3; + optional int32 duration = 4; + optional bool continuation = 5; + optional bool unconscious = 6; + optional bool announcement = 7; + optional int32 repeat_count = 8; + optional Coord pos = 9; + optional int32 id = 10; + optional int32 year = 11; + optional int32 time = 12; +} + +message Status +{ + repeated Report reports = 1; +} diff --git a/plugins/remotefortressreader/df_version_int.h b/plugins/remotefortressreader/df_version_int.h index d6d0bd750..35c9ed851 100644 --- a/plugins/remotefortressreader/df_version_int.h +++ b/plugins/remotefortressreader/df_version_int.h @@ -1,2 +1,2 @@ #pragma once -#define DF_VERSION_INT 43005 +#define DF_VERSION_INT 44002 diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index b543a2ab3..704c91ae1 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1,5 +1,5 @@ #include "df_version_int.h" -#define RFR_VERSION "0.18.0" +#define RFR_VERSION "0.19.0" #include #include @@ -30,6 +30,7 @@ #include "modules/Units.h" #include "modules/World.h" +#include "df/unit_action.h" #if DF_VERSION_INT > 34011 #include "df/army.h" #include "df/army_flags.h" @@ -75,7 +76,10 @@ #include "df/physical_attribute_type.h" #include "df/plant.h" #include "df/plant_raw_flags.h" +#include "df/projectile.h" +#include "df/proj_unitst.h" #include "df/region_map_entry.h" +#include "df/report.h" #include "df/site_realization_building.h" #include "df/site_realization_building_info_castle_towerst.h" #include "df/site_realization_building_info_castle_wallst.h" @@ -137,6 +141,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in static command_result GetPlantList(color_ostream &stream, const BlockRequest *in, PlantList *out); static command_result CheckHashes(color_ostream &stream, const EmptyMessage *in); static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in, UnitList *out); +static command_result GetUnitListInside(color_ostream &stream, const BlockRequest *in, UnitList *out); static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in, ViewInfo *out); static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, MapInfo *out); static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in); @@ -157,460 +162,474 @@ static command_result SetPauseState(color_ostream & stream, const SingleBool * i static command_result GetPauseState(color_ostream & stream, const EmptyMessage * in, SingleBool * out); static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out); void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); +static command_result GetReports(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Status * out); void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); const char* growth_locations[] = { - "TWIGS", - "LIGHT_BRANCHES", - "HEAVY_BRANCHES", - "TRUNK", - "ROOTS", - "CAP", - "SAPLING", - "SHRUB" + "TWIGS", + "LIGHT_BRANCHES", + "HEAVY_BRANCHES", + "TRUNK", + "ROOTS", + "CAP", + "SAPLING", + "SHRUB" }; #define GROWTH_LOCATIONS_SIZE 8 command_result dump_bp_mods(color_ostream &out, vector & parameters) { - remove("bp_appearance_mods.csv"); - ofstream output; - output.open("bp_appearance_mods.csv"); - - output << "Race Index;Race;Caste;Bodypart Token;Bodypart Name;Tissue Layer;Modifier Type;Range\n"; - - for (int creatureIndex = 0; creatureIndex < world->raws.creatures.all.size(); creatureIndex++) - { - auto creatureRaw = world->raws.creatures.all[creatureIndex]; - for (int casteIndex = 0; casteIndex < creatureRaw->caste.size(); casteIndex++) - { - df::caste_raw *casteRaw = creatureRaw->caste[casteIndex]; - for (int partIndex = 0; partIndex < casteRaw->bp_appearance.part_idx.size(); partIndex++) - { - output << creatureIndex << ";"; - output << creatureRaw->creature_id << ";"; - output << casteRaw->caste_id << ";"; - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->token << ";"; - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->name_singular[0]->c_str() << ";"; - int layer = casteRaw->bp_appearance.layer_idx[partIndex]; - if (layer < 0) - output << "N/A;"; - else - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->layers[layer]->layer_name << ";"; - output << ENUM_KEY_STR(appearance_modifier_type, casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->type) << ";"; - auto appMod = casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]; + remove("bp_appearance_mods.csv"); + ofstream output; + output.open("bp_appearance_mods.csv"); + + output << "Race Index;Race;Caste;Bodypart Token;Bodypart Name;Tissue Layer;Modifier Type;Range\n"; + + for (int creatureIndex = 0; creatureIndex < world->raws.creatures.all.size(); creatureIndex++) + { + auto creatureRaw = world->raws.creatures.all[creatureIndex]; + for (int casteIndex = 0; casteIndex < creatureRaw->caste.size(); casteIndex++) + { + df::caste_raw *casteRaw = creatureRaw->caste[casteIndex]; + for (int partIndex = 0; partIndex < casteRaw->bp_appearance.part_idx.size(); partIndex++) + { + output << creatureIndex << ";"; + output << creatureRaw->creature_id << ";"; + output << casteRaw->caste_id << ";"; + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->token << ";"; + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->name_singular[0]->c_str() << ";"; + int layer = casteRaw->bp_appearance.layer_idx[partIndex]; + if (layer < 0) + output << "N/A;"; + else + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->layers[layer]->layer_name << ";"; + output << ENUM_KEY_STR(appearance_modifier_type, casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->type) << ";"; + auto appMod = casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]; #if DF_VERSION_INT > 34011 - if (appMod->growth_rate > 0) - { - output << appMod->growth_min << " - " << appMod->growth_max << "\n"; - } - else + if (appMod->growth_rate > 0) + { + output << appMod->growth_min << " - " << appMod->growth_max << "\n"; + } + else #endif - { - output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[0] << " - "; - output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[6] << "\n"; - } - } - } - } + { + output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[0] << " - "; + output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[6] << "\n"; + } + } + } + } - output.close(); + output.close(); - return CR_OK; + return CR_OK; } command_result RemoteFortressReader_version(color_ostream &out, vector ¶meters) { - out.print(RFR_VERSION); - return CR_OK; + out.print(RFR_VERSION); + return CR_OK; } // Mandatory init function. If you have some global state, create it here. DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - //// Fill the command list with your commands. - commands.push_back(PluginCommand( - "dump_bp_mods", "Dump bodypart mods for debugging", - dump_bp_mods, false, /* true means that the command can't be used from non-interactive user interface */ - // Extended help string. Used by CR_WRONG_USAGE and the help command: - " This command does nothing at all.\n" - "Example:\n" - " isoworldremote\n" - " Does nothing.\n" - )); - commands.push_back(PluginCommand("RemoteFortressReader_version", "List the loaded RemoteFortressReader version", RemoteFortressReader_version, false, "This is used for plugin version checking.")); - return CR_OK; + //// Fill the command list with your commands. + commands.push_back(PluginCommand( + "dump_bp_mods", "Dump bodypart mods for debugging", + dump_bp_mods, false, /* true means that the command can't be used from non-interactive user interface */ + // Extended help string. Used by CR_WRONG_USAGE and the help command: + " This command does nothing at all.\n" + "Example:\n" + " isoworldremote\n" + " Does nothing.\n" + )); + commands.push_back(PluginCommand("RemoteFortressReader_version", "List the loaded RemoteFortressReader version", RemoteFortressReader_version, false, "This is used for plugin version checking.")); + return CR_OK; } +#ifndef SF_ALLOW_REMOTE +#define SF_ALLOW_REMOTE 0 +#endif // !SF_ALLOW_REMOTE + DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) { - RPCService *svc = new RPCService(); - svc->addFunction("GetMaterialList", GetMaterialList); - svc->addFunction("GetGrowthList", GetGrowthList); - svc->addFunction("GetBlockList", GetBlockList); - svc->addFunction("CheckHashes", CheckHashes); - svc->addFunction("GetTiletypeList", GetTiletypeList); - svc->addFunction("GetPlantList", GetPlantList); - svc->addFunction("GetUnitList", GetUnitList); - svc->addFunction("GetViewInfo", GetViewInfo); - svc->addFunction("GetMapInfo", GetMapInfo); - svc->addFunction("ResetMapHashes", ResetMapHashes); - svc->addFunction("GetItemList", GetItemList); - svc->addFunction("GetBuildingDefList", GetBuildingDefList); - svc->addFunction("GetWorldMap", GetWorldMap); - svc->addFunction("GetWorldMapNew", GetWorldMapNew); - svc->addFunction("GetRegionMaps", GetRegionMaps); - svc->addFunction("GetRegionMapsNew", GetRegionMapsNew); - svc->addFunction("GetCreatureRaws", GetCreatureRaws); - svc->addFunction("GetPartialCreatureRaws", GetPartialCreatureRaws); - svc->addFunction("GetWorldMapCenter", GetWorldMapCenter); - svc->addFunction("GetPlantRaws", GetPlantRaws); - svc->addFunction("GetPartialPlantRaws", GetPartialPlantRaws); - svc->addFunction("CopyScreen", CopyScreen); - svc->addFunction("PassKeyboardEvent", PassKeyboardEvent); - svc->addFunction("SendDigCommand", SendDigCommand); - svc->addFunction("SetPauseState", SetPauseState); - svc->addFunction("GetPauseState", GetPauseState); - svc->addFunction("GetVersionInfo", GetVersionInfo); - return svc; + RPCService *svc = new RPCService(); + svc->addFunction("GetMaterialList", GetMaterialList, SF_ALLOW_REMOTE); + svc->addFunction("GetGrowthList", GetGrowthList, SF_ALLOW_REMOTE); + svc->addFunction("GetBlockList", GetBlockList, SF_ALLOW_REMOTE); + svc->addFunction("CheckHashes", CheckHashes, SF_ALLOW_REMOTE); + svc->addFunction("GetTiletypeList", GetTiletypeList, SF_ALLOW_REMOTE); + svc->addFunction("GetPlantList", GetPlantList, SF_ALLOW_REMOTE); + svc->addFunction("GetUnitList", GetUnitList, SF_ALLOW_REMOTE); + svc->addFunction("GetUnitListInside", GetUnitListInside, SF_ALLOW_REMOTE); + svc->addFunction("GetViewInfo", GetViewInfo, SF_ALLOW_REMOTE); + svc->addFunction("GetMapInfo", GetMapInfo, SF_ALLOW_REMOTE); + svc->addFunction("ResetMapHashes", ResetMapHashes, SF_ALLOW_REMOTE); + svc->addFunction("GetItemList", GetItemList, SF_ALLOW_REMOTE); + svc->addFunction("GetBuildingDefList", GetBuildingDefList, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMap", GetWorldMap, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMapNew", GetWorldMapNew, SF_ALLOW_REMOTE); + svc->addFunction("GetRegionMaps", GetRegionMaps, SF_ALLOW_REMOTE); + svc->addFunction("GetRegionMapsNew", GetRegionMapsNew, SF_ALLOW_REMOTE); + svc->addFunction("GetCreatureRaws", GetCreatureRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetPartialCreatureRaws", GetPartialCreatureRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMapCenter", GetWorldMapCenter, SF_ALLOW_REMOTE); + svc->addFunction("GetPlantRaws", GetPlantRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetPartialPlantRaws", GetPartialPlantRaws, SF_ALLOW_REMOTE); + svc->addFunction("CopyScreen", CopyScreen, SF_ALLOW_REMOTE); + svc->addFunction("PassKeyboardEvent", PassKeyboardEvent, SF_ALLOW_REMOTE); + svc->addFunction("SendDigCommand", SendDigCommand, SF_ALLOW_REMOTE); + svc->addFunction("SetPauseState", SetPauseState, SF_ALLOW_REMOTE); + svc->addFunction("GetPauseState", GetPauseState, SF_ALLOW_REMOTE); + svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); + svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. DFhackCExport command_result plugin_shutdown(color_ostream &out) { - // You *MUST* kill all threads you created before this returns. - // If everything fails, just return CR_FAILURE. Your plugin will be - // in a zombie state, but things won't crash. - return CR_OK; + // You *MUST* kill all threads you created before this returns. + // If everything fails, just return CR_FAILURE. Your plugin will be + // in a zombie state, but things won't crash. + return CR_OK; } uint16_t fletcher16(uint8_t const *data, size_t bytes) { - uint16_t sum1 = 0xff, sum2 = 0xff; - - while (bytes) { - size_t tlen = bytes > 20 ? 20 : bytes; - bytes -= tlen; - do { - sum2 += sum1 += *data++; - } while (--tlen); - sum1 = (sum1 & 0xff) + (sum1 >> 8); - sum2 = (sum2 & 0xff) + (sum2 >> 8); - } - /* Second reduction step to reduce sums to 8 bits */ - sum1 = (sum1 & 0xff) + (sum1 >> 8); - sum2 = (sum2 & 0xff) + (sum2 >> 8); - return sum2 << 8 | sum1; + uint16_t sum1 = 0xff, sum2 = 0xff; + + while (bytes) { + size_t tlen = bytes > 20 ? 20 : bytes; + bytes -= tlen; + do { + sum2 += sum1 += *data++; + } while (--tlen); + sum1 = (sum1 & 0xff) + (sum1 >> 8); + sum2 = (sum2 & 0xff) + (sum2 >> 8); + } + /* Second reduction step to reduce sums to 8 bits */ + sum1 = (sum1 & 0xff) + (sum1 >> 8); + sum2 = (sum2 & 0xff) + (sum2 >> 8); + return sum2 << 8 | sum1; } void ConvertDfColor(int16_t index, RemoteFortressReader::ColorDefinition * out) { - if (!df::global::enabler) - return; + if (!df::global::enabler) + return; - auto enabler = df::global::enabler; + auto enabler = df::global::enabler; - out->set_red((int)(enabler->ccolor[index][0] * 255)); - out->set_green((int)(enabler->ccolor[index][1] * 255)); - out->set_blue((int)(enabler->ccolor[index][2] * 255)); + out->set_red((int)(enabler->ccolor[index][0] * 255)); + out->set_green((int)(enabler->ccolor[index][1] * 255)); + out->set_blue((int)(enabler->ccolor[index][2] * 255)); } void ConvertDfColor(int16_t in[3], RemoteFortressReader::ColorDefinition * out) { - int index = in[0] | (8 * in[2]); - ConvertDfColor(index, out); + int index = in[0] | (8 * in[2]); + ConvertDfColor(index, out); } void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out) { - df::descriptor_color *color = world->raws.language.colors[index]; - out->set_red(color->red * 255); - out->set_green(color->green * 255); - out->set_blue(color->blue * 255); + df::descriptor_color *color = world->raws.language.colors[index]; + out->set_red(color->red * 255); + out->set_green(color->green * 255); + out->set_blue(color->blue * 255); +} + +void ConvertDFCoord(DFCoord in, RemoteFortressReader::Coord * out) +{ + out->set_x(in.x); + out->set_y(in.y); + out->set_z(in.z); } RemoteFortressReader::TiletypeMaterial TranslateMaterial(df::tiletype_material material) { - switch (material) - { - case df::enums::tiletype_material::NONE: - return RemoteFortressReader::NO_MATERIAL; - break; - case df::enums::tiletype_material::AIR: - return RemoteFortressReader::AIR; - break; - case df::enums::tiletype_material::SOIL: - return RemoteFortressReader::SOIL; - break; - case df::enums::tiletype_material::STONE: - return RemoteFortressReader::STONE; - break; - case df::enums::tiletype_material::FEATURE: - return RemoteFortressReader::FEATURE; - break; - case df::enums::tiletype_material::LAVA_STONE: - return RemoteFortressReader::LAVA_STONE; - break; - case df::enums::tiletype_material::MINERAL: - return RemoteFortressReader::MINERAL; - break; - case df::enums::tiletype_material::FROZEN_LIQUID: - return RemoteFortressReader::FROZEN_LIQUID; - break; - case df::enums::tiletype_material::CONSTRUCTION: - return RemoteFortressReader::CONSTRUCTION; - break; - case df::enums::tiletype_material::GRASS_LIGHT: - return RemoteFortressReader::GRASS_LIGHT; - break; - case df::enums::tiletype_material::GRASS_DARK: - return RemoteFortressReader::GRASS_DARK; - break; - case df::enums::tiletype_material::GRASS_DRY: - return RemoteFortressReader::GRASS_DRY; - break; - case df::enums::tiletype_material::GRASS_DEAD: - return RemoteFortressReader::GRASS_DEAD; - break; - case df::enums::tiletype_material::PLANT: - return RemoteFortressReader::PLANT; - break; - case df::enums::tiletype_material::HFS: - return RemoteFortressReader::HFS; - break; - case df::enums::tiletype_material::CAMPFIRE: - return RemoteFortressReader::CAMPFIRE; - break; - case df::enums::tiletype_material::FIRE: - return RemoteFortressReader::FIRE; - break; - case df::enums::tiletype_material::ASHES: - return RemoteFortressReader::ASHES; - break; - case df::enums::tiletype_material::MAGMA: - return RemoteFortressReader::MAGMA; - break; - case df::enums::tiletype_material::DRIFTWOOD: - return RemoteFortressReader::DRIFTWOOD; - break; - case df::enums::tiletype_material::POOL: - return RemoteFortressReader::POOL; - break; - case df::enums::tiletype_material::BROOK: - return RemoteFortressReader::BROOK; - break; - case df::enums::tiletype_material::RIVER: - return RemoteFortressReader::RIVER; - break; + switch (material) + { + case df::enums::tiletype_material::NONE: + return RemoteFortressReader::NO_MATERIAL; + break; + case df::enums::tiletype_material::AIR: + return RemoteFortressReader::AIR; + break; + case df::enums::tiletype_material::SOIL: + return RemoteFortressReader::SOIL; + break; + case df::enums::tiletype_material::STONE: + return RemoteFortressReader::STONE; + break; + case df::enums::tiletype_material::FEATURE: + return RemoteFortressReader::FEATURE; + break; + case df::enums::tiletype_material::LAVA_STONE: + return RemoteFortressReader::LAVA_STONE; + break; + case df::enums::tiletype_material::MINERAL: + return RemoteFortressReader::MINERAL; + break; + case df::enums::tiletype_material::FROZEN_LIQUID: + return RemoteFortressReader::FROZEN_LIQUID; + break; + case df::enums::tiletype_material::CONSTRUCTION: + return RemoteFortressReader::CONSTRUCTION; + break; + case df::enums::tiletype_material::GRASS_LIGHT: + return RemoteFortressReader::GRASS_LIGHT; + break; + case df::enums::tiletype_material::GRASS_DARK: + return RemoteFortressReader::GRASS_DARK; + break; + case df::enums::tiletype_material::GRASS_DRY: + return RemoteFortressReader::GRASS_DRY; + break; + case df::enums::tiletype_material::GRASS_DEAD: + return RemoteFortressReader::GRASS_DEAD; + break; + case df::enums::tiletype_material::PLANT: + return RemoteFortressReader::PLANT; + break; + case df::enums::tiletype_material::HFS: + return RemoteFortressReader::HFS; + break; + case df::enums::tiletype_material::CAMPFIRE: + return RemoteFortressReader::CAMPFIRE; + break; + case df::enums::tiletype_material::FIRE: + return RemoteFortressReader::FIRE; + break; + case df::enums::tiletype_material::ASHES: + return RemoteFortressReader::ASHES; + break; + case df::enums::tiletype_material::MAGMA: + return RemoteFortressReader::MAGMA; + break; + case df::enums::tiletype_material::DRIFTWOOD: + return RemoteFortressReader::DRIFTWOOD; + break; + case df::enums::tiletype_material::POOL: + return RemoteFortressReader::POOL; + break; + case df::enums::tiletype_material::BROOK: + return RemoteFortressReader::BROOK; + break; + case df::enums::tiletype_material::RIVER: + return RemoteFortressReader::RIVER; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_material::ROOT: - return RemoteFortressReader::ROOT; - break; - case df::enums::tiletype_material::TREE: - return RemoteFortressReader::TREE_MATERIAL; - break; - case df::enums::tiletype_material::MUSHROOM: - return RemoteFortressReader::MUSHROOM; - break; - case df::enums::tiletype_material::UNDERWORLD_GATE: - return RemoteFortressReader::UNDERWORLD_GATE; - break; + case df::enums::tiletype_material::ROOT: + return RemoteFortressReader::ROOT; + break; + case df::enums::tiletype_material::TREE: + return RemoteFortressReader::TREE_MATERIAL; + break; + case df::enums::tiletype_material::MUSHROOM: + return RemoteFortressReader::MUSHROOM; + break; + case df::enums::tiletype_material::UNDERWORLD_GATE: + return RemoteFortressReader::UNDERWORLD_GATE; + break; #endif - default: - return RemoteFortressReader::NO_MATERIAL; - break; - } - return RemoteFortressReader::NO_MATERIAL; + default: + return RemoteFortressReader::NO_MATERIAL; + break; + } + return RemoteFortressReader::NO_MATERIAL; } RemoteFortressReader::TiletypeSpecial TranslateSpecial(df::tiletype_special special) { - switch (special) - { - case df::enums::tiletype_special::NONE: - return RemoteFortressReader::NO_SPECIAL; - break; - case df::enums::tiletype_special::NORMAL: - return RemoteFortressReader::NORMAL; - break; - case df::enums::tiletype_special::RIVER_SOURCE: - return RemoteFortressReader::RIVER_SOURCE; - break; - case df::enums::tiletype_special::WATERFALL: - return RemoteFortressReader::WATERFALL; - break; - case df::enums::tiletype_special::SMOOTH: - return RemoteFortressReader::SMOOTH; - break; - case df::enums::tiletype_special::FURROWED: - return RemoteFortressReader::FURROWED; - break; - case df::enums::tiletype_special::WET: - return RemoteFortressReader::WET; - break; - case df::enums::tiletype_special::DEAD: - return RemoteFortressReader::DEAD; - break; - case df::enums::tiletype_special::WORN_1: - return RemoteFortressReader::WORN_1; - break; - case df::enums::tiletype_special::WORN_2: - return RemoteFortressReader::WORN_2; - break; - case df::enums::tiletype_special::WORN_3: - return RemoteFortressReader::WORN_3; - break; - case df::enums::tiletype_special::TRACK: - return RemoteFortressReader::TRACK; - break; + switch (special) + { + case df::enums::tiletype_special::NONE: + return RemoteFortressReader::NO_SPECIAL; + break; + case df::enums::tiletype_special::NORMAL: + return RemoteFortressReader::NORMAL; + break; + case df::enums::tiletype_special::RIVER_SOURCE: + return RemoteFortressReader::RIVER_SOURCE; + break; + case df::enums::tiletype_special::WATERFALL: + return RemoteFortressReader::WATERFALL; + break; + case df::enums::tiletype_special::SMOOTH: + return RemoteFortressReader::SMOOTH; + break; + case df::enums::tiletype_special::FURROWED: + return RemoteFortressReader::FURROWED; + break; + case df::enums::tiletype_special::WET: + return RemoteFortressReader::WET; + break; + case df::enums::tiletype_special::DEAD: + return RemoteFortressReader::DEAD; + break; + case df::enums::tiletype_special::WORN_1: + return RemoteFortressReader::WORN_1; + break; + case df::enums::tiletype_special::WORN_2: + return RemoteFortressReader::WORN_2; + break; + case df::enums::tiletype_special::WORN_3: + return RemoteFortressReader::WORN_3; + break; + case df::enums::tiletype_special::TRACK: + return RemoteFortressReader::TRACK; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_special::SMOOTH_DEAD: - return RemoteFortressReader::SMOOTH_DEAD; - break; + case df::enums::tiletype_special::SMOOTH_DEAD: + return RemoteFortressReader::SMOOTH_DEAD; + break; #endif - default: - return RemoteFortressReader::NO_SPECIAL; - break; - } - return RemoteFortressReader::NO_SPECIAL; + default: + return RemoteFortressReader::NO_SPECIAL; + break; + } + return RemoteFortressReader::NO_SPECIAL; } RemoteFortressReader::TiletypeShape TranslateShape(df::tiletype_shape shape) { - switch (shape) - { - case df::enums::tiletype_shape::NONE: - return RemoteFortressReader::NO_SHAPE; - break; - case df::enums::tiletype_shape::EMPTY: - return RemoteFortressReader::EMPTY; - break; - case df::enums::tiletype_shape::FLOOR: - return RemoteFortressReader::FLOOR; - break; - case df::enums::tiletype_shape::BOULDER: - return RemoteFortressReader::BOULDER; - break; - case df::enums::tiletype_shape::PEBBLES: - return RemoteFortressReader::PEBBLES; - break; - case df::enums::tiletype_shape::WALL: - return RemoteFortressReader::WALL; - break; - case df::enums::tiletype_shape::FORTIFICATION: - return RemoteFortressReader::FORTIFICATION; - break; - case df::enums::tiletype_shape::STAIR_UP: - return RemoteFortressReader::STAIR_UP; - break; - case df::enums::tiletype_shape::STAIR_DOWN: - return RemoteFortressReader::STAIR_DOWN; - break; - case df::enums::tiletype_shape::STAIR_UPDOWN: - return RemoteFortressReader::STAIR_UPDOWN; - break; - case df::enums::tiletype_shape::RAMP: - return RemoteFortressReader::RAMP; - break; - case df::enums::tiletype_shape::RAMP_TOP: - return RemoteFortressReader::RAMP_TOP; - break; - case df::enums::tiletype_shape::BROOK_BED: - return RemoteFortressReader::BROOK_BED; - break; - case df::enums::tiletype_shape::BROOK_TOP: - return RemoteFortressReader::BROOK_TOP; - break; + switch (shape) + { + case df::enums::tiletype_shape::NONE: + return RemoteFortressReader::NO_SHAPE; + break; + case df::enums::tiletype_shape::EMPTY: + return RemoteFortressReader::EMPTY; + break; + case df::enums::tiletype_shape::FLOOR: + return RemoteFortressReader::FLOOR; + break; + case df::enums::tiletype_shape::BOULDER: + return RemoteFortressReader::BOULDER; + break; + case df::enums::tiletype_shape::PEBBLES: + return RemoteFortressReader::PEBBLES; + break; + case df::enums::tiletype_shape::WALL: + return RemoteFortressReader::WALL; + break; + case df::enums::tiletype_shape::FORTIFICATION: + return RemoteFortressReader::FORTIFICATION; + break; + case df::enums::tiletype_shape::STAIR_UP: + return RemoteFortressReader::STAIR_UP; + break; + case df::enums::tiletype_shape::STAIR_DOWN: + return RemoteFortressReader::STAIR_DOWN; + break; + case df::enums::tiletype_shape::STAIR_UPDOWN: + return RemoteFortressReader::STAIR_UPDOWN; + break; + case df::enums::tiletype_shape::RAMP: + return RemoteFortressReader::RAMP; + break; + case df::enums::tiletype_shape::RAMP_TOP: + return RemoteFortressReader::RAMP_TOP; + break; + case df::enums::tiletype_shape::BROOK_BED: + return RemoteFortressReader::BROOK_BED; + break; + case df::enums::tiletype_shape::BROOK_TOP: + return RemoteFortressReader::BROOK_TOP; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_shape::BRANCH: - return RemoteFortressReader::BRANCH; - break; + case df::enums::tiletype_shape::BRANCH: + return RemoteFortressReader::BRANCH; + break; #endif #if DF_VERSION_INT < 40001 - case df::enums::tiletype_shape::TREE: - return RemoteFortressReader::TREE_SHAPE; - break; + case df::enums::tiletype_shape::TREE: + return RemoteFortressReader::TREE_SHAPE; + break; #endif #if DF_VERSION_INT > 40001 - case df::enums::tiletype_shape::TRUNK_BRANCH: - return RemoteFortressReader::TRUNK_BRANCH; - break; - case df::enums::tiletype_shape::TWIG: - return RemoteFortressReader::TWIG; - break; + case df::enums::tiletype_shape::TRUNK_BRANCH: + return RemoteFortressReader::TRUNK_BRANCH; + break; + case df::enums::tiletype_shape::TWIG: + return RemoteFortressReader::TWIG; + break; #endif - case df::enums::tiletype_shape::SAPLING: - return RemoteFortressReader::SAPLING; - break; - case df::enums::tiletype_shape::SHRUB: - return RemoteFortressReader::SHRUB; - break; - case df::enums::tiletype_shape::ENDLESS_PIT: - return RemoteFortressReader::EMPTY; - break; - default: - return RemoteFortressReader::NO_SHAPE; - break; - } - return RemoteFortressReader::NO_SHAPE; + case df::enums::tiletype_shape::SAPLING: + return RemoteFortressReader::SAPLING; + break; + case df::enums::tiletype_shape::SHRUB: + return RemoteFortressReader::SHRUB; + break; + case df::enums::tiletype_shape::ENDLESS_PIT: + return RemoteFortressReader::EMPTY; + break; + default: + return RemoteFortressReader::NO_SHAPE; + break; + } + return RemoteFortressReader::NO_SHAPE; } RemoteFortressReader::TiletypeVariant TranslateVariant(df::tiletype_variant variant) { - switch (variant) - { - case df::enums::tiletype_variant::NONE: - return RemoteFortressReader::NO_VARIANT; - break; - case df::enums::tiletype_variant::VAR_1: - return RemoteFortressReader::VAR_1; - break; - case df::enums::tiletype_variant::VAR_2: - return RemoteFortressReader::VAR_2; - break; - case df::enums::tiletype_variant::VAR_3: - return RemoteFortressReader::VAR_3; - break; - case df::enums::tiletype_variant::VAR_4: - return RemoteFortressReader::VAR_4; - break; - default: - return RemoteFortressReader::NO_VARIANT; - break; - } - return RemoteFortressReader::NO_VARIANT; + switch (variant) + { + case df::enums::tiletype_variant::NONE: + return RemoteFortressReader::NO_VARIANT; + break; + case df::enums::tiletype_variant::VAR_1: + return RemoteFortressReader::VAR_1; + break; + case df::enums::tiletype_variant::VAR_2: + return RemoteFortressReader::VAR_2; + break; + case df::enums::tiletype_variant::VAR_3: + return RemoteFortressReader::VAR_3; + break; + case df::enums::tiletype_variant::VAR_4: + return RemoteFortressReader::VAR_4; + break; + default: + return RemoteFortressReader::NO_VARIANT; + break; + } + return RemoteFortressReader::NO_VARIANT; } static command_result CheckHashes(color_ostream &stream, const EmptyMessage *in) { - clock_t start = clock(); - for (int i = 0; i < world->map.map_blocks.size(); i++) - { - df::map_block * block = world->map.map_blocks[i]; - fletcher16((uint8_t*)(block->tiletype), 16 * 16 * sizeof(df::enums::tiletype::tiletype)); - } - clock_t end = clock(); - double elapsed_secs = double(end - start) / CLOCKS_PER_SEC; - stream.print("Checking all hashes took %f seconds.", elapsed_secs); - return CR_OK; + clock_t start = clock(); + for (int i = 0; i < world->map.map_blocks.size(); i++) + { + df::map_block * block = world->map.map_blocks[i]; + fletcher16((uint8_t*)(block->tiletype), 16 * 16 * sizeof(df::enums::tiletype::tiletype)); + } + clock_t end = clock(); + double elapsed_secs = double(end - start) / CLOCKS_PER_SEC; + stream.print("Checking all hashes took %f seconds.", elapsed_secs); + return CR_OK; } void CopyMat(RemoteFortressReader::MatPair * mat, int type, int index) { - if (type >= MaterialInfo::FIGURE_BASE && type < MaterialInfo::PLANT_BASE) - { - df::historical_figure * figure = df::historical_figure::find(index); - if (figure) - { - type -= MaterialInfo::GROUP_SIZE; - index = figure->race; - } - } - mat->set_mat_type(type); - mat->set_mat_index(index); + if (type >= MaterialInfo::FIGURE_BASE && type < MaterialInfo::PLANT_BASE) + { + df::historical_figure * figure = df::historical_figure::find(index); + if (figure) + { + type -= MaterialInfo::GROUP_SIZE; + index = figure->race; + } + } + mat->set_mat_type(type); + mat->set_mat_index(index); } @@ -618,2187 +637,2244 @@ map hashes; bool IsTiletypeChanged(DFCoord pos) { - uint16_t hash; - df::map_block * block = Maps::getBlock(pos); - if (block) - hash = fletcher16((uint8_t*)(block->tiletype), 16 * 16 * (sizeof(df::enums::tiletype::tiletype))); - else - hash = 0; - if (hashes[pos] != hash) - { - hashes[pos] = hash; - return true; - } - return false; + uint16_t hash; + df::map_block * block = Maps::getBlock(pos); + if (block) + hash = fletcher16((uint8_t*)(block->tiletype), 16 * 16 * (sizeof(df::enums::tiletype::tiletype))); + else + hash = 0; + if (hashes[pos] != hash) + { + hashes[pos] = hash; + return true; + } + return false; } map waterHashes; bool IsDesignationChanged(DFCoord pos) { - uint16_t hash; - df::map_block * block = Maps::getBlock(pos); - if (block) - hash = fletcher16((uint8_t*)(block->designation), 16 * 16 * (sizeof(df::tile_designation))); - else - hash = 0; - if (waterHashes[pos] != hash) - { - waterHashes[pos] = hash; - return true; - } - return false; + uint16_t hash; + df::map_block * block = Maps::getBlock(pos); + if (block) + hash = fletcher16((uint8_t*)(block->designation), 16 * 16 * (sizeof(df::tile_designation))); + else + hash = 0; + if (waterHashes[pos] != hash) + { + waterHashes[pos] = hash; + return true; + } + return false; } map buildingHashes; bool IsBuildingChanged(DFCoord pos) { - df::map_block * block = Maps::getBlock(pos); - bool changed = false; - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) - { - DFCoord localPos = DFCoord(pos.x * 16 + x, pos.y * 16 + y, pos.z); - auto bld = block->occupancy[x][y].bits.building; - if (buildingHashes[pos] != bld) - { - buildingHashes[pos] = bld; - changed = true; - } - } - return changed; + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) + { + DFCoord localPos = DFCoord(pos.x * 16 + x, pos.y * 16 + y, pos.z); + auto bld = block->occupancy[x][y].bits.building; + if (buildingHashes[pos] != bld) + { + buildingHashes[pos] = bld; + changed = true; + } + } + return changed; } map spatterHashes; bool IsspatterChanged(DFCoord pos) { - df::map_block * block = Maps::getBlock(pos); - bool changed = false; - std::vector materials; + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + std::vector materials; #if DF_VERSION_INT > 34011 - std::vector items; - if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) - return false; + std::vector items; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return false; #else - if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL)) - return false; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL)) + return false; #endif - uint16_t hash = 0; + uint16_t hash = 0; - for (int i = 0; i < materials.size(); i++) - { - auto mat = materials[i]; - hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); - } + for (int i = 0; i < materials.size(); i++) + { + auto mat = materials[i]; + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < items.size(); i++) - { - auto item = items[i]; - hash ^= fletcher16((uint8_t*)item, sizeof(df::block_square_event_item_spatterst)); - } + for (int i = 0; i < items.size(); i++) + { + auto item = items[i]; + hash ^= fletcher16((uint8_t*)item, sizeof(df::block_square_event_item_spatterst)); + } #endif - if (spatterHashes[pos] != hash) - { - spatterHashes[pos] = hash; - return true; - } - return false; + if (spatterHashes[pos] != hash) + { + spatterHashes[pos] = hash; + return true; + } + return false; } map itemHashes; bool isItemChanged(int i) { - uint16_t hash = 0; - auto item = df::item::find(i); - if (item) - { - hash = fletcher16((uint8_t*)item, sizeof(df::item)); - } - if (itemHashes[i] != hash) - { - itemHashes[i] = hash; - return true; - } - return false; + uint16_t hash = 0; + auto item = df::item::find(i); + if (item) + { + hash = fletcher16((uint8_t*)item, sizeof(df::item)); + } + if (itemHashes[i] != hash) + { + itemHashes[i] = hash; + return true; + } + return false; } bool areItemsChanged(vector * items) { - bool result = false; - for (int i = 0; i < items->size(); i++) - { - if (isItemChanged(items->at(i))) - result = true; - } - return result; + bool result = false; + for (int i = 0; i < items->size(); i++) + { + if (isItemChanged(items->at(i))) + result = true; + } + return result; } static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { - hashes.clear(); - waterHashes.clear(); - buildingHashes.clear(); - spatterHashes.clear(); - itemHashes.clear(); - return CR_OK; + hashes.clear(); + waterHashes.clear(); + buildingHashes.clear(); + spatterHashes.clear(); + itemHashes.clear(); + return CR_OK; } df::matter_state GetState(df::material * mat, uint16_t temp = 10015) { - df::matter_state state = matter_state::Solid; - if (temp >= mat->heat.melting_point) - state = df::matter_state::Liquid; - if (temp >= mat->heat.boiling_point) - state = matter_state::Gas; - return state; + df::matter_state state = matter_state::Solid; + if (temp >= mat->heat.melting_point) + state = df::matter_state::Liquid; + if (temp >= mat->heat.boiling_point) + state = matter_state::Gas; + return state; } static command_result GetMaterialList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - - - - df::world_raws *raws = &world->raws; - df::world_history *history = &world->history; - MaterialInfo mat; - for (int i = 0; i < raws->inorganics.size(); i++) - { - mat.decode(0, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(0); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); - } - } - for (int i = 0; i < 19; i++) - { - int k = -1; - if (i == 7) - k = 1;// for coal. - for (int j = -1; j <= k; j++) - { - mat.decode(i, j); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(i); - mat_def->mutable_mat_pair()->set_mat_index(j); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); - } - } - } - for (int i = 0; i < raws->creatures.all.size(); i++) - { - df::creature_raw * creature = raws->creatures.all[i]; - for (int j = 0; j < creature->material.size(); j++) - { - mat.decode(j + MaterialInfo::CREATURE_BASE, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(j + 19); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); - } - } - } - //for (int i = 0; i < history->figures.size(); i++) - //{ - // df::historical_figure * figure = history->figures[i]; - // if (figure->race < 0) - // continue; - // df::creature_raw * creature = raws->creatures.all[figure->race]; - // for (int j = 0; j < creature->material.size(); j++) - // { - // mat.decode(j + MaterialInfo::FIGURE_BASE, i); - // MaterialDefinition *mat_def = out->add_material_list(); - // mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); - // mat_def->mutable_mat_pair()->set_mat_index(i); - // stringstream id; - // id << "HF" << i << mat.getToken(); - // mat_def->set_id(id.str()); - // mat_def->set_name(mat.toString()); //find the name at cave temperature; - // if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) - // { - // df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; - // mat_def->mutable_state_color()->set_red(color->red * 255); - // mat_def->mutable_state_color()->set_green(color->green * 255); - // mat_def->mutable_state_color()->set_blue(color->blue * 255); - // } - // } - //} - for (int i = 0; i < raws->plants.all.size(); i++) - { - df::plant_raw * plant = raws->plants.all[i]; - for (int j = 0; j < plant->material.size(); j++) - { - mat.decode(j + 419, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(j + 419); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (plant->material[j]->state_color[GetState(plant->material[j])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); - } - } - } - return CR_OK; + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + + + + df::world_raws *raws = &world->raws; + df::world_history *history = &world->history; + MaterialInfo mat; + for (int i = 0; i < raws->inorganics.size(); i++) + { + mat.decode(0, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(0); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); + } + } + for (int i = 0; i < 19; i++) + { + int k = -1; + if (i == 7) + k = 1;// for coal. + for (int j = -1; j <= k; j++) + { + mat.decode(i, j); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(i); + mat_def->mutable_mat_pair()->set_mat_index(j); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); + } + } + } + for (int i = 0; i < raws->creatures.all.size(); i++) + { + df::creature_raw * creature = raws->creatures.all[i]; + for (int j = 0; j < creature->material.size(); j++) + { + mat.decode(j + MaterialInfo::CREATURE_BASE, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(j + 19); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); + } + } + } + //for (int i = 0; i < history->figures.size(); i++) + //{ + // df::historical_figure * figure = history->figures[i]; + // if (figure->race < 0) + // continue; + // df::creature_raw * creature = raws->creatures.all[figure->race]; + // for (int j = 0; j < creature->material.size(); j++) + // { + // mat.decode(j + MaterialInfo::FIGURE_BASE, i); + // MaterialDefinition *mat_def = out->add_material_list(); + // mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); + // mat_def->mutable_mat_pair()->set_mat_index(i); + // stringstream id; + // id << "HF" << i << mat.getToken(); + // mat_def->set_id(id.str()); + // mat_def->set_name(mat.toString()); //find the name at cave temperature; + // if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + // { + // df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; + // mat_def->mutable_state_color()->set_red(color->red * 255); + // mat_def->mutable_state_color()->set_green(color->green * 255); + // mat_def->mutable_state_color()->set_blue(color->blue * 255); + // } + // } + //} + for (int i = 0; i < raws->plants.all.size(); i++) + { + df::plant_raw * plant = raws->plants.all[i]; + for (int j = 0; j < plant->material.size(); j++) + { + mat.decode(j + 419, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(j + 419); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (plant->material[j]->state_color[GetState(plant->material[j])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); + } + } + } + return CR_OK; } static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - FOR_ENUM_ITEMS(item_type, it) - { - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(-1); - mat_def->set_id(ENUM_KEY_STR(item_type, it)); - if (it == item_type::BOX) - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(0); - mat_def->set_id("BOX_CHEST"); - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(1); - mat_def->set_id("BOX_BAG"); - } - int subtypes = Items::getSubtypeCount(it); - if (subtypes >= 0) - { - for (int i = 0; i < subtypes; i++) - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(i); - df::itemdef * item = Items::getSubtypeDef(it, i); - mat_def->set_id(item->id); - } - } - } - - - return CR_OK; + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + FOR_ENUM_ITEMS(item_type, it) + { + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(-1); + mat_def->set_id(ENUM_KEY_STR(item_type, it)); + if (it == item_type::BOX) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(0); + mat_def->set_id("BOX_CHEST"); + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(1); + mat_def->set_id("BOX_BAG"); + } + int subtypes = Items::getSubtypeCount(it); + if (subtypes >= 0) + { + for (int i = 0; i < subtypes; i++) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + df::itemdef * item = Items::getSubtypeDef(it, i); + mat_def->set_id(item->id); + } + } + } + + + return CR_OK; } static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } - df::world_raws *raws = &world->raws; - if (!raws) - return CR_OK;//'. + df::world_raws *raws = &world->raws; + if (!raws) + return CR_OK;//'. - for (int i = 0; i < raws->plants.all.size(); i++) - { - df::plant_raw * pp = raws->plants.all[i]; - if (!pp) - continue; - MaterialDefinition * basePlant = out->add_material_list(); - basePlant->set_id(pp->id + ":BASE"); - basePlant->set_name(pp->name); - basePlant->mutable_mat_pair()->set_mat_type(-1); - basePlant->mutable_mat_pair()->set_mat_index(i); + for (int i = 0; i < raws->plants.all.size(); i++) + { + df::plant_raw * pp = raws->plants.all[i]; + if (!pp) + continue; + MaterialDefinition * basePlant = out->add_material_list(); + basePlant->set_id(pp->id + ":BASE"); + basePlant->set_name(pp->name); + basePlant->mutable_mat_pair()->set_mat_type(-1); + basePlant->mutable_mat_pair()->set_mat_index(i); #if DF_VERSION_INT > 40001 - for (int g = 0; g < pp->growths.size(); g++) - { - df::plant_growth* growth = pp->growths[g]; - if (!growth) - continue; - for (int l = 0; l < GROWTH_LOCATIONS_SIZE; l++) - { - MaterialDefinition * out_growth = out->add_material_list(); - out_growth->set_id(pp->id + ":" + growth->id + +":" + growth_locations[l]); - out_growth->set_name(growth->name); - out_growth->mutable_mat_pair()->set_mat_type(g * 10 + l); - out_growth->mutable_mat_pair()->set_mat_index(i); - } - } + for (int g = 0; g < pp->growths.size(); g++) + { + df::plant_growth* growth = pp->growths[g]; + if (!growth) + continue; + for (int l = 0; l < GROWTH_LOCATIONS_SIZE; l++) + { + MaterialDefinition * out_growth = out->add_material_list(); + out_growth->set_id(pp->id + ":" + growth->id + +":" + growth_locations[l]); + out_growth->set_name(growth->name); + out_growth->mutable_mat_pair()->set_mat_type(g * 10 + l); + out_growth->mutable_mat_pair()->set_mat_index(i); + } + } #endif - } - return CR_OK; + } + return CR_OK; } void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - - MapExtras::Block * block = MC->BlockAtTile(DfBlock->map_pos); - - int trunk_percent[16][16]; - int tree_x[16][16]; - int tree_y[16][16]; - int tree_z[16][16]; - for (int xx = 0; xx < 16; xx++) - for (int yy = 0; yy < 16; yy++) - { - trunk_percent[xx][yy] = 255; - tree_x[xx][yy] = -3000; - tree_y[xx][yy] = -3000; - tree_z[xx][yy] = -3000; - } + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + + MapExtras::Block * block = MC->BlockAtTile(DfBlock->map_pos); + + int trunk_percent[16][16]; + int tree_x[16][16]; + int tree_y[16][16]; + int tree_z[16][16]; + for (int xx = 0; xx < 16; xx++) + for (int yy = 0; yy < 16; yy++) + { + trunk_percent[xx][yy] = 255; + tree_x[xx][yy] = -3000; + tree_y[xx][yy] = -3000; + tree_z[xx][yy] = -3000; + } #if DF_VERSION_INT > 34011 - df::map_block_column * column = df::global::world->map.column_index[(DfBlock->map_pos.x / 48) * 3][(DfBlock->map_pos.y / 48) * 3]; - for (int i = 0; i < column->plants.size(); i++) - { - df::plant* plant = column->plants[i]; - if (plant->tree_info == NULL) - continue; - df::plant_tree_info * tree_info = plant->tree_info; - if ( - plant->pos.z - tree_info->roots_depth > DfBlock->map_pos.z - || (plant->pos.z + tree_info->body_height) <= DfBlock->map_pos.z - || (plant->pos.x - tree_info->dim_x / 2) > (DfBlock->map_pos.x + 16) - || (plant->pos.x + tree_info->dim_x / 2) < (DfBlock->map_pos.x) - || (plant->pos.y - tree_info->dim_y / 2) > (DfBlock->map_pos.y + 16) - || (plant->pos.y + tree_info->dim_y / 2) < (DfBlock->map_pos.y) - ) - continue; - DFCoord localPos = plant->pos - DfBlock->map_pos; - for (int xx = 0; xx < tree_info->dim_x; xx++) - for (int yy = 0; yy < tree_info->dim_y; yy++) - { - int xxx = localPos.x - (tree_info->dim_x / 2) + xx; - int yyy = localPos.y - (tree_info->dim_y / 2) + yy; - if (xxx < 0 - || yyy < 0 - || xxx >= 16 - || yyy >= 16 - ) - continue; - df::plant_tree_tile tile; - if (-localPos.z < 0) - { - tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; - } - else - { - tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; - } - if (!tile.whole || tile.bits.blocked) - continue; - if (tree_info->body_height <= 1) - trunk_percent[xxx][yyy] = 0; - else - trunk_percent[xxx][yyy] = -localPos.z * 100 / (tree_info->body_height - 1); - tree_x[xxx][yyy] = xx - tree_info->dim_x / 2; - tree_y[xxx][yyy] = yy - tree_info->dim_y / 2; - tree_z[xxx][yyy] = localPos.z; - } - } + df::map_block_column * column = df::global::world->map.column_index[(DfBlock->map_pos.x / 48) * 3][(DfBlock->map_pos.y / 48) * 3]; + for (int i = 0; i < column->plants.size(); i++) + { + df::plant* plant = column->plants[i]; + if (plant->tree_info == NULL) + continue; + df::plant_tree_info * tree_info = plant->tree_info; + if ( + plant->pos.z - tree_info->roots_depth > DfBlock->map_pos.z + || (plant->pos.z + tree_info->body_height) <= DfBlock->map_pos.z + || (plant->pos.x - tree_info->dim_x / 2) > (DfBlock->map_pos.x + 16) + || (plant->pos.x + tree_info->dim_x / 2) < (DfBlock->map_pos.x) + || (plant->pos.y - tree_info->dim_y / 2) > (DfBlock->map_pos.y + 16) + || (plant->pos.y + tree_info->dim_y / 2) < (DfBlock->map_pos.y) + ) + continue; + DFCoord localPos = plant->pos - DfBlock->map_pos; + for (int xx = 0; xx < tree_info->dim_x; xx++) + for (int yy = 0; yy < tree_info->dim_y; yy++) + { + int xxx = localPos.x - (tree_info->dim_x / 2) + xx; + int yyy = localPos.y - (tree_info->dim_y / 2) + yy; + if (xxx < 0 + || yyy < 0 + || xxx >= 16 + || yyy >= 16 + ) + continue; + df::plant_tree_tile tile; + if (-localPos.z < 0) + { + tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; + } + else + { + tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; + } + if (!tile.whole || tile.bits.blocked) + continue; + if (tree_info->body_height <= 1) + trunk_percent[xxx][yyy] = 0; + else + trunk_percent[xxx][yyy] = -localPos.z * 100 / (tree_info->body_height - 1); + tree_x[xxx][yyy] = xx - tree_info->dim_x / 2; + tree_y[xxx][yyy] = yy - tree_info->dim_y / 2; + tree_z[xxx][yyy] = localPos.z; + } + } #endif - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - df::tiletype tile = DfBlock->tiletype[xx][yy]; - NetBlock->add_tiles(tile); - df::coord2d p = df::coord2d(xx, yy); - t_matpair baseMat = block->baseMaterialAt(p); - t_matpair staticMat = block->staticMaterialAt(p); - switch (tileMaterial(tile)) - { - case tiletype_material::FROZEN_LIQUID: - staticMat.mat_type = builtin_mats::WATER; - staticMat.mat_index = -1; - break; - default: - break; - } - CopyMat(NetBlock->add_materials(), staticMat.mat_type, staticMat.mat_index); - CopyMat(NetBlock->add_layer_materials(), 0, block->layerMaterialAt(p)); - CopyMat(NetBlock->add_vein_materials(), 0, block->veinMaterialAt(p)); - CopyMat(NetBlock->add_base_materials(), baseMat.mat_type, baseMat.mat_index); - RemoteFortressReader::MatPair * constructionItem = NetBlock->add_construction_items(); - CopyMat(constructionItem, -1, -1); - if (tileMaterial(tile) == tiletype_material::CONSTRUCTION) - { - df::construction *con = df::construction::find(DfBlock->map_pos + df::coord(xx, yy, 0)); - if (con) - { - CopyMat(constructionItem, con->item_type, con->item_subtype); - } - } - NetBlock->add_tree_percent(trunk_percent[xx][yy]); - NetBlock->add_tree_x(tree_x[xx][yy]); - NetBlock->add_tree_y(tree_y[xx][yy]); - NetBlock->add_tree_z(tree_z[xx][yy]); - } + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + df::tiletype tile = DfBlock->tiletype[xx][yy]; + NetBlock->add_tiles(tile); + df::coord2d p = df::coord2d(xx, yy); + t_matpair baseMat = block->baseMaterialAt(p); + t_matpair staticMat = block->staticMaterialAt(p); + switch (tileMaterial(tile)) + { + case tiletype_material::FROZEN_LIQUID: + staticMat.mat_type = builtin_mats::WATER; + staticMat.mat_index = -1; + break; + default: + break; + } + CopyMat(NetBlock->add_materials(), staticMat.mat_type, staticMat.mat_index); + CopyMat(NetBlock->add_layer_materials(), 0, block->layerMaterialAt(p)); + CopyMat(NetBlock->add_vein_materials(), 0, block->veinMaterialAt(p)); + CopyMat(NetBlock->add_base_materials(), baseMat.mat_type, baseMat.mat_index); + RemoteFortressReader::MatPair * constructionItem = NetBlock->add_construction_items(); + CopyMat(constructionItem, -1, -1); + if (tileMaterial(tile) == tiletype_material::CONSTRUCTION) + { + df::construction *con = df::construction::find(DfBlock->map_pos + df::coord(xx, yy, 0)); + if (con) + { + CopyMat(constructionItem, con->item_type, con->item_subtype); + } + } + NetBlock->add_tree_percent(trunk_percent[xx][yy]); + NetBlock->add_tree_x(tree_x[xx][yy]); + NetBlock->add_tree_y(tree_y[xx][yy]); + NetBlock->add_tree_z(tree_z[xx][yy]); + } } void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - df::tile_designation designation = DfBlock->designation[xx][yy]; - df::tile_occupancy occupancy = DfBlock->occupancy[xx][yy]; - int lava = 0; - int water = 0; - if (designation.bits.liquid_type == df::enums::tile_liquid::Magma) - lava = designation.bits.flow_size; - else - water = designation.bits.flow_size; - NetBlock->add_magma(lava); - NetBlock->add_water(water); - NetBlock->add_aquifer(designation.bits.water_table); - NetBlock->add_light(designation.bits.light); - NetBlock->add_outside(designation.bits.outside); - NetBlock->add_subterranean(designation.bits.subterranean); - NetBlock->add_water_salt(designation.bits.water_salt); - NetBlock->add_water_stagnant(designation.bits.water_stagnant); - if (gamemode && (*gamemode == game_mode::ADVENTURE)) - { - auto fog_of_war = DfBlock->fog_of_war[xx][yy]; - NetBlock->add_hidden(designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden); - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - NetBlock->add_tile_dig_designation_marker(false); - NetBlock->add_tile_dig_designation_auto(false); - } - else - { - NetBlock->add_hidden(designation.bits.hidden); + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + df::tile_designation designation = DfBlock->designation[xx][yy]; + df::tile_occupancy occupancy = DfBlock->occupancy[xx][yy]; + int lava = 0; + int water = 0; + if (designation.bits.liquid_type == df::enums::tile_liquid::Magma) + lava = designation.bits.flow_size; + else + water = designation.bits.flow_size; + NetBlock->add_magma(lava); + NetBlock->add_water(water); + NetBlock->add_aquifer(designation.bits.water_table); + NetBlock->add_light(designation.bits.light); + NetBlock->add_outside(designation.bits.outside); + NetBlock->add_subterranean(designation.bits.subterranean); + NetBlock->add_water_salt(designation.bits.water_salt); + NetBlock->add_water_stagnant(designation.bits.water_stagnant); + if (gamemode && (*gamemode == game_mode::ADVENTURE)) + { + auto fog_of_war = DfBlock->fog_of_war[xx][yy]; + NetBlock->add_hidden(designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden); + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + NetBlock->add_tile_dig_designation_marker(false); + NetBlock->add_tile_dig_designation_auto(false); + } + else + { + NetBlock->add_hidden(designation.bits.hidden); #if DF_VERSION_INT > 34011 - NetBlock->add_tile_dig_designation_marker(occupancy.bits.dig_marked); - NetBlock->add_tile_dig_designation_auto(occupancy.bits.dig_auto); + NetBlock->add_tile_dig_designation_marker(occupancy.bits.dig_marked); + NetBlock->add_tile_dig_designation_auto(occupancy.bits.dig_auto); #endif - switch (designation.bits.dig) - { - case df::enums::tile_dig_designation::No: - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - break; - case df::enums::tile_dig_designation::Default: - NetBlock->add_tile_dig_designation(TileDigDesignation::DEFAULT_DIG); - break; - case df::enums::tile_dig_designation::UpDownStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::UP_DOWN_STAIR_DIG); - break; - case df::enums::tile_dig_designation::Channel: - NetBlock->add_tile_dig_designation(TileDigDesignation::CHANNEL_DIG); - break; - case df::enums::tile_dig_designation::Ramp: - NetBlock->add_tile_dig_designation(TileDigDesignation::RAMP_DIG); - break; - case df::enums::tile_dig_designation::DownStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::DOWN_STAIR_DIG); - break; - case df::enums::tile_dig_designation::UpStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::UP_STAIR_DIG); - break; - default: - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - break; - } - } - } + switch (designation.bits.dig) + { + case df::enums::tile_dig_designation::No: + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + break; + case df::enums::tile_dig_designation::Default: + NetBlock->add_tile_dig_designation(TileDigDesignation::DEFAULT_DIG); + break; + case df::enums::tile_dig_designation::UpDownStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::UP_DOWN_STAIR_DIG); + break; + case df::enums::tile_dig_designation::Channel: + NetBlock->add_tile_dig_designation(TileDigDesignation::CHANNEL_DIG); + break; + case df::enums::tile_dig_designation::Ramp: + NetBlock->add_tile_dig_designation(TileDigDesignation::RAMP_DIG); + break; + case df::enums::tile_dig_designation::DownStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::DOWN_STAIR_DIG); + break; + case df::enums::tile_dig_designation::UpStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::UP_STAIR_DIG); + break; + default: + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + break; + } + } + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < world->jobs.postings.size(); i++) - { - auto job = world->jobs.postings[i]->job; - if (job == nullptr) - continue; - if ( - job->pos.z > DfBlock->map_pos.z - || job->pos.z < DfBlock->map_pos.z - || job->pos.x >= (DfBlock->map_pos.x + 16) - || job->pos.x < (DfBlock->map_pos.x) - || job->pos.y >= (DfBlock->map_pos.y + 16) - || job->pos.y < (DfBlock->map_pos.y) - ) - continue; - - int index = (job->pos.x - DfBlock->map_pos.x) + (16 * (job->pos.y - DfBlock->map_pos.y)); - - switch (job->job_type) - { - case job_type::Dig: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - case job_type::CarveUpwardStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_STAIR_DIG); - break; - case job_type::CarveDownwardStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DOWN_STAIR_DIG); - break; - case job_type::CarveUpDownStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_DOWN_STAIR_DIG); - break; - case job_type::CarveRamp: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::RAMP_DIG); - break; - case job_type::DigChannel: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::CHANNEL_DIG); - break; - case job_type::FellTree: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - case job_type::GatherPlants: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - default: - break; - } - } + for (int i = 0; i < world->jobs.postings.size(); i++) + { + auto job = world->jobs.postings[i]->job; + if (job == nullptr) + continue; + if ( + job->pos.z > DfBlock->map_pos.z + || job->pos.z < DfBlock->map_pos.z + || job->pos.x >= (DfBlock->map_pos.x + 16) + || job->pos.x < (DfBlock->map_pos.x) + || job->pos.y >= (DfBlock->map_pos.y + 16) + || job->pos.y < (DfBlock->map_pos.y) + ) + continue; + + int index = (job->pos.x - DfBlock->map_pos.x) + (16 * (job->pos.y - DfBlock->map_pos.y)); + + switch (job->job_type) + { + case job_type::Dig: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::CarveUpwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_STAIR_DIG); + break; + case job_type::CarveDownwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DOWN_STAIR_DIG); + break; + case job_type::CarveUpDownStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_DOWN_STAIR_DIG); + break; + case job_type::CarveRamp: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::RAMP_DIG); + break; + case job_type::DigChannel: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::CHANNEL_DIG); + break; + case job_type::FellTree: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::GatherPlants: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + default: + break; + } + } #endif } void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC) { - for (int i = 0; i < df::global::world->buildings.all.size(); i++) - { - df::building * bld = df::global::world->buildings.all[i]; - if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y) - { - auto out_bld = NetBlock->add_buildings(); - out_bld->set_index(bld->id); - continue; - } - - int z2 = bld->z; - - if (bld->getType() == building_type::Well) - { - df::building_wellst * well_building = virtual_cast(bld); - if (well_building) - { - z2 = well_building->bucket_z; - } - } - if (bld->z < min.z || z2 >= max.z) - { - auto out_bld = NetBlock->add_buildings(); - out_bld->set_index(bld->id); - continue; - } - auto out_bld = NetBlock->add_buildings(); - CopyBuilding(i, out_bld); - df::building_actual* actualBuilding = virtual_cast(bld); - if (actualBuilding) - { - for (int i = 0; i < actualBuilding->contained_items.size(); i++) - { - auto buildingItem = out_bld->add_items(); - buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); - CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); - } - } - } + for (int i = 0; i < df::global::world->buildings.all.size(); i++) + { + df::building * bld = df::global::world->buildings.all[i]; + if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y) + { + auto out_bld = NetBlock->add_buildings(); + out_bld->set_index(bld->id); + continue; + } + + int z2 = bld->z; + + if (bld->getType() == building_type::Well) + { + df::building_wellst * well_building = virtual_cast(bld); + if (well_building) + { + z2 = well_building->bucket_z; + } + } + if (bld->z < min.z || z2 >= max.z) + { + auto out_bld = NetBlock->add_buildings(); + out_bld->set_index(bld->id); + continue; + } + auto out_bld = NetBlock->add_buildings(); + CopyBuilding(i, out_bld); + df::building_actual* actualBuilding = virtual_cast(bld); + if (actualBuilding) + { + for (int i = 0; i < actualBuilding->contained_items.size(); i++) + { + auto buildingItem = out_bld->add_items(); + buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); + CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); + } + } + } } void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - std::vector materials; + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + std::vector materials; #if DF_VERSION_INT > 34011 - std::vector items; - std::vector grasses; - if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, &grasses, NULL, NULL, &items)) - return; + std::vector items; + std::vector grasses; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, &grasses, NULL, NULL, &items)) + return; #else - if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL)) - return; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL)) + return; #endif - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - auto send_pile = NetBlock->add_spatterpile(); - for (int i = 0; i < materials.size(); i++) - { - auto mat = materials[i]; - if (mat->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - send_spat->set_state((MatterState)mat->mat_state); - CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); - send_spat->set_amount(mat->amount[xx][yy]); - } + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + auto send_pile = NetBlock->add_spatterpile(); + for (int i = 0; i < materials.size(); i++) + { + auto mat = materials[i]; + if (mat->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + send_spat->set_state((MatterState)mat->mat_state); + CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); + send_spat->set_amount(mat->amount[xx][yy]); + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < items.size(); i++) - { - auto item = items[i]; - if (item->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - CopyMat(send_spat->mutable_material(), item->mattype, item->matindex); - send_spat->set_amount(item->amount[xx][yy]); - auto send_item = send_spat->mutable_item(); - send_item->set_mat_type(item->item_type); - send_item->set_mat_index(item->item_subtype); - } - int grassPercent = 0; - for (int i = 0; i < grasses.size(); i++) - { - auto grass = grasses[i]; - if (grass->amount[xx][yy] > grassPercent) - grassPercent = grass->amount[xx][yy]; - } - NetBlock->add_grass_percent(grassPercent); + for (int i = 0; i < items.size(); i++) + { + auto item = items[i]; + if (item->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + CopyMat(send_spat->mutable_material(), item->mattype, item->matindex); + send_spat->set_amount(item->amount[xx][yy]); + auto send_item = send_spat->mutable_item(); + send_item->set_mat_type(item->item_type); + send_item->set_mat_index(item->item_subtype); + } + int grassPercent = 0; + for (int i = 0; i < grasses.size(); i++) + { + auto grass = grasses[i]; + if (grass->amount[xx][yy] > grassPercent) + grassPercent = grass->amount[xx][yy]; + } + NetBlock->add_grass_percent(grassPercent); #endif - } + } } void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { - NetItem->set_id(DfItem->id); - NetItem->set_flags1(DfItem->flags.whole); - NetItem->set_flags2(DfItem->flags2.whole); - auto pos = NetItem->mutable_pos(); - pos->set_x(DfItem->pos.x); - pos->set_y(DfItem->pos.y); - pos->set_z(DfItem->pos.z); - auto mat = NetItem->mutable_material(); - mat->set_mat_index(DfItem->getMaterialIndex()); - mat->set_mat_type(DfItem->getMaterial()); - auto type = NetItem->mutable_type(); - type->set_mat_type(DfItem->getType()); - type->set_mat_index(DfItem->getSubtype()); - if (DfItem->getType() == item_type::BOX) - { - type->set_mat_index(DfItem->isBag()); - } - auto constructed_item = virtual_cast(DfItem); - if(constructed_item) - { - for (int i = 0; i < constructed_item->improvements.size(); i++) - { - auto improvement = constructed_item->improvements[i]; - if (!improvement || improvement->getType() != improvement_type::THREAD) - continue; - - auto improvement_thread = virtual_cast(improvement); - if (!improvement_thread || improvement_thread->dye.mat_type < 0) - continue; - - DFHack::MaterialInfo info; - if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) - continue; - - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } - else if (DfItem->getType() == item_type::THREAD) - { - auto thread = virtual_cast(DfItem); - if (thread && thread->dye_mat_type >= 0) - { - DFHack::MaterialInfo info; - if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } + NetItem->set_id(DfItem->id); + NetItem->set_flags1(DfItem->flags.whole); + NetItem->set_flags2(DfItem->flags2.whole); + auto pos = NetItem->mutable_pos(); + pos->set_x(DfItem->pos.x); + pos->set_y(DfItem->pos.y); + pos->set_z(DfItem->pos.z); + auto mat = NetItem->mutable_material(); + mat->set_mat_index(DfItem->getMaterialIndex()); + mat->set_mat_type(DfItem->getMaterial()); + auto type = NetItem->mutable_type(); + type->set_mat_type(DfItem->getType()); + type->set_mat_index(DfItem->getSubtype()); + if (DfItem->getType() == item_type::BOX) + { + type->set_mat_index(DfItem->isBag()); + } + auto constructed_item = virtual_cast(DfItem); + if (constructed_item) + { + for (int i = 0; i < constructed_item->improvements.size(); i++) + { + auto improvement = constructed_item->improvements[i]; + if (!improvement || improvement->getType() != improvement_type::THREAD) + continue; + + auto improvement_thread = virtual_cast(improvement); + if (!improvement_thread || improvement_thread->dye.mat_type < 0) + continue; + + DFHack::MaterialInfo info; + if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) + continue; + + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } + else if (DfItem->getType() == item_type::THREAD) + { + auto thread = virtual_cast(DfItem); + if (thread && thread->dye_mat_type >= 0) + { + DFHack::MaterialInfo info; + if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } } void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - for (int i = 0; i < DfBlock->items.size(); i++) - { - int id = DfBlock->items[i]; - - - auto item = df::item::find(id); - if(item) - CopyItem(NetBlock->add_items(), item); - } + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + for (int i = 0; i < DfBlock->items.size(); i++) + { + int id = DfBlock->items[i]; + + + auto item = df::item::find(id); + if (item) + CopyItem(NetBlock->add_items(), item); + } } static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) { - int x, y, z; - DFHack::Maps::getPosition(x, y, z); - out->set_map_x(x); - out->set_map_y(y); - MapExtras::MapCache MC; - int center_x = (in->min_x() + in->max_x()) / 2; - int center_y = (in->min_y() + in->max_y()) / 2; - - int NUMBER_OF_POINTS = ((in->max_x() - center_x + 1) * 2) * ((in->max_y() - center_y + 1) * 2); - int blocks_needed; - if (in->has_blocks_needed()) - blocks_needed = in->blocks_needed(); - else - blocks_needed = NUMBER_OF_POINTS*(in->max_z() - in->min_z()); - int blocks_sent = 0; - int min_x = in->min_x(); - int min_y = in->min_y(); - int max_x = in->max_x(); - int max_y = in->max_y(); - int min_z = in->min_z(); - int max_z = in->max_z(); - bool sentBuildings = false; //Always send all the buildings needed on the first block, and none on the rest. - //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); - for (int zz = max_z - 1; zz >= min_z; zz--) - { - // (di, dj) is a vector - direction in which we move right now - int di = 1; - int dj = 0; - // length of current segment - int segment_length = 1; - // current position (i, j) and how much of current segment we passed - int i = center_x; - int j = center_y; - int segment_passed = 0; - for (int k = 0; k < NUMBER_OF_POINTS; ++k) - { - if (blocks_sent >= blocks_needed) - break; - if (!(i < min_x || i >= max_x || j < min_y || j >= max_y)) - { - DFCoord pos = DFCoord(i, j, zz); - df::map_block * block = DFHack::Maps::getBlock(pos); - if (block != NULL) - { - int nonAir = 0; - for (int xxx = 0; xxx < 16; xxx++) - for (int yyy = 0; yyy < 16; yyy++) - { - if ((DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::None && - DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::Open) - || block->designation[xxx][yyy].bits.flow_size > 0 - || block->occupancy[xxx][yyy].bits.building > 0) - nonAir++; - } - if (nonAir > 0 || !sentBuildings) - { - bool tileChanged = IsTiletypeChanged(pos); - bool desChanged = IsDesignationChanged(pos); - bool spatterChanged = IsspatterChanged(pos); - bool buildingChanged = !sentBuildings; - bool itemsChanged = areItemsChanged(&block->items); - //bool bldChanged = IsBuildingChanged(pos); - RemoteFortressReader::MapBlock *net_block; - if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) - net_block = out->add_map_blocks(); - if (tileChanged) - { - CopyBlock(block, net_block, &MC, pos); - blocks_sent++; - } - if (desChanged) - CopyDesignation(block, net_block, &MC, pos); - if (buildingChanged) - { - CopyBuildings(DFCoord(min_x * 16, min_y * 16, min_z), DFCoord(max_x * 16, max_y * 16, max_z), net_block, &MC); - sentBuildings = true; - } - if (spatterChanged) - Copyspatters(block, net_block, &MC, pos); - if (itemsChanged) - CopyItems(block, net_block, &MC, pos); - } - } - } - - // make a step, add 'direction' vector (di, dj) to current position (i, j) - i += di; - j += dj; - ++segment_passed; - //System.out.println(i + " " + j); - - if (segment_passed == segment_length) - { - // done with current segment - segment_passed = 0; - - // 'rotate' directions - int buffer = di; - di = -dj; - dj = buffer; - - // increase segment length if necessary - if (dj == 0) { - ++segment_length; - } - } - } - } - MC.trash(); - return CR_OK; + int x, y, z; + DFHack::Maps::getPosition(x, y, z); + out->set_map_x(x); + out->set_map_y(y); + MapExtras::MapCache MC; + int center_x = (in->min_x() + in->max_x()) / 2; + int center_y = (in->min_y() + in->max_y()) / 2; + + int NUMBER_OF_POINTS = ((in->max_x() - center_x + 1) * 2) * ((in->max_y() - center_y + 1) * 2); + int blocks_needed; + if (in->has_blocks_needed()) + blocks_needed = in->blocks_needed(); + else + blocks_needed = NUMBER_OF_POINTS*(in->max_z() - in->min_z()); + int blocks_sent = 0; + int min_x = in->min_x(); + int min_y = in->min_y(); + int max_x = in->max_x(); + int max_y = in->max_y(); + int min_z = in->min_z(); + int max_z = in->max_z(); + bool sentBuildings = false; //Always send all the buildings needed on the first block, and none on the rest. + //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); + for (int zz = max_z - 1; zz >= min_z; zz--) + { + // (di, dj) is a vector - direction in which we move right now + int di = 1; + int dj = 0; + // length of current segment + int segment_length = 1; + // current position (i, j) and how much of current segment we passed + int i = center_x; + int j = center_y; + int segment_passed = 0; + for (int k = 0; k < NUMBER_OF_POINTS; ++k) + { + if (blocks_sent >= blocks_needed) + break; + if (!(i < min_x || i >= max_x || j < min_y || j >= max_y)) + { + DFCoord pos = DFCoord(i, j, zz); + df::map_block * block = DFHack::Maps::getBlock(pos); + if (block != NULL) + { + int nonAir = 0; + for (int xxx = 0; xxx < 16; xxx++) + for (int yyy = 0; yyy < 16; yyy++) + { + if ((DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::None && + DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::Open) + || block->designation[xxx][yyy].bits.flow_size > 0 + || block->occupancy[xxx][yyy].bits.building > 0) + nonAir++; + } + if (nonAir > 0 || !sentBuildings) + { + bool tileChanged = IsTiletypeChanged(pos); + bool desChanged = IsDesignationChanged(pos); + bool spatterChanged = IsspatterChanged(pos); + bool buildingChanged = !sentBuildings; + bool itemsChanged = areItemsChanged(&block->items); + //bool bldChanged = IsBuildingChanged(pos); + RemoteFortressReader::MapBlock *net_block; + if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) + net_block = out->add_map_blocks(); + if (tileChanged) + { + CopyBlock(block, net_block, &MC, pos); + blocks_sent++; + } + if (desChanged) + CopyDesignation(block, net_block, &MC, pos); + if (buildingChanged) + { + CopyBuildings(DFCoord(min_x * 16, min_y * 16, min_z), DFCoord(max_x * 16, max_y * 16, max_z), net_block, &MC); + sentBuildings = true; + } + if (spatterChanged) + Copyspatters(block, net_block, &MC, pos); + if (itemsChanged) + CopyItems(block, net_block, &MC, pos); + } + } + } + + // make a step, add 'direction' vector (di, dj) to current position (i, j) + i += di; + j += dj; + ++segment_passed; + //System.out.println(i + " " + j); + + if (segment_passed == segment_length) + { + // done with current segment + segment_passed = 0; + + // 'rotate' directions + int buffer = di; + di = -dj; + dj = buffer; + + // increase segment length if necessary + if (dj == 0) { + ++segment_length; + } + } + } + } + MC.trash(); + return CR_OK; } static command_result GetTiletypeList(color_ostream &stream, const EmptyMessage *in, TiletypeList *out) { - int count = 0; - FOR_ENUM_ITEMS(tiletype, tt) - { - Tiletype * type = out->add_tiletype_list(); - type->set_id(tt); - type->set_name(ENUM_KEY_STR(tiletype, tt)); - const char * name = tileName(tt); - if (name != NULL && name[0] != 0) - type->set_caption(name); - type->set_shape(TranslateShape(tileShape(tt))); - type->set_special(TranslateSpecial(tileSpecial(tt))); - type->set_material(TranslateMaterial(tileMaterial(tt))); - type->set_variant(TranslateVariant(tileVariant(tt))); - type->set_direction(tileDirection(tt).getStr()); - count++; - } - return CR_OK; + int count = 0; + FOR_ENUM_ITEMS(tiletype, tt) + { + Tiletype * type = out->add_tiletype_list(); + type->set_id(tt); + type->set_name(ENUM_KEY_STR(tiletype, tt)); + const char * name = tileName(tt); + if (name != NULL && name[0] != 0) + type->set_caption(name); + type->set_shape(TranslateShape(tileShape(tt))); + type->set_special(TranslateSpecial(tileSpecial(tt))); + type->set_material(TranslateMaterial(tileMaterial(tt))); + type->set_variant(TranslateVariant(tileVariant(tt))); + type->set_direction(tileDirection(tt).getStr()); + count++; + } + return CR_OK; } static command_result GetPlantList(color_ostream &stream, const BlockRequest *in, PlantList *out) { - int min_x = in->min_x() / 3; - int min_y = in->min_y() / 3; - int min_z = in->min_z(); - int max_x = in->max_x() / 3; - int max_y = in->max_y() / 3; - int max_z = in->max_z(); + int min_x = in->min_x() / 3; + int min_y = in->min_y() / 3; + int min_z = in->min_z(); + int max_x = in->max_x() / 3; + int max_y = in->max_y() / 3; + int max_z = in->max_z(); #if DF_VERSION_INT < 40001 - //plants are gotten differently here + //plants are gotten differently here #else - for (int xx = min_x; xx < max_x; xx++) - for (int yy = min_y; yy < max_y; yy++) - { - if (xx < 0 || yy < 0 || xx >= world->map.x_count_block || yy >= world->map.y_count_block) - continue; - df::map_block_column * column = world->map.column_index[xx][yy]; - for (int i = 0; i < column->plants.size(); i++) - { - df::plant * plant = column->plants[i]; - if (!plant->tree_info) - { - if (plant->pos.z < min_z || plant->pos.z >= max_z) - continue; - if (plant->pos.x < in->min_x() * 16 || plant->pos.x >= in->max_x() * 16) - continue; - if (plant->pos.y < in->min_y() * 16 || plant->pos.y >= in->max_y() * 16) - continue; - } - else - { - if (plant->pos.z - plant->tree_info->roots_depth < min_z || plant->pos.z + plant->tree_info->body_height > max_z) - continue; - if (plant->pos.x - plant->tree_info->dim_x / 2 < in->min_x() * 16 || plant->pos.x + plant->tree_info->dim_x / 2 >= in->max_x() * 16) - continue; - if (plant->pos.y - plant->tree_info->dim_y / 2 < in->min_y() * 16 || plant->pos.y + plant->tree_info->dim_y / 2 >= in->max_y() * 16) - continue; - } - RemoteFortressReader::PlantDef * out_plant = out->add_plant_list(); - out_plant->set_index(plant->material); - out_plant->set_pos_x(plant->pos.x); - out_plant->set_pos_y(plant->pos.y); - out_plant->set_pos_z(plant->pos.z); - } - } + for (int xx = min_x; xx < max_x; xx++) + for (int yy = min_y; yy < max_y; yy++) + { + if (xx < 0 || yy < 0 || xx >= world->map.x_count_block || yy >= world->map.y_count_block) + continue; + df::map_block_column * column = world->map.column_index[xx][yy]; + for (int i = 0; i < column->plants.size(); i++) + { + df::plant * plant = column->plants[i]; + if (!plant->tree_info) + { + if (plant->pos.z < min_z || plant->pos.z >= max_z) + continue; + if (plant->pos.x < in->min_x() * 16 || plant->pos.x >= in->max_x() * 16) + continue; + if (plant->pos.y < in->min_y() * 16 || plant->pos.y >= in->max_y() * 16) + continue; + } + else + { + if (plant->pos.z - plant->tree_info->roots_depth < min_z || plant->pos.z + plant->tree_info->body_height > max_z) + continue; + if (plant->pos.x - plant->tree_info->dim_x / 2 < in->min_x() * 16 || plant->pos.x + plant->tree_info->dim_x / 2 >= in->max_x() * 16) + continue; + if (plant->pos.y - plant->tree_info->dim_y / 2 < in->min_y() * 16 || plant->pos.y + plant->tree_info->dim_y / 2 >= in->max_y() * 16) + continue; + } + RemoteFortressReader::PlantDef * out_plant = out->add_plant_list(); + out_plant->set_index(plant->material); + out_plant->set_pos_x(plant->pos.x); + out_plant->set_pos_y(plant->pos.y); + out_plant->set_pos_z(plant->pos.z); + } + } #endif - return CR_OK; + return CR_OK; } static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in, UnitList *out) { - auto world = df::global::world; - for (int i = 0; i < world->units.all.size(); i++) - { - df::unit * unit = world->units.all[i]; - auto send_unit = out->add_creature_list(); - send_unit->set_id(unit->id); - send_unit->set_pos_x(unit->pos.x); - send_unit->set_pos_y(unit->pos.y); - send_unit->set_pos_z(unit->pos.z); - send_unit->mutable_race()->set_mat_type(unit->race); - send_unit->mutable_race()->set_mat_index(unit->caste); - ConvertDfColor(Units::getProfessionColor(unit), send_unit->mutable_profession_color()); - send_unit->set_flags1(unit->flags1.whole); - send_unit->set_flags2(unit->flags2.whole); - send_unit->set_flags3(unit->flags3.whole); - send_unit->set_is_soldier(ENUM_ATTR(profession, military, unit->profession)); - auto size_info = send_unit->mutable_size_info(); - size_info->set_size_cur(unit->body.size_info.size_cur); - size_info->set_size_base(unit->body.size_info.size_base); - size_info->set_area_cur(unit->body.size_info.area_cur); - size_info->set_area_base(unit->body.size_info.area_base); - size_info->set_length_cur(unit->body.size_info.length_cur); - size_info->set_length_base(unit->body.size_info.length_base); - if (unit->name.has_name) - { - send_unit->set_name(DF2UTF(Translation::TranslateName(Units::getVisibleName(unit)))); - } - - auto appearance = send_unit->mutable_appearance(); - for (int j = 0; j < unit->appearance.body_modifiers.size(); j++) - appearance->add_body_modifiers(unit->appearance.body_modifiers[j]); - for (int j = 0; j < unit->appearance.bp_modifiers.size(); j++) - appearance->add_bp_modifiers(unit->appearance.bp_modifiers[j]); - for (int j = 0; j < unit->appearance.colors.size(); j++) - appearance->add_colors(unit->appearance.colors[j]); - appearance->set_size_modifier(unit->appearance.size_modifier); - - send_unit->set_profession_id(unit->profession); - - std::vector pvec; - - if (Units::getNoblePositions(&pvec, unit)) - { - for (int j = 0; j < pvec.size(); j++) - { - auto noble_positon = pvec[j]; - send_unit->add_noble_positions(noble_positon.position->code); - } - } - - send_unit->set_rider_id(unit->relationship_ids[df::unit_relationship_type::RiderMount]); - - auto creatureRaw = world->raws.creatures.all[unit->race]; - auto casteRaw = creatureRaw->caste[unit->caste]; - - for (int j = 0; j < unit->appearance.tissue_style_type.size(); j++) - { - auto type = unit->appearance.tissue_style_type[j]; - if (type < 0) - continue; - int style_raw_index = binsearch_index(casteRaw->tissue_styles, &df::tissue_style_raw::id, type); - auto styleRaw = casteRaw->tissue_styles[style_raw_index]; - if (styleRaw->token == "HAIR") - { - auto send_style = appearance->mutable_hair(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "BEARD") - { - auto send_style = appearance->mutable_beard(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "MOUSTACHE") - { - auto send_style = appearance->mutable_moustache(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "SIDEBURNS") - { - auto send_style = appearance->mutable_sideburns(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - } - - for (int j = 0; j < unit->inventory.size(); j++) - { - auto inventory_item = unit->inventory[j]; - auto sent_item = send_unit->add_inventory(); - sent_item->set_mode((InventoryMode)inventory_item->mode); - CopyItem(sent_item->mutable_item(), inventory_item->item); - } - } - return CR_OK; + return GetUnitListInside(stream, NULL, out); +} + +static command_result GetUnitListInside(color_ostream &stream, const BlockRequest *in, UnitList *out) +{ + auto world = df::global::world; + for (int i = 0; i < world->units.all.size(); i++) + { + df::unit * unit = world->units.all[i]; + auto send_unit = out->add_creature_list(); + send_unit->set_id(unit->id); + send_unit->set_pos_x(unit->pos.x); + send_unit->set_pos_y(unit->pos.y); + send_unit->set_pos_z(unit->pos.z); + send_unit->mutable_race()->set_mat_type(unit->race); + send_unit->mutable_race()->set_mat_index(unit->caste); + if (in != NULL) + { + if (unit->pos.z < in->min_z() || unit->pos.z >= in->max_z()) + continue; + if (unit->pos.x < in->min_x() * 16 || unit->pos.x >= in->max_x() * 16) + continue; + if (unit->pos.y < in->min_y() * 16 || unit->pos.y >= in->max_y() * 16) + continue; + } + ConvertDfColor(Units::getProfessionColor(unit), send_unit->mutable_profession_color()); + send_unit->set_flags1(unit->flags1.whole); + send_unit->set_flags2(unit->flags2.whole); + send_unit->set_flags3(unit->flags3.whole); + send_unit->set_is_soldier(ENUM_ATTR(profession, military, unit->profession)); + auto size_info = send_unit->mutable_size_info(); + size_info->set_size_cur(unit->body.size_info.size_cur); + size_info->set_size_base(unit->body.size_info.size_base); + size_info->set_area_cur(unit->body.size_info.area_cur); + size_info->set_area_base(unit->body.size_info.area_base); + size_info->set_length_cur(unit->body.size_info.length_cur); + size_info->set_length_base(unit->body.size_info.length_base); + if (unit->name.has_name) + { + send_unit->set_name(DF2UTF(Translation::TranslateName(Units::getVisibleName(unit)))); + } + + auto appearance = send_unit->mutable_appearance(); + for (int j = 0; j < unit->appearance.body_modifiers.size(); j++) + appearance->add_body_modifiers(unit->appearance.body_modifiers[j]); + for (int j = 0; j < unit->appearance.bp_modifiers.size(); j++) + appearance->add_bp_modifiers(unit->appearance.bp_modifiers[j]); + for (int j = 0; j < unit->appearance.colors.size(); j++) + appearance->add_colors(unit->appearance.colors[j]); + appearance->set_size_modifier(unit->appearance.size_modifier); + + send_unit->set_profession_id(unit->profession); + + std::vector pvec; + + if (Units::getNoblePositions(&pvec, unit)) + { + for (int j = 0; j < pvec.size(); j++) + { + auto noble_positon = pvec[j]; + send_unit->add_noble_positions(noble_positon.position->code); + } + } + + send_unit->set_rider_id(unit->relationship_ids[df::unit_relationship_type::RiderMount]); + + auto creatureRaw = world->raws.creatures.all[unit->race]; + auto casteRaw = creatureRaw->caste[unit->caste]; + + for (int j = 0; j < unit->appearance.tissue_style_type.size(); j++) + { + auto type = unit->appearance.tissue_style_type[j]; + if (type < 0) + continue; + int style_raw_index = binsearch_index(casteRaw->tissue_styles, &df::tissue_style_raw::id, type); + auto styleRaw = casteRaw->tissue_styles[style_raw_index]; + if (styleRaw->token == "HAIR") + { + auto send_style = appearance->mutable_hair(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "BEARD") + { + auto send_style = appearance->mutable_beard(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "MOUSTACHE") + { + auto send_style = appearance->mutable_moustache(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "SIDEBURNS") + { + auto send_style = appearance->mutable_sideburns(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + } + + for (int j = 0; j < unit->inventory.size(); j++) + { + auto inventory_item = unit->inventory[j]; + auto sent_item = send_unit->add_inventory(); + sent_item->set_mode((InventoryMode)inventory_item->mode); + CopyItem(sent_item->mutable_item(), inventory_item->item); + } + + if (unit->flags1.bits.projectile) + { + for (auto proj = world->proj_list.next; proj != NULL; proj = proj->next) + { + STRICT_VIRTUAL_CAST_VAR(item, df::proj_unitst, proj->item); + if (item == NULL) + continue; + if (item->unit != unit) + continue; + send_unit->set_subpos_x(item->pos_x / 100000.0); + send_unit->set_subpos_y(item->pos_y / 100000.0); + send_unit->set_subpos_z(item->pos_z / 140000.0); + } + } + } + return CR_OK; } static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in, ViewInfo *out) { - int x, y, z, w, h, cx, cy, cz; - Gui::getWindowSize(w, h); - Gui::getViewCoords(x, y, z); - Gui::getCursorCoords(cx, cy, cz); + int x, y, z, w, h, cx, cy, cz; + Gui::getWindowSize(w, h); + Gui::getViewCoords(x, y, z); + Gui::getCursorCoords(cx, cy, cz); #if DF_VERSION_INT > 34011 - auto embark = Gui::getViewscreenByType(0); - if (embark) - { - df::embark_location location = embark->location; - df::world_data * data = df::global::world->world_data; - if (data && data->region_map) - { - z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; - } - } + auto embark = Gui::getViewscreenByType(0); + if (embark) + { + df::embark_location location = embark->location; + df::world_data * data = df::global::world->world_data; + if (data && data->region_map) + { + z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; + } + } #endif - out->set_view_pos_x(x); - out->set_view_pos_y(y); - out->set_view_pos_z(z); - out->set_view_size_x(w); - out->set_view_size_y(h); - out->set_cursor_pos_x(cx); - out->set_cursor_pos_y(cy); - out->set_cursor_pos_z(cz); - out->set_follow_unit_id(ui->follow_unit); - out->set_follow_item_id(ui->follow_item); - return CR_OK; + out->set_view_pos_x(x); + out->set_view_pos_y(y); + out->set_view_pos_z(z); + out->set_view_size_x(w); + out->set_view_size_y(h); + out->set_cursor_pos_x(cx); + out->set_cursor_pos_y(cy); + out->set_cursor_pos_z(cz); + + if (gamemode && *gamemode == GameMode::ADVENTURE) + out->set_follow_unit_id(world->units.active[0]->id); + else + out->set_follow_unit_id(ui->follow_unit); + out->set_follow_item_id(ui->follow_item); + return CR_OK; } static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, MapInfo *out) { - if (!Maps::IsValid()) - return CR_FAILURE; - uint32_t size_x, size_y, size_z; - int32_t pos_x, pos_y, pos_z; - Maps::getSize(size_x, size_y, size_z); - Maps::getPosition(pos_x, pos_y, pos_z); - out->set_block_size_x(size_x); - out->set_block_size_y(size_y); - out->set_block_size_z(size_z); - out->set_block_pos_x(pos_x); - out->set_block_pos_y(pos_y); - out->set_block_pos_z(pos_z); - out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); - out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); - out->set_save_name(df::global::world->cur_savegame.save_dir); - return CR_OK; + if (!Maps::IsValid()) + return CR_FAILURE; + uint32_t size_x, size_y, size_z; + int32_t pos_x, pos_y, pos_z; + Maps::getSize(size_x, size_y, size_z); + Maps::getPosition(pos_x, pos_y, pos_z); + out->set_block_size_x(size_x); + out->set_block_size_y(size_y); + out->set_block_size_z(size_z); + out->set_block_pos_x(pos_x); + out->set_block_pos_y(pos_y); + out->set_block_pos_z(pos_z); + out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); + out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); + out->set_save_name(df::global::world->cur_savegame.save_dir); + return CR_OK; } DFCoord GetMapCenter() { - DFCoord output; + DFCoord output; #if DF_VERSION_INT > 34011 - auto embark = Gui::getViewscreenByType(0); - if (embark) - { - df::embark_location location = embark->location; - output.x = (location.region_pos.x * 16) + 8; - output.y = (location.region_pos.y * 16) + 8; - output.z = 100; - df::world_data * data = df::global::world->world_data; - if (data && data->region_map) - { - output.z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; - } - } - else + auto embark = Gui::getViewscreenByType(0); + if (embark) + { + df::embark_location location = embark->location; + output.x = (location.region_pos.x * 16) + 8; + output.y = (location.region_pos.y * 16) + 8; + output.z = 100; + df::world_data * data = df::global::world->world_data; + if (data && data->region_map) + { + output.z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; + } + } + else #endif - if (Maps::IsValid()) - { - int x, y, z; - Maps::getPosition(x,y,z); - output = DFCoord(x, y, z); - } + if (Maps::IsValid()) + { + int x, y, z; + Maps::getPosition(x, y, z); + output = DFCoord(x, y, z); + } #if DF_VERSION_INT > 34011 - else - for (int i = 0; i < df::global::world->armies.all.size(); i++) - { - df::army * thisArmy = df::global::world->armies.all[i]; - if (thisArmy->flags.is_set(df::enums::army_flags::player)) - { - output.x = (thisArmy->pos.x / 3) - 1; - output.y = (thisArmy->pos.y / 3) - 1; - output.z = thisArmy->pos.z; - } - } + else + for (int i = 0; i < df::global::world->armies.all.size(); i++) + { + df::army * thisArmy = df::global::world->armies.all[i]; + if (thisArmy->flags.is_set(df::enums::army_flags::player)) + { + output.x = (thisArmy->pos.x / 3) - 1; + output.y = (thisArmy->pos.y / 3) - 1; + output.z = thisArmy->pos.z; + } + } #endif - return output; + return output; } static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - if (!data->region_map) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); - auto poles = data->flip_latitude; + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + auto poles = data->flip_latitude; #if DF_VERSION_INT > 34011 - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - for (int yy = 0; yy < height; yy++) - for (int xx = 0; xx < width; xx++) - { - df::region_map_entry * map_entry = &data->region_map[xx][yy]; - df::world_region * region = data->regions[map_entry->region_id]; - out->add_elevation(map_entry->elevation); - out->add_rainfall(map_entry->rainfall); - out->add_vegetation(map_entry->vegetation); - out->add_temperature(map_entry->temperature); - out->add_evilness(map_entry->evilness); - out->add_drainage(map_entry->drainage); - out->add_volcanism(map_entry->volcanism); - out->add_savagery(map_entry->savagery); - out->add_salinity(map_entry->salinity); - auto clouds = out->add_clouds(); + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + out->add_elevation(map_entry->elevation); + out->add_rainfall(map_entry->rainfall); + out->add_vegetation(map_entry->vegetation); + out->add_temperature(map_entry->temperature); + out->add_evilness(map_entry->evilness); + out->add_drainage(map_entry->drainage); + out->add_volcanism(map_entry->volcanism); + out->add_savagery(map_entry->savagery); + out->add_salinity(map_entry->salinity); + auto clouds = out->add_clouds(); #if DF_VERSION_INT > 34011 - clouds->set_cirrus(map_entry->clouds.bits.cirrus); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); #else - clouds->set_cirrus(map_entry->clouds.bits.striped); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); + clouds->set_cirrus(map_entry->clouds.bits.striped); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); #endif - if (region->type == world_region_type::Lake) - { - out->add_water_elevation(region->lake_surface); - } - else - out->add_water_elevation(99); - } - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); - - - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + if (region->type == world_region_type::Lake) + { + out->add_water_elevation(region->lake_surface); + } + else + out->add_water_elevation(99); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + + + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) { - df::world_region * region = df::world_region::find(e1->region_id); - df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); - out->set_rainfall(e1->rainfall); - out->set_vegetation(e1->vegetation); - out->set_temperature(e1->temperature); - out->set_evilness(e1->evilness); - out->set_drainage(e1->drainage); - out->set_volcanism(e1->volcanism); - out->set_savagery(e1->savagery); - out->set_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->set_water_elevation(region->lake_surface); - else - out->set_water_elevation(99); - - int topLayer = 0; - for (int i = 0; i < geoBiome->layers.size(); i++) - { - auto layer = geoBiome->layers[i]; - if (layer->top_height == 0) - { - topLayer = layer->mat_index; - } - if (layer->type != geo_layer_type::SOIL - && layer->type != geo_layer_type::SOIL_OCEAN - && layer->type != geo_layer_type::SOIL_SAND) - { - auto mat = out->add_stone_materials(); - mat->set_mat_index(layer->mat_index); - mat->set_mat_type(0); - } - } - auto surfaceMat = out->mutable_surface_material(); - surfaceMat->set_mat_index(topLayer); - surfaceMat->set_mat_type(0); - - for (int i = 0; i < region->population.size(); i++) - { - auto pop = region->population[i]; - if (pop->type == world_population_type::Grass) - { - auto plantMat = out->add_plant_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - else if (pop->type == world_population_type::Tree) - { - auto plantMat = out->add_tree_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - } + df::world_region * region = df::world_region::find(e1->region_id); + df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); + out->set_rainfall(e1->rainfall); + out->set_vegetation(e1->vegetation); + out->set_temperature(e1->temperature); + out->set_evilness(e1->evilness); + out->set_drainage(e1->drainage); + out->set_volcanism(e1->volcanism); + out->set_savagery(e1->savagery); + out->set_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->set_water_elevation(region->lake_surface); + else + out->set_water_elevation(99); + + int topLayer = 0; + for (int i = 0; i < geoBiome->layers.size(); i++) + { + auto layer = geoBiome->layers[i]; + if (layer->top_height == 0) + { + topLayer = layer->mat_index; + } + if (layer->type != geo_layer_type::SOIL + && layer->type != geo_layer_type::SOIL_OCEAN + && layer->type != geo_layer_type::SOIL_SAND) + { + auto mat = out->add_stone_materials(); + mat->set_mat_index(layer->mat_index); + mat->set_mat_type(0); + } + } + auto surfaceMat = out->mutable_surface_material(); + surfaceMat->set_mat_index(topLayer); + surfaceMat->set_mat_type(0); + + for (int i = 0; i < region->population.size(); i++) + { + auto pop = region->population[i]; + if (pop->type == world_population_type::Grass) + { + auto plantMat = out->add_plant_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + else if (pop->type == world_population_type::Tree) + { + auto plantMat = out->add_tree_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + } #if DF_VERSION_INT >= 43005 - out->set_snow(e1->snowfall); + out->set_snow(e1->snowfall); #endif } static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - if (!data->region_map) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); #if DF_VERSION_INT > 34011 - auto poles = data->flip_latitude; - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + auto poles = data->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - for (int yy = 0; yy < height; yy++) - for (int xx = 0; xx < width; xx++) - { - df::region_map_entry * map_entry = &data->region_map[xx][yy]; - df::world_region * region = data->regions[map_entry->region_id]; - - auto regionTile = out->add_region_tiles(); - regionTile->set_elevation(map_entry->elevation); - SetRegionTile(regionTile, map_entry); - auto clouds = out->add_clouds(); + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + + auto regionTile = out->add_region_tiles(); + regionTile->set_elevation(map_entry->elevation); + SetRegionTile(regionTile, map_entry); + auto clouds = out->add_clouds(); #if DF_VERSION_INT > 34011 - clouds->set_cirrus(map_entry->clouds.bits.cirrus); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); #else - clouds->set_cirrus(map_entry->clouds.bits.striped); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); + clouds->set_cirrus(map_entry->clouds.bits.striped); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); #endif - } - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static void AddRegionTiles(WorldMap * out, df::region_map_entry * e1, df::world_data * worldData) { - df::world_region * region = worldData->regions[e1->region_id]; - out->add_rainfall(e1->rainfall); - out->add_vegetation(e1->vegetation); - out->add_temperature(e1->temperature); - out->add_evilness(e1->evilness); - out->add_drainage(e1->drainage); - out->add_volcanism(e1->volcanism); - out->add_savagery(e1->savagery); - out->add_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->add_water_elevation(region->lake_surface); - else - out->add_water_elevation(99); + df::world_region * region = worldData->regions[e1->region_id]; + out->add_rainfall(e1->rainfall); + out->add_vegetation(e1->vegetation); + out->add_temperature(e1->temperature); + out->add_evilness(e1->evilness); + out->add_drainage(e1->drainage); + out->add_volcanism(e1->volcanism); + out->add_savagery(e1->savagery); + out->add_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->add_water_elevation(region->lake_surface); + else + out->add_water_elevation(99); } static void AddRegionTiles(WorldMap * out, df::coord2d pos, df::world_data * worldData) { - if (pos.x < 0) - pos.x = 0; - if (pos.y < 0) - pos.y = 0; - if (pos.x >= worldData->world_width) - pos.x = worldData->world_width - 1; - if (pos.y >= worldData->world_height) - pos.y = worldData->world_height - 1; - AddRegionTiles(out, &worldData->region_map[pos.x][pos.y], worldData); + if (pos.x < 0) + pos.x = 0; + if (pos.y < 0) + pos.y = 0; + if (pos.x >= worldData->world_width) + pos.x = worldData->world_width - 1; + if (pos.y >= worldData->world_height) + pos.y = worldData->world_height - 1; + AddRegionTiles(out, &worldData->region_map[pos.x][pos.y], worldData); } static void AddRegionTiles(RegionTile * out, df::coord2d pos, df::world_data * worldData) { - if (pos.x < 0) - pos.x = 0; - if (pos.y < 0) - pos.y = 0; - if (pos.x >= worldData->world_width) - pos.x = worldData->world_width - 1; - if (pos.y >= worldData->world_height) - pos.y = worldData->world_height - 1; - SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); + if (pos.x < 0) + pos.x = 0; + if (pos.y < 0) + pos.y = 0; + if (pos.x >= worldData->world_width) + pos.x = worldData->world_width - 1; + if (pos.y >= worldData->world_height) + pos.y = worldData->world_height - 1; + SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); } static df::coord2d ShiftCoords(df::coord2d source, int direction) { - switch (direction) - { - case 1: - return df::coord2d(source.x - 1, source.y + 1); - case 2: - return df::coord2d(source.x, source.y + 1); - case 3: - return df::coord2d(source.x + 1, source.y + 1); - case 4: - return df::coord2d(source.x - 1, source.y); - case 5: - return source; - case 6: - return df::coord2d(source.x + 1, source.y); - case 7: - return df::coord2d(source.x - 1, source.y - 1); - case 8: - return df::coord2d(source.x, source.y - 1); - case 9: - return df::coord2d(source.x + 1, source.y - 1); - default: - return source; - } + switch (direction) + { + case 1: + return df::coord2d(source.x - 1, source.y + 1); + case 2: + return df::coord2d(source.x, source.y + 1); + case 3: + return df::coord2d(source.x + 1, source.y + 1); + case 4: + return df::coord2d(source.x - 1, source.y); + case 5: + return source; + case 6: + return df::coord2d(source.x + 1, source.y); + case 7: + return df::coord2d(source.x - 1, source.y - 1); + case 8: + return df::coord2d(source.x, source.y - 1); + case 9: + return df::coord2d(source.x + 1, source.y - 1); + default: + return source; + } } static void CopyLocalMap(df::world_data * worldData, df::world_region_details* worldRegionDetails, WorldMap * out) { - int pos_x = worldRegionDetails->pos.x; - int pos_y = worldRegionDetails->pos.y; - out->set_map_x(pos_x); - out->set_map_y(pos_y); - out->set_world_width(17); - out->set_world_height(17); - char name[256]; - sprintf(name, "Region %d, %d", pos_x, pos_y); - out->set_name_english(name); - out->set_name(name); + int pos_x = worldRegionDetails->pos.x; + int pos_y = worldRegionDetails->pos.y; + out->set_map_x(pos_x); + out->set_map_y(pos_y); + out->set_world_width(17); + out->set_world_height(17); + char name[256]; + sprintf(name, "Region %d, %d", pos_x, pos_y); + out->set_name_english(name); + out->set_name(name); #if DF_VERSION_INT > 34011 - auto poles = worldData->flip_latitude; - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + auto poles = worldData->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - df::world_region_details * south = NULL; - df::world_region_details * east = NULL; - df::world_region_details * southEast = NULL; - - for (int i = 0; i < worldData->region_details.size(); i++) - { - auto region = worldData->region_details[i]; - if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) - southEast = region; - else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) - east = region; - else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) - south = region; - } - - for (int yy = 0; yy < 17; yy++) - for (int xx = 0; xx < 17; xx++) - { - //This is because the bottom row doesn't line up. - if (xx == 16 && yy == 16 && southEast != NULL) - { - out->add_elevation(southEast->elevation[0][0]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); - } - else if (xx == 16 && east != NULL) - { - out->add_elevation(east->elevation[0][yy]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); - } - else if (yy == 16 && south != NULL) - { - out->add_elevation(south->elevation[xx][0]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); - } - else - { - out->add_elevation(worldRegionDetails->elevation[xx][yy]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); - } - - if (xx == 16 || yy == 16) - { - out->add_river_tiles(); - } - else - { - auto riverTile = out->add_river_tiles(); - auto east = riverTile->mutable_east(); - auto north = riverTile->mutable_north(); - auto south = riverTile->mutable_south(); - auto west = riverTile->mutable_west(); - - north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); - north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); - north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); - north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); - - south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); - south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); - south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); - south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); - - west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); - west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); - west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); - west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); - - east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); - east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); - east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); - east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); - } - } + df::world_region_details * south = NULL; + df::world_region_details * east = NULL; + df::world_region_details * southEast = NULL; + + for (int i = 0; i < worldData->region_details.size(); i++) + { + auto region = worldData->region_details[i]; + if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) + southEast = region; + else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) + east = region; + else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) + south = region; + } + + for (int yy = 0; yy < 17; yy++) + for (int xx = 0; xx < 17; xx++) + { + //This is because the bottom row doesn't line up. + if (xx == 16 && yy == 16 && southEast != NULL) + { + out->add_elevation(southEast->elevation[0][0]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); + } + else if (xx == 16 && east != NULL) + { + out->add_elevation(east->elevation[0][yy]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); + } + else if (yy == 16 && south != NULL) + { + out->add_elevation(south->elevation[xx][0]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); + } + else + { + out->add_elevation(worldRegionDetails->elevation[xx][yy]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); + } + + if (xx == 16 || yy == 16) + { + out->add_river_tiles(); + } + else + { + auto riverTile = out->add_river_tiles(); + auto east = riverTile->mutable_east(); + auto north = riverTile->mutable_north(); + auto south = riverTile->mutable_south(); + auto west = riverTile->mutable_west(); + + north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); + north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); + north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); + north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); + + south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); + south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); + south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); + south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); + + west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); + west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); + west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); + west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); + + east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); + east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); + east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); + east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + } + } } static void CopyLocalMap(df::world_data * worldData, df::world_region_details* worldRegionDetails, RegionMap * out) { - int pos_x = worldRegionDetails->pos.x; - int pos_y = worldRegionDetails->pos.y; - out->set_map_x(pos_x); - out->set_map_y(pos_y); - char name[256]; - sprintf(name, "Region %d, %d", pos_x, pos_y); - out->set_name_english(name); - out->set_name(name); - - - df::world_region_details * south = NULL; - df::world_region_details * east = NULL; - df::world_region_details * southEast = NULL; - - for (int i = 0; i < worldData->region_details.size(); i++) - { - auto region = worldData->region_details[i]; - if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) - southEast = region; - else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) - east = region; - else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) - south = region; - } - - RegionTile* outputTiles[17][17]; - - for (int yy = 0; yy < 17; yy++) - for (int xx = 0; xx < 17; xx++) - { - auto tile = out->add_tiles(); - outputTiles[xx][yy] = tile; - //This is because the bottom row doesn't line up. - if (xx == 16 && yy == 16 && southEast != NULL) - { - tile->set_elevation(southEast->elevation[0][0]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); - } - else if (xx == 16 && east != NULL) - { - tile->set_elevation(east->elevation[0][yy]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); - } - else if (yy == 16 && south != NULL) - { - tile->set_elevation(south->elevation[xx][0]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); - } - else - { - tile->set_elevation(worldRegionDetails->elevation[xx][yy]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); - } - - auto riverTile = tile->mutable_river_tiles(); - auto east = riverTile->mutable_east(); - auto north = riverTile->mutable_north(); - auto south = riverTile->mutable_south(); - auto west = riverTile->mutable_west(); - - if (xx < 16) - { - north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); - north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); - north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); - north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); - } - else - { - north->set_active(0); - north->set_elevation(100); - north->set_min_pos(-30000); - north->set_max_pos(-30000); - } - - if (yy < 16 && xx < 16) - { - south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); - south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); - south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); - south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); - } - else - { - south->set_active(0); - south->set_elevation(100); - south->set_min_pos(-30000); - south->set_max_pos(-30000); - } - - if (yy < 16) - { - west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); - west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); - west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); - west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); - } - else - { - west->set_active(0); - west->set_elevation(100); - west->set_min_pos(-30000); - west->set_max_pos(-30000); - } - - if (xx < 16 && yy < 16) - { - east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); - east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); - east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); - east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); - } - else - { - east->set_active(0); - east->set_elevation(100); - east->set_min_pos(-30000); - east->set_max_pos(-30000); - } - } - - auto regionMap = worldData->region_map[pos_x][pos_y]; - - for (int i = 0; i < worldData->sites.size(); i++) - { - df::world_site* site = worldData->sites[i]; - if (!site) - continue; - - int region_min_x = pos_x * 16; - int region_min_y = pos_y * 16; - - if ((site->global_min_x > (region_min_x + 16)) || - (site->global_min_y > (region_min_y + 16)) || - (site->global_max_x < (region_min_x)) || - (site->global_max_y < (region_min_y))) - continue; - - if (site->realization == NULL) - continue; - - auto realization = site->realization; - for (int site_x = 0; site_x < 17; site_x++) - for (int site_y = 0; site_y < 17; site_y++) - { - int region_x = site->global_min_x - region_min_x + site_x; - int region_y = site->global_min_y - region_min_y + site_y; - - if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) - continue; - - for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) - { - auto in_building = realization->building_map[site_x][site_y].buildings[j]; - auto out_building = outputTiles[region_x][region_y]->add_buildings(); - - out_building->set_id(in_building->id); + int pos_x = worldRegionDetails->pos.x; + int pos_y = worldRegionDetails->pos.y; + out->set_map_x(pos_x); + out->set_map_y(pos_y); + char name[256]; + sprintf(name, "Region %d, %d", pos_x, pos_y); + out->set_name_english(name); + out->set_name(name); + + + df::world_region_details * south = NULL; + df::world_region_details * east = NULL; + df::world_region_details * southEast = NULL; + + for (int i = 0; i < worldData->region_details.size(); i++) + { + auto region = worldData->region_details[i]; + if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) + southEast = region; + else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) + east = region; + else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) + south = region; + } + + RegionTile* outputTiles[17][17]; + + for (int yy = 0; yy < 17; yy++) + for (int xx = 0; xx < 17; xx++) + { + auto tile = out->add_tiles(); + outputTiles[xx][yy] = tile; + //This is because the bottom row doesn't line up. + if (xx == 16 && yy == 16 && southEast != NULL) + { + tile->set_elevation(southEast->elevation[0][0]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); + } + else if (xx == 16 && east != NULL) + { + tile->set_elevation(east->elevation[0][yy]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); + } + else if (yy == 16 && south != NULL) + { + tile->set_elevation(south->elevation[xx][0]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); + } + else + { + tile->set_elevation(worldRegionDetails->elevation[xx][yy]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); + } + + auto riverTile = tile->mutable_river_tiles(); + auto east = riverTile->mutable_east(); + auto north = riverTile->mutable_north(); + auto south = riverTile->mutable_south(); + auto west = riverTile->mutable_west(); + + if (xx < 16) + { + north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); + north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); + north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); + north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); + } + else + { + north->set_active(0); + north->set_elevation(100); + north->set_min_pos(-30000); + north->set_max_pos(-30000); + } + + if (yy < 16 && xx < 16) + { + south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); + south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); + south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); + south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); + } + else + { + south->set_active(0); + south->set_elevation(100); + south->set_min_pos(-30000); + south->set_max_pos(-30000); + } + + if (yy < 16) + { + west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); + west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); + west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); + west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); + } + else + { + west->set_active(0); + west->set_elevation(100); + west->set_min_pos(-30000); + west->set_max_pos(-30000); + } + + if (xx < 16 && yy < 16) + { + east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); + east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); + east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); + east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + } + else + { + east->set_active(0); + east->set_elevation(100); + east->set_min_pos(-30000); + east->set_max_pos(-30000); + } + } + + auto regionMap = worldData->region_map[pos_x][pos_y]; + + for (int i = 0; i < worldData->sites.size(); i++) + { + df::world_site* site = worldData->sites[i]; + if (!site) + continue; + + int region_min_x = pos_x * 16; + int region_min_y = pos_y * 16; + + if ((site->global_min_x >(region_min_x + 16)) || + (site->global_min_y > (region_min_y + 16)) || + (site->global_max_x < (region_min_x)) || + (site->global_max_y < (region_min_y))) + continue; + + if (site->realization == NULL) + continue; + + auto realization = site->realization; + for (int site_x = 0; site_x < 17; site_x++) + for (int site_y = 0; site_y < 17; site_y++) + { + int region_x = site->global_min_x - region_min_x + site_x; + int region_y = site->global_min_y - region_min_y + site_y; + + if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) + continue; + + for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) + { + auto in_building = realization->building_map[site_x][site_y].buildings[j]; + auto out_building = outputTiles[region_x][region_y]->add_buildings(); + + out_building->set_id(in_building->id); #if DF_VERSION_INT > 34011 - out_building->set_type((SiteRealizationBuildingType)in_building->type); + out_building->set_type((SiteRealizationBuildingType)in_building->type); #endif - out_building->set_min_x(in_building->min_x - (site_x * 48)); - out_building->set_min_y(in_building->min_y - (site_y * 48)); - out_building->set_max_x(in_building->max_x - (site_x * 48)); - out_building->set_max_y(in_building->max_y - (site_y * 48)); + out_building->set_min_x(in_building->min_x - (site_x * 48)); + out_building->set_min_y(in_building->min_y - (site_y * 48)); + out_building->set_max_x(in_building->max_x - (site_x * 48)); + out_building->set_max_y(in_building->max_y - (site_y * 48)); - CopyMat(out_building->mutable_material(), in_building->item.mat_type, in_building->item.mat_index); + CopyMat(out_building->mutable_material(), in_building->item.mat_type, in_building->item.mat_index); #if DF_VERSION_INT >= 43005 - STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); - if (tower_info) - { - CopyMat(out_building->mutable_material(), tower_info->wall_item.mat_type, tower_info->wall_item.mat_index); - - auto out_tower = out_building->mutable_tower_info(); - out_tower->set_roof_z(tower_info->roof_z); - out_tower->set_round(tower_info->shape.bits.round); - out_tower->set_goblin(tower_info->shape.bits.goblin); - } - STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); - if (wall_info) - { - CopyMat(out_building->mutable_material(), wall_info->wall_item.mat_type, wall_info->wall_item.mat_index); - - auto out_wall = out_building->mutable_wall_info(); - - out_wall->set_start_x(wall_info->start_x - (site_x * 48)); - out_wall->set_start_y(wall_info->start_y - (site_y * 48)); - out_wall->set_start_z(wall_info->start_z); - out_wall->set_end_x(wall_info->end_x - (site_x * 48)); - out_wall->set_end_y(wall_info->end_y - (site_y * 48)); - out_wall->set_end_z(wall_info->end_z); - } + STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); + if (tower_info) + { + CopyMat(out_building->mutable_material(), tower_info->wall_item.mat_type, tower_info->wall_item.mat_index); + + auto out_tower = out_building->mutable_tower_info(); + out_tower->set_roof_z(tower_info->roof_z); + out_tower->set_round(tower_info->shape.bits.round); + out_tower->set_goblin(tower_info->shape.bits.goblin); + } + STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); + if (wall_info) + { + CopyMat(out_building->mutable_material(), wall_info->wall_item.mat_type, wall_info->wall_item.mat_index); + + auto out_wall = out_building->mutable_wall_info(); + + out_wall->set_start_x(wall_info->start_x - (site_x * 48)); + out_wall->set_start_y(wall_info->start_y - (site_y * 48)); + out_wall->set_start_z(wall_info->start_z); + out_wall->set_end_x(wall_info->end_x - (site_x * 48)); + out_wall->set_end_y(wall_info->end_y - (site_y * 48)); + out_wall->set_end_z(wall_info->end_z); + } #endif - } + } - } - } + } + } } static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) { - if (!df::global::world->world_data) - { - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - for (int i = 0; i < data->region_details.size(); i++) - { - df::world_region_details * region = data->region_details[i]; - if (!region) - continue; - WorldMap * regionMap = out->add_world_maps(); - CopyLocalMap(data, region, regionMap); - } - return CR_OK; + if (!df::global::world->world_data) + { + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + for (int i = 0; i < data->region_details.size(); i++) + { + df::world_region_details * region = data->region_details[i]; + if (!region) + continue; + WorldMap * regionMap = out->add_world_maps(); + CopyLocalMap(data, region, regionMap); + } + return CR_OK; } static command_result GetRegionMapsNew(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) { - if (!df::global::world->world_data) - { - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - for (int i = 0; i < data->region_details.size(); i++) - { - df::world_region_details * region = data->region_details[i]; - if (!region) - continue; - RegionMap * regionMap = out->add_region_maps(); - CopyLocalMap(data, region, regionMap); - } - return CR_OK; + if (!df::global::world->world_data) + { + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + for (int i = 0; i < data->region_details.size(); i++) + { + df::world_region_details * region = data->region_details[i]; + if (!region) + continue; + RegionMap * regionMap = out->add_region_maps(); + CopyLocalMap(data, region, regionMap); + } + return CR_OK; } static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage *in, CreatureRawList *out) { - return GetPartialCreatureRaws(stream, NULL, out); + return GetPartialCreatureRaws(stream, NULL, out); } static command_result GetPartialCreatureRaws(color_ostream &stream, const ListRequest *in, CreatureRawList *out) { - if (!df::global::world) - return CR_FAILURE; + if (!df::global::world) + return CR_FAILURE; - df::world * world = df::global::world; + df::world * world = df::global::world; - int list_start = 0; - int list_end = world->raws.creatures.all.size(); + int list_start = 0; + int list_end = world->raws.creatures.all.size(); - if (in != nullptr) - { - list_start = in->list_start(); - if(in->list_end() < list_end) - list_end = in->list_end(); - } + if (in != nullptr) + { + list_start = in->list_start(); + if (in->list_end() < list_end) + list_end = in->list_end(); + } - for (int i = list_start; i < list_end; i++) - { - df::creature_raw * orig_creature = world->raws.creatures.all[i]; + for (int i = list_start; i < list_end; i++) + { + df::creature_raw * orig_creature = world->raws.creatures.all[i]; - auto send_creature = out->add_creature_raws(); + auto send_creature = out->add_creature_raws(); - send_creature->set_index(i); - send_creature->set_creature_id(orig_creature->creature_id); - send_creature->add_name(orig_creature->name[0]); - send_creature->add_name(orig_creature->name[1]); - send_creature->add_name(orig_creature->name[2]); + send_creature->set_index(i); + send_creature->set_creature_id(orig_creature->creature_id); + send_creature->add_name(orig_creature->name[0]); + send_creature->add_name(orig_creature->name[1]); + send_creature->add_name(orig_creature->name[2]); - send_creature->add_general_baby_name(orig_creature->general_baby_name[0]); - send_creature->add_general_baby_name(orig_creature->general_baby_name[1]); + send_creature->add_general_baby_name(orig_creature->general_baby_name[0]); + send_creature->add_general_baby_name(orig_creature->general_baby_name[1]); - send_creature->add_general_child_name(orig_creature->general_child_name[0]); - send_creature->add_general_child_name(orig_creature->general_child_name[1]); + send_creature->add_general_child_name(orig_creature->general_child_name[0]); + send_creature->add_general_child_name(orig_creature->general_child_name[1]); - send_creature->set_creature_tile(orig_creature->creature_tile); - send_creature->set_creature_soldier_tile(orig_creature->creature_soldier_tile); + send_creature->set_creature_tile(orig_creature->creature_tile); + send_creature->set_creature_soldier_tile(orig_creature->creature_soldier_tile); - ConvertDfColor(orig_creature->color, send_creature->mutable_color()); + ConvertDfColor(orig_creature->color, send_creature->mutable_color()); - send_creature->set_adultsize(orig_creature->adultsize); + send_creature->set_adultsize(orig_creature->adultsize); - for (int j = 0; j < orig_creature->caste.size(); j++) - { - auto orig_caste = orig_creature->caste[j]; - if (!orig_caste) - continue; - auto send_caste = send_creature->add_caste(); + for (int j = 0; j < orig_creature->caste.size(); j++) + { + auto orig_caste = orig_creature->caste[j]; + if (!orig_caste) + continue; + auto send_caste = send_creature->add_caste(); - send_caste->set_index(j); + send_caste->set_index(j); - send_caste->set_caste_id(orig_caste->caste_id); + send_caste->set_caste_id(orig_caste->caste_id); - send_caste->add_caste_name(orig_caste->caste_name[0]); - send_caste->add_caste_name(orig_caste->caste_name[1]); - send_caste->add_caste_name(orig_caste->caste_name[2]); + send_caste->add_caste_name(orig_caste->caste_name[0]); + send_caste->add_caste_name(orig_caste->caste_name[1]); + send_caste->add_caste_name(orig_caste->caste_name[2]); - send_caste->add_baby_name(orig_caste->baby_name[0]); - send_caste->add_baby_name(orig_caste->baby_name[1]); + send_caste->add_baby_name(orig_caste->baby_name[0]); + send_caste->add_baby_name(orig_caste->baby_name[1]); - send_caste->add_child_name(orig_caste->child_name[0]); - send_caste->add_child_name(orig_caste->child_name[1]); - send_caste->set_gender(orig_caste->gender); + send_caste->add_child_name(orig_caste->child_name[0]); + send_caste->add_child_name(orig_caste->child_name[1]); + send_caste->set_gender(orig_caste->gender); - for (int partIndex = 0; partIndex < orig_caste->body_info.body_parts.size(); partIndex++) - { - auto orig_part = orig_caste->body_info.body_parts[partIndex]; - if (!orig_part) - continue; - auto send_part = send_caste->add_body_parts(); + for (int partIndex = 0; partIndex < orig_caste->body_info.body_parts.size(); partIndex++) + { + auto orig_part = orig_caste->body_info.body_parts[partIndex]; + if (!orig_part) + continue; + auto send_part = send_caste->add_body_parts(); - send_part->set_token(orig_part->token); - send_part->set_category(orig_part->category); - send_part->set_parent(orig_part->con_part_id); + send_part->set_token(orig_part->token); + send_part->set_category(orig_part->category); + send_part->set_parent(orig_part->con_part_id); - for (int partFlagIndex = 0; partFlagIndex <= ENUM_LAST_ITEM(body_part_raw_flags); partFlagIndex++) - { - send_part->add_flags(orig_part->flags.is_set((body_part_raw_flags::body_part_raw_flags)partFlagIndex)); - } + for (int partFlagIndex = 0; partFlagIndex <= ENUM_LAST_ITEM(body_part_raw_flags); partFlagIndex++) + { + send_part->add_flags(orig_part->flags.is_set((body_part_raw_flags::body_part_raw_flags)partFlagIndex)); + } - for (int layerIndex = 0; layerIndex < orig_part->layers.size(); layerIndex++) - { - auto orig_layer = orig_part->layers[layerIndex]; - if (!orig_layer) - continue; - auto send_layer = send_part->add_layers(); + for (int layerIndex = 0; layerIndex < orig_part->layers.size(); layerIndex++) + { + auto orig_layer = orig_part->layers[layerIndex]; + if (!orig_layer) + continue; + auto send_layer = send_part->add_layers(); - send_layer->set_layer_name(orig_layer->layer_name); - send_layer->set_tissue_id(orig_layer->tissue_id); - send_layer->set_layer_depth(orig_layer->layer_depth); - for (int layerModIndex = 0; layerModIndex < orig_layer->bp_modifiers.size(); layerModIndex++) - { - send_layer->add_bp_modifiers(orig_layer->bp_modifiers[layerModIndex]); - } - } + send_layer->set_layer_name(orig_layer->layer_name); + send_layer->set_tissue_id(orig_layer->tissue_id); + send_layer->set_layer_depth(orig_layer->layer_depth); + for (int layerModIndex = 0; layerModIndex < orig_layer->bp_modifiers.size(); layerModIndex++) + { + send_layer->add_bp_modifiers(orig_layer->bp_modifiers[layerModIndex]); + } + } - send_part->set_relsize(orig_part->relsize); - } + send_part->set_relsize(orig_part->relsize); + } - send_caste->set_total_relsize(orig_caste->body_info.total_relsize); + send_caste->set_total_relsize(orig_caste->body_info.total_relsize); - for (int k = 0; k < orig_caste->bp_appearance.modifiers.size(); k++) - { - auto send_mod = send_caste->add_modifiers(); - auto orig_mod = orig_caste->bp_appearance.modifiers[k]; - send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); + for (int k = 0; k < orig_caste->bp_appearance.modifiers.size(); k++) + { + auto send_mod = send_caste->add_modifiers(); + auto orig_mod = orig_caste->bp_appearance.modifiers[k]; + send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); #if DF_VERSION_INT > 34011 - if (orig_mod->growth_rate > 0) - { - send_mod->set_mod_min(orig_mod->growth_min); - send_mod->set_mod_max(orig_mod->growth_max); - } - else + if (orig_mod->growth_rate > 0) + { + send_mod->set_mod_min(orig_mod->growth_min); + send_mod->set_mod_max(orig_mod->growth_max); + } + else #endif - { - send_mod->set_mod_min(orig_mod->ranges[0]); - send_mod->set_mod_max(orig_mod->ranges[6]); - } - - } - for (int k = 0; k < orig_caste->bp_appearance.modifier_idx.size(); k++) - { - send_caste->add_modifier_idx(orig_caste->bp_appearance.modifier_idx[k]); - send_caste->add_part_idx(orig_caste->bp_appearance.part_idx[k]); - send_caste->add_layer_idx(orig_caste->bp_appearance.layer_idx[k]); - } - for (int k = 0; k < orig_caste->body_appearance_modifiers.size(); k++) - { - auto send_mod = send_caste->add_body_appearance_modifiers(); - auto orig_mod = orig_caste->body_appearance_modifiers[k]; - - send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); + { + send_mod->set_mod_min(orig_mod->ranges[0]); + send_mod->set_mod_max(orig_mod->ranges[6]); + } + + } + for (int k = 0; k < orig_caste->bp_appearance.modifier_idx.size(); k++) + { + send_caste->add_modifier_idx(orig_caste->bp_appearance.modifier_idx[k]); + send_caste->add_part_idx(orig_caste->bp_appearance.part_idx[k]); + send_caste->add_layer_idx(orig_caste->bp_appearance.layer_idx[k]); + } + for (int k = 0; k < orig_caste->body_appearance_modifiers.size(); k++) + { + auto send_mod = send_caste->add_body_appearance_modifiers(); + auto orig_mod = orig_caste->body_appearance_modifiers[k]; + + send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); #if DF_VERSION_INT > 34011 - if (orig_mod->growth_rate > 0) - { - send_mod->set_mod_min(orig_mod->growth_min); - send_mod->set_mod_max(orig_mod->growth_max); - } - else + if (orig_mod->growth_rate > 0) + { + send_mod->set_mod_min(orig_mod->growth_min); + send_mod->set_mod_max(orig_mod->growth_max); + } + else #endif - { - send_mod->set_mod_min(orig_mod->ranges[0]); - send_mod->set_mod_max(orig_mod->ranges[6]); - } - } - for (int k = 0; k < orig_caste->color_modifiers.size(); k++) - { - auto send_mod = send_caste->add_color_modifiers(); - auto orig_mod = orig_caste->color_modifiers[k]; - - for (int l = 0; l < orig_mod->pattern_index.size(); l++) - { - auto orig_pattern = world->raws.language.patterns[orig_mod->pattern_index[l]]; - auto send_pattern = send_mod->add_patterns(); - - for (int m = 0; m < orig_pattern->colors.size(); m++) - { - auto send_color = send_pattern->add_colors(); - auto orig_color = world->raws.language.colors[orig_pattern->colors[m]]; - send_color->set_red(orig_color->red * 255.0); - send_color->set_green(orig_color->green * 255.0); - send_color->set_blue(orig_color->blue * 255.0); - } - - send_pattern->set_id(orig_pattern->id); - send_pattern->set_pattern((PatternType)orig_pattern->pattern); - } - - for (int l = 0; l < orig_mod->body_part_id.size(); l++) - { - send_mod->add_body_part_id(orig_mod->body_part_id[l]); - send_mod->add_tissue_layer_id(orig_mod->tissue_layer_id[l]); - send_mod->set_start_date(orig_mod->start_date); - send_mod->set_end_date(orig_mod->end_date); - send_mod->set_part(orig_mod->part); - } - } - - send_caste->set_description(orig_caste->description); - send_caste->set_adult_size(orig_caste->misc.adult_size); - } - - for (int j = 0; j < orig_creature->tissue.size(); j++) - { - auto orig_tissue = orig_creature->tissue[j]; - auto send_tissue = send_creature->add_tissues(); - - send_tissue->set_id(orig_tissue->id); - send_tissue->set_name(orig_tissue->tissue_name_singular); - send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); - - CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); - } -} - - return CR_OK; + { + send_mod->set_mod_min(orig_mod->ranges[0]); + send_mod->set_mod_max(orig_mod->ranges[6]); + } + } + for (int k = 0; k < orig_caste->color_modifiers.size(); k++) + { + auto send_mod = send_caste->add_color_modifiers(); + auto orig_mod = orig_caste->color_modifiers[k]; + + for (int l = 0; l < orig_mod->pattern_index.size(); l++) + { + auto orig_pattern = world->raws.language.patterns[orig_mod->pattern_index[l]]; + auto send_pattern = send_mod->add_patterns(); + + for (int m = 0; m < orig_pattern->colors.size(); m++) + { + auto send_color = send_pattern->add_colors(); + auto orig_color = world->raws.language.colors[orig_pattern->colors[m]]; + send_color->set_red(orig_color->red * 255.0); + send_color->set_green(orig_color->green * 255.0); + send_color->set_blue(orig_color->blue * 255.0); + } + + send_pattern->set_id(orig_pattern->id); + send_pattern->set_pattern((PatternType)orig_pattern->pattern); + } + + for (int l = 0; l < orig_mod->body_part_id.size(); l++) + { + send_mod->add_body_part_id(orig_mod->body_part_id[l]); + send_mod->add_tissue_layer_id(orig_mod->tissue_layer_id[l]); + send_mod->set_start_date(orig_mod->start_date); + send_mod->set_end_date(orig_mod->end_date); + send_mod->set_part(orig_mod->part); + } + } + + send_caste->set_description(orig_caste->description); + send_caste->set_adult_size(orig_caste->misc.adult_size); + } + + for (int j = 0; j < orig_creature->tissue.size(); j++) + { + auto orig_tissue = orig_creature->tissue[j]; + auto send_tissue = send_creature->add_tissues(); + + send_tissue->set_id(orig_tissue->id); + send_tissue->set_name(orig_tissue->tissue_name_singular); + send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); + + CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); + } + } + + return CR_OK; } static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out) { - GetPartialPlantRaws(stream, nullptr, out); - return CR_OK; + GetPartialPlantRaws(stream, nullptr, out); + return CR_OK; } static command_result GetPartialPlantRaws(color_ostream &stream, const ListRequest *in, PlantRawList *out) { - if (!df::global::world) - return CR_FAILURE; - - df::world * world = df::global::world; - - int list_start = 0; - int list_end = world->raws.plants.all.size(); - - if (in != nullptr) - { - list_start = in->list_start(); - if (in->list_end() < list_end) - list_end = in->list_end(); - } - - for (int i = 0; i < world->raws.plants.all.size(); i++) - { - df::plant_raw* plant_local = world->raws.plants.all[i]; - PlantRaw* plant_remote = out->add_plant_raws(); - - plant_remote->set_index(i); - plant_remote->set_id(plant_local->id); - plant_remote->set_name(plant_local->name); - if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) - plant_remote->set_tile(plant_local->tiles.shrub_tile); - else - plant_remote->set_tile(plant_local->tiles.tree_tile); + if (!df::global::world) + return CR_FAILURE; + + df::world * world = df::global::world; + + int list_start = 0; + int list_end = world->raws.plants.all.size(); + + if (in != nullptr) + { + list_start = in->list_start(); + if (in->list_end() < list_end) + list_end = in->list_end(); + } + + for (int i = 0; i < world->raws.plants.all.size(); i++) + { + df::plant_raw* plant_local = world->raws.plants.all[i]; + PlantRaw* plant_remote = out->add_plant_raws(); + + plant_remote->set_index(i); + plant_remote->set_id(plant_local->id); + plant_remote->set_name(plant_local->name); + if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) + plant_remote->set_tile(plant_local->tiles.shrub_tile); + else + plant_remote->set_tile(plant_local->tiles.tree_tile); #if DF_VERSION_INT > 34011 - for (int j = 0; j < plant_local->growths.size(); j++) - { - df::plant_growth* growth_local = plant_local->growths[j]; - TreeGrowth * growth_remote = plant_remote->add_growths(); - growth_remote->set_index(j); - growth_remote->set_id(growth_local->id); - growth_remote->set_name(growth_local->name); - for (int k = 0; k < growth_local->prints.size(); k++) - { - df::plant_growth_print* print_local = growth_local->prints[k]; - GrowthPrint* print_remote = growth_remote->add_prints(); - print_remote->set_priority(print_local->priority); - print_remote->set_color(print_local->color[0] | (print_local->color[2] * 8)); - print_remote->set_timing_start(print_local->timing_start); - print_remote->set_timing_end(print_local->timing_end); - print_remote->set_tile(print_local->tile_growth); - } - growth_remote->set_timing_start(growth_local->timing_1); - growth_remote->set_timing_end(growth_local->timing_2); - growth_remote->set_twigs(growth_local->locations.bits.twigs); - growth_remote->set_light_branches(growth_local->locations.bits.light_branches); - growth_remote->set_heavy_branches(growth_local->locations.bits.heavy_branches); - growth_remote->set_trunk(growth_local->locations.bits.trunk); - growth_remote->set_roots(growth_local->locations.bits.roots); - growth_remote->set_cap(growth_local->locations.bits.cap); - growth_remote->set_sapling(growth_local->locations.bits.sapling); - growth_remote->set_timing_start(growth_local->timing_1); - growth_remote->set_timing_end(growth_local->timing_2); - growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); - growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); - CopyMat(growth_remote->mutable_mat(), growth_local->mat_type, growth_local->mat_index); - } + for (int j = 0; j < plant_local->growths.size(); j++) + { + df::plant_growth* growth_local = plant_local->growths[j]; + TreeGrowth * growth_remote = plant_remote->add_growths(); + growth_remote->set_index(j); + growth_remote->set_id(growth_local->id); + growth_remote->set_name(growth_local->name); + for (int k = 0; k < growth_local->prints.size(); k++) + { + df::plant_growth_print* print_local = growth_local->prints[k]; + GrowthPrint* print_remote = growth_remote->add_prints(); + print_remote->set_priority(print_local->priority); + print_remote->set_color(print_local->color[0] | (print_local->color[2] * 8)); + print_remote->set_timing_start(print_local->timing_start); + print_remote->set_timing_end(print_local->timing_end); + print_remote->set_tile(print_local->tile_growth); + } + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_twigs(growth_local->locations.bits.twigs); + growth_remote->set_light_branches(growth_local->locations.bits.light_branches); + growth_remote->set_heavy_branches(growth_local->locations.bits.heavy_branches); + growth_remote->set_trunk(growth_local->locations.bits.trunk); + growth_remote->set_roots(growth_local->locations.bits.roots); + growth_remote->set_cap(growth_local->locations.bits.cap); + growth_remote->set_sapling(growth_local->locations.bits.sapling); + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); + growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); + CopyMat(growth_remote->mutable_mat(), growth_local->mat_type, growth_local->mat_index); + } #endif - } - return CR_OK; + } + return CR_OK; } static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out) { - df::graphic * gps = df::global::gps; - out->set_width(gps->dimx); - out->set_height(gps->dimy); - for (int i = 0; i < (gps->dimx * gps->dimy); i++) - { - int index = i * 4; - auto tile = out->add_tiles(); - tile->set_character(gps->screen[index]); - tile->set_foreground(gps->screen[index + 1] | (gps->screen[index + 3] * 8)); - tile->set_background(gps->screen[index + 2]); - } - - return CR_OK; + df::graphic * gps = df::global::gps; + out->set_width(gps->dimx); + out->set_height(gps->dimy); + for (int i = 0; i < (gps->dimx * gps->dimy); i++) + { + int index = i * 4; + auto tile = out->add_tiles(); + tile->set_character(gps->screen[index]); + tile->set_foreground(gps->screen[index + 1] | (gps->screen[index + 3] * 8)); + tile->set_background(gps->screen[index + 2]); + } + + return CR_OK; } static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in) { #if DF_VERSION_INT > 34011 - SDL::Event e; - e.key.type = in->type(); - e.key.state = in->state(); - e.key.ksym.mod = (SDL::Mod)in->mod(); - e.key.ksym.scancode = in->scancode(); - e.key.ksym.sym = (SDL::Key)in->sym(); - e.key.ksym.unicode = in->unicode(); - SDL_PushEvent(&e); + SDL::Event e; + e.key.type = in->type(); + e.key.state = in->state(); + e.key.ksym.mod = (SDL::Mod)in->mod(); + e.key.ksym.scancode = in->scancode(); + e.key.ksym.sym = (SDL::Key)in->sym(); + e.key.ksym.unicode = in->unicode(); + SDL_PushEvent(&e); #endif - return CR_OK; + return CR_OK; } static command_result SendDigCommand(color_ostream &stream, const DigCommand *in) { - MapExtras::MapCache mc; - - for (int i = 0; i < in->locations_size(); i++) - { - auto pos = in->locations(i); - auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); - switch (in->designation()) - { - case NO_DIG: - des.bits.dig = tile_dig_designation::No; - break; - case DEFAULT_DIG: - des.bits.dig = tile_dig_designation::Default; - break; - case UP_DOWN_STAIR_DIG: - des.bits.dig = tile_dig_designation::UpDownStair; - break; - case CHANNEL_DIG: - des.bits.dig = tile_dig_designation::Channel; - break; - case RAMP_DIG: - des.bits.dig = tile_dig_designation::Ramp; - break; - case DOWN_STAIR_DIG: - des.bits.dig = tile_dig_designation::DownStair; - break; - case UP_STAIR_DIG: - des.bits.dig = tile_dig_designation::UpStair; - break; - default: - break; - } - mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); + MapExtras::MapCache mc; + + for (int i = 0; i < in->locations_size(); i++) + { + auto pos = in->locations(i); + auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); + switch (in->designation()) + { + case NO_DIG: + des.bits.dig = tile_dig_designation::No; + break; + case DEFAULT_DIG: + des.bits.dig = tile_dig_designation::Default; + break; + case UP_DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpDownStair; + break; + case CHANNEL_DIG: + des.bits.dig = tile_dig_designation::Channel; + break; + case RAMP_DIG: + des.bits.dig = tile_dig_designation::Ramp; + break; + case DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::DownStair; + break; + case UP_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpStair; + break; + default: + break; + } + mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); #if DF_VERSION_INT >= 43005 - //remove and job postings related. - for (df::job_list_link * listing = &(world->jobs.list); listing != NULL; listing = listing->next) - { - if (listing->item == NULL) - continue; - auto type = listing->item->job_type; - switch (type) - { - case df::enums::job_type::CarveFortification: - case df::enums::job_type::DetailWall: - case df::enums::job_type::DetailFloor: - case df::enums::job_type::Dig: - case df::enums::job_type::CarveUpwardStaircase: - case df::enums::job_type::CarveDownwardStaircase: - case df::enums::job_type::CarveUpDownStaircase: - case df::enums::job_type::CarveRamp: - case df::enums::job_type::DigChannel: - case df::enums::job_type::FellTree: - case df::enums::job_type::GatherPlants: - case df::enums::job_type::RemoveConstruction: - case df::enums::job_type::CarveTrack: - { - if (listing->item->pos == DFCoord(pos.x(), pos.y(), pos.z())) - { - Job::removeJob(listing->item); - goto JOB_FOUND; - } - break; - } - default: - continue; - } - } - JOB_FOUND: - continue; + //remove and job postings related. + for (df::job_list_link * listing = &(world->jobs.list); listing != NULL; listing = listing->next) + { + if (listing->item == NULL) + continue; + auto type = listing->item->job_type; + switch (type) + { + case df::enums::job_type::CarveFortification: + case df::enums::job_type::DetailWall: + case df::enums::job_type::DetailFloor: + case df::enums::job_type::Dig: + case df::enums::job_type::CarveUpwardStaircase: + case df::enums::job_type::CarveDownwardStaircase: + case df::enums::job_type::CarveUpDownStaircase: + case df::enums::job_type::CarveRamp: + case df::enums::job_type::DigChannel: + case df::enums::job_type::FellTree: + case df::enums::job_type::GatherPlants: + case df::enums::job_type::RemoveConstruction: + case df::enums::job_type::CarveTrack: + { + if (listing->item->pos == DFCoord(pos.x(), pos.y(), pos.z())) + { + Job::removeJob(listing->item); + goto JOB_FOUND; + } + break; + } + default: + continue; + } + } + JOB_FOUND: + continue; #endif - } + } - mc.WriteAll(); - return CR_OK; + mc.WriteAll(); + return CR_OK; } static command_result SetPauseState(color_ostream &stream, const SingleBool *in) { - DFHack::World::SetPauseState(in->value()); - return CR_OK; + DFHack::World::SetPauseState(in->value()); + return CR_OK; } static command_result GetPauseState(color_ostream &stream, const EmptyMessage *in, SingleBool *out) { - out->set_value(World::ReadPauseState()); - return CR_OK; + out->set_value(World::ReadPauseState()); + return CR_OK; } -command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out) +static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out) { - out->set_dfhack_version(DFHACK_VERSION); + out->set_dfhack_version(DFHACK_VERSION); #if DF_VERSION_INT == 34011 - out->set_dwarf_fortress_version("0.34.11"); + out->set_dwarf_fortress_version("0.34.11"); #else - out->set_dwarf_fortress_version(DF_VERSION); + out->set_dwarf_fortress_version(DF_VERSION); #endif - out->set_remote_fortress_reader_version(RFR_VERSION); - return command_result(); + out->set_remote_fortress_reader_version(RFR_VERSION); + return CR_OK; } + +static command_result GetReports(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Status * out) +{ + for (int i = 0; i < world->status.reports.size(); i++) + { + auto local_rep = world->status.reports[i]; + if (!local_rep) + continue; + auto send_rep = out->add_reports(); + send_rep->set_type(local_rep->type); + send_rep->set_text(DF2UTF(local_rep->text)); + ConvertDfColor(local_rep->color | (local_rep->bright ? 8 : 0), send_rep->mutable_color()); + send_rep->set_duration(local_rep->duration); + send_rep->set_continuation(local_rep->flags.bits.continuation); + send_rep->set_unconscious(local_rep->flags.bits.unconscious); + send_rep->set_announcement(local_rep->flags.bits.announcement); + send_rep->set_repeat_count(local_rep->repeat_count); + ConvertDFCoord(local_rep->pos, send_rep->mutable_pos()); + send_rep->set_id(local_rep->id); + send_rep->set_year(local_rep->year); + send_rep->set_time(local_rep->time); + } + return CR_OK; +} \ No newline at end of file From c4f9f6edb2534ef4aa3177535a73e40833f4826e Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 17 Dec 2017 18:42:03 +0530 Subject: [PATCH 032/170] Add item stack size. --- plugins/proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader/remotefortressreader.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 62ea5ee54..433a247ae 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -267,6 +267,7 @@ message Item optional MatPair type = 5; optional MatPair material = 6; optional ColorDefinition dye = 7; + optional int32 stack_size = 8; } message MapBlock diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 704c91ae1..22826ead3 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1313,7 +1313,12 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { type->set_mat_index(DfItem->isBag()); } - auto constructed_item = virtual_cast(DfItem); + VIRTUAL_CAST_VAR(actual_item, df::item_actual, DfItem); + if (actual_item) + { + NetItem->set_stack_size(actual_item->stack_size); + } + VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); if (constructed_item) { for (int i = 0; i < constructed_item->improvements.size(); i++) From e478c00ce53831ffaabc812bf39d8baf36d4bc08 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 19 Dec 2017 11:20:12 +0530 Subject: [PATCH 033/170] Replace tab with space. --- plugins/proto/RemoteFortressReader.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 433a247ae..cb7acca07 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -267,7 +267,7 @@ message Item optional MatPair type = 5; optional MatPair material = 6; optional ColorDefinition dye = 7; - optional int32 stack_size = 8; + optional int32 stack_size = 8; } message MapBlock From b8d5aba0efce5e160519566f8290bd718ce28217 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 20 Dec 2017 00:02:26 -0500 Subject: [PATCH 034/170] Update xml, scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index e2e256066..c531a0901 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e2e256066cc4a5c427172d9d27db25b7823e4e86 +Subproject commit c531a09019e521fabb3c943bb49f831f635c309f diff --git a/scripts b/scripts index 252a5adbf..8b6507ed7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 252a5adbf1a5cae45cf7e623d3c5ce6f3aa1195d +Subproject commit 8b6507ed7e8841afe35ee8e156f08edbb7c59f45 From 04b1a8065477bc1b3ca2edd3d216c214f7f5e03c Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 20 Dec 2017 17:11:01 +0530 Subject: [PATCH 035/170] Don't re-send all reports all the time. --- .../remotefortressreader.cpp | 4638 +++++++++-------- 1 file changed, 2326 insertions(+), 2312 deletions(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 22826ead3..93df40dac 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -168,86 +168,86 @@ static command_result GetReports(color_ostream & stream, const EmptyMessage * in void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); const char* growth_locations[] = { - "TWIGS", - "LIGHT_BRANCHES", - "HEAVY_BRANCHES", - "TRUNK", - "ROOTS", - "CAP", - "SAPLING", - "SHRUB" + "TWIGS", + "LIGHT_BRANCHES", + "HEAVY_BRANCHES", + "TRUNK", + "ROOTS", + "CAP", + "SAPLING", + "SHRUB" }; #define GROWTH_LOCATIONS_SIZE 8 command_result dump_bp_mods(color_ostream &out, vector & parameters) { - remove("bp_appearance_mods.csv"); - ofstream output; - output.open("bp_appearance_mods.csv"); - - output << "Race Index;Race;Caste;Bodypart Token;Bodypart Name;Tissue Layer;Modifier Type;Range\n"; - - for (int creatureIndex = 0; creatureIndex < world->raws.creatures.all.size(); creatureIndex++) - { - auto creatureRaw = world->raws.creatures.all[creatureIndex]; - for (int casteIndex = 0; casteIndex < creatureRaw->caste.size(); casteIndex++) - { - df::caste_raw *casteRaw = creatureRaw->caste[casteIndex]; - for (int partIndex = 0; partIndex < casteRaw->bp_appearance.part_idx.size(); partIndex++) - { - output << creatureIndex << ";"; - output << creatureRaw->creature_id << ";"; - output << casteRaw->caste_id << ";"; - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->token << ";"; - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->name_singular[0]->c_str() << ";"; - int layer = casteRaw->bp_appearance.layer_idx[partIndex]; - if (layer < 0) - output << "N/A;"; - else - output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->layers[layer]->layer_name << ";"; - output << ENUM_KEY_STR(appearance_modifier_type, casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->type) << ";"; - auto appMod = casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]; + remove("bp_appearance_mods.csv"); + ofstream output; + output.open("bp_appearance_mods.csv"); + + output << "Race Index;Race;Caste;Bodypart Token;Bodypart Name;Tissue Layer;Modifier Type;Range\n"; + + for (int creatureIndex = 0; creatureIndex < world->raws.creatures.all.size(); creatureIndex++) + { + auto creatureRaw = world->raws.creatures.all[creatureIndex]; + for (int casteIndex = 0; casteIndex < creatureRaw->caste.size(); casteIndex++) + { + df::caste_raw *casteRaw = creatureRaw->caste[casteIndex]; + for (int partIndex = 0; partIndex < casteRaw->bp_appearance.part_idx.size(); partIndex++) + { + output << creatureIndex << ";"; + output << creatureRaw->creature_id << ";"; + output << casteRaw->caste_id << ";"; + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->token << ";"; + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->name_singular[0]->c_str() << ";"; + int layer = casteRaw->bp_appearance.layer_idx[partIndex]; + if (layer < 0) + output << "N/A;"; + else + output << casteRaw->body_info.body_parts[casteRaw->bp_appearance.part_idx[partIndex]]->layers[layer]->layer_name << ";"; + output << ENUM_KEY_STR(appearance_modifier_type, casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->type) << ";"; + auto appMod = casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]; #if DF_VERSION_INT > 34011 - if (appMod->growth_rate > 0) - { - output << appMod->growth_min << " - " << appMod->growth_max << "\n"; - } - else + if (appMod->growth_rate > 0) + { + output << appMod->growth_min << " - " << appMod->growth_max << "\n"; + } + else #endif - { - output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[0] << " - "; - output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[6] << "\n"; - } - } - } - } + { + output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[0] << " - "; + output << casteRaw->bp_appearance.modifiers[casteRaw->bp_appearance.modifier_idx[partIndex]]->ranges[6] << "\n"; + } + } + } + } - output.close(); + output.close(); - return CR_OK; + return CR_OK; } command_result RemoteFortressReader_version(color_ostream &out, vector ¶meters) { - out.print(RFR_VERSION); - return CR_OK; + out.print(RFR_VERSION); + return CR_OK; } // Mandatory init function. If you have some global state, create it here. DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - //// Fill the command list with your commands. - commands.push_back(PluginCommand( - "dump_bp_mods", "Dump bodypart mods for debugging", - dump_bp_mods, false, /* true means that the command can't be used from non-interactive user interface */ - // Extended help string. Used by CR_WRONG_USAGE and the help command: - " This command does nothing at all.\n" - "Example:\n" - " isoworldremote\n" - " Does nothing.\n" - )); - commands.push_back(PluginCommand("RemoteFortressReader_version", "List the loaded RemoteFortressReader version", RemoteFortressReader_version, false, "This is used for plugin version checking.")); - return CR_OK; + //// Fill the command list with your commands. + commands.push_back(PluginCommand( + "dump_bp_mods", "Dump bodypart mods for debugging", + dump_bp_mods, false, /* true means that the command can't be used from non-interactive user interface */ + // Extended help string. Used by CR_WRONG_USAGE and the help command: + " This command does nothing at all.\n" + "Example:\n" + " isoworldremote\n" + " Does nothing.\n" + )); + commands.push_back(PluginCommand("RemoteFortressReader_version", "List the loaded RemoteFortressReader version", RemoteFortressReader_version, false, "This is used for plugin version checking.")); + return CR_OK; } #ifndef SF_ALLOW_REMOTE @@ -256,380 +256,380 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector addFunction("GetMaterialList", GetMaterialList, SF_ALLOW_REMOTE); - svc->addFunction("GetGrowthList", GetGrowthList, SF_ALLOW_REMOTE); - svc->addFunction("GetBlockList", GetBlockList, SF_ALLOW_REMOTE); - svc->addFunction("CheckHashes", CheckHashes, SF_ALLOW_REMOTE); - svc->addFunction("GetTiletypeList", GetTiletypeList, SF_ALLOW_REMOTE); - svc->addFunction("GetPlantList", GetPlantList, SF_ALLOW_REMOTE); - svc->addFunction("GetUnitList", GetUnitList, SF_ALLOW_REMOTE); - svc->addFunction("GetUnitListInside", GetUnitListInside, SF_ALLOW_REMOTE); - svc->addFunction("GetViewInfo", GetViewInfo, SF_ALLOW_REMOTE); - svc->addFunction("GetMapInfo", GetMapInfo, SF_ALLOW_REMOTE); - svc->addFunction("ResetMapHashes", ResetMapHashes, SF_ALLOW_REMOTE); - svc->addFunction("GetItemList", GetItemList, SF_ALLOW_REMOTE); - svc->addFunction("GetBuildingDefList", GetBuildingDefList, SF_ALLOW_REMOTE); - svc->addFunction("GetWorldMap", GetWorldMap, SF_ALLOW_REMOTE); - svc->addFunction("GetWorldMapNew", GetWorldMapNew, SF_ALLOW_REMOTE); - svc->addFunction("GetRegionMaps", GetRegionMaps, SF_ALLOW_REMOTE); - svc->addFunction("GetRegionMapsNew", GetRegionMapsNew, SF_ALLOW_REMOTE); - svc->addFunction("GetCreatureRaws", GetCreatureRaws, SF_ALLOW_REMOTE); - svc->addFunction("GetPartialCreatureRaws", GetPartialCreatureRaws, SF_ALLOW_REMOTE); - svc->addFunction("GetWorldMapCenter", GetWorldMapCenter, SF_ALLOW_REMOTE); - svc->addFunction("GetPlantRaws", GetPlantRaws, SF_ALLOW_REMOTE); - svc->addFunction("GetPartialPlantRaws", GetPartialPlantRaws, SF_ALLOW_REMOTE); - svc->addFunction("CopyScreen", CopyScreen, SF_ALLOW_REMOTE); - svc->addFunction("PassKeyboardEvent", PassKeyboardEvent, SF_ALLOW_REMOTE); - svc->addFunction("SendDigCommand", SendDigCommand, SF_ALLOW_REMOTE); - svc->addFunction("SetPauseState", SetPauseState, SF_ALLOW_REMOTE); - svc->addFunction("GetPauseState", GetPauseState, SF_ALLOW_REMOTE); - svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); - svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); - return svc; + RPCService *svc = new RPCService(); + svc->addFunction("GetMaterialList", GetMaterialList, SF_ALLOW_REMOTE); + svc->addFunction("GetGrowthList", GetGrowthList, SF_ALLOW_REMOTE); + svc->addFunction("GetBlockList", GetBlockList, SF_ALLOW_REMOTE); + svc->addFunction("CheckHashes", CheckHashes, SF_ALLOW_REMOTE); + svc->addFunction("GetTiletypeList", GetTiletypeList, SF_ALLOW_REMOTE); + svc->addFunction("GetPlantList", GetPlantList, SF_ALLOW_REMOTE); + svc->addFunction("GetUnitList", GetUnitList, SF_ALLOW_REMOTE); + svc->addFunction("GetUnitListInside", GetUnitListInside, SF_ALLOW_REMOTE); + svc->addFunction("GetViewInfo", GetViewInfo, SF_ALLOW_REMOTE); + svc->addFunction("GetMapInfo", GetMapInfo, SF_ALLOW_REMOTE); + svc->addFunction("ResetMapHashes", ResetMapHashes, SF_ALLOW_REMOTE); + svc->addFunction("GetItemList", GetItemList, SF_ALLOW_REMOTE); + svc->addFunction("GetBuildingDefList", GetBuildingDefList, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMap", GetWorldMap, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMapNew", GetWorldMapNew, SF_ALLOW_REMOTE); + svc->addFunction("GetRegionMaps", GetRegionMaps, SF_ALLOW_REMOTE); + svc->addFunction("GetRegionMapsNew", GetRegionMapsNew, SF_ALLOW_REMOTE); + svc->addFunction("GetCreatureRaws", GetCreatureRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetPartialCreatureRaws", GetPartialCreatureRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetWorldMapCenter", GetWorldMapCenter, SF_ALLOW_REMOTE); + svc->addFunction("GetPlantRaws", GetPlantRaws, SF_ALLOW_REMOTE); + svc->addFunction("GetPartialPlantRaws", GetPartialPlantRaws, SF_ALLOW_REMOTE); + svc->addFunction("CopyScreen", CopyScreen, SF_ALLOW_REMOTE); + svc->addFunction("PassKeyboardEvent", PassKeyboardEvent, SF_ALLOW_REMOTE); + svc->addFunction("SendDigCommand", SendDigCommand, SF_ALLOW_REMOTE); + svc->addFunction("SetPauseState", SetPauseState, SF_ALLOW_REMOTE); + svc->addFunction("GetPauseState", GetPauseState, SF_ALLOW_REMOTE); + svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); + svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. DFhackCExport command_result plugin_shutdown(color_ostream &out) { - // You *MUST* kill all threads you created before this returns. - // If everything fails, just return CR_FAILURE. Your plugin will be - // in a zombie state, but things won't crash. - return CR_OK; + // You *MUST* kill all threads you created before this returns. + // If everything fails, just return CR_FAILURE. Your plugin will be + // in a zombie state, but things won't crash. + return CR_OK; } uint16_t fletcher16(uint8_t const *data, size_t bytes) { - uint16_t sum1 = 0xff, sum2 = 0xff; - - while (bytes) { - size_t tlen = bytes > 20 ? 20 : bytes; - bytes -= tlen; - do { - sum2 += sum1 += *data++; - } while (--tlen); - sum1 = (sum1 & 0xff) + (sum1 >> 8); - sum2 = (sum2 & 0xff) + (sum2 >> 8); - } - /* Second reduction step to reduce sums to 8 bits */ - sum1 = (sum1 & 0xff) + (sum1 >> 8); - sum2 = (sum2 & 0xff) + (sum2 >> 8); - return sum2 << 8 | sum1; + uint16_t sum1 = 0xff, sum2 = 0xff; + + while (bytes) { + size_t tlen = bytes > 20 ? 20 : bytes; + bytes -= tlen; + do { + sum2 += sum1 += *data++; + } while (--tlen); + sum1 = (sum1 & 0xff) + (sum1 >> 8); + sum2 = (sum2 & 0xff) + (sum2 >> 8); + } + /* Second reduction step to reduce sums to 8 bits */ + sum1 = (sum1 & 0xff) + (sum1 >> 8); + sum2 = (sum2 & 0xff) + (sum2 >> 8); + return sum2 << 8 | sum1; } void ConvertDfColor(int16_t index, RemoteFortressReader::ColorDefinition * out) { - if (!df::global::enabler) - return; + if (!df::global::enabler) + return; - auto enabler = df::global::enabler; + auto enabler = df::global::enabler; - out->set_red((int)(enabler->ccolor[index][0] * 255)); - out->set_green((int)(enabler->ccolor[index][1] * 255)); - out->set_blue((int)(enabler->ccolor[index][2] * 255)); + out->set_red((int)(enabler->ccolor[index][0] * 255)); + out->set_green((int)(enabler->ccolor[index][1] * 255)); + out->set_blue((int)(enabler->ccolor[index][2] * 255)); } void ConvertDfColor(int16_t in[3], RemoteFortressReader::ColorDefinition * out) { - int index = in[0] | (8 * in[2]); - ConvertDfColor(index, out); + int index = in[0] | (8 * in[2]); + ConvertDfColor(index, out); } void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out) { - df::descriptor_color *color = world->raws.language.colors[index]; - out->set_red(color->red * 255); - out->set_green(color->green * 255); - out->set_blue(color->blue * 255); + df::descriptor_color *color = world->raws.language.colors[index]; + out->set_red(color->red * 255); + out->set_green(color->green * 255); + out->set_blue(color->blue * 255); } void ConvertDFCoord(DFCoord in, RemoteFortressReader::Coord * out) { - out->set_x(in.x); - out->set_y(in.y); - out->set_z(in.z); + out->set_x(in.x); + out->set_y(in.y); + out->set_z(in.z); } RemoteFortressReader::TiletypeMaterial TranslateMaterial(df::tiletype_material material) { - switch (material) - { - case df::enums::tiletype_material::NONE: - return RemoteFortressReader::NO_MATERIAL; - break; - case df::enums::tiletype_material::AIR: - return RemoteFortressReader::AIR; - break; - case df::enums::tiletype_material::SOIL: - return RemoteFortressReader::SOIL; - break; - case df::enums::tiletype_material::STONE: - return RemoteFortressReader::STONE; - break; - case df::enums::tiletype_material::FEATURE: - return RemoteFortressReader::FEATURE; - break; - case df::enums::tiletype_material::LAVA_STONE: - return RemoteFortressReader::LAVA_STONE; - break; - case df::enums::tiletype_material::MINERAL: - return RemoteFortressReader::MINERAL; - break; - case df::enums::tiletype_material::FROZEN_LIQUID: - return RemoteFortressReader::FROZEN_LIQUID; - break; - case df::enums::tiletype_material::CONSTRUCTION: - return RemoteFortressReader::CONSTRUCTION; - break; - case df::enums::tiletype_material::GRASS_LIGHT: - return RemoteFortressReader::GRASS_LIGHT; - break; - case df::enums::tiletype_material::GRASS_DARK: - return RemoteFortressReader::GRASS_DARK; - break; - case df::enums::tiletype_material::GRASS_DRY: - return RemoteFortressReader::GRASS_DRY; - break; - case df::enums::tiletype_material::GRASS_DEAD: - return RemoteFortressReader::GRASS_DEAD; - break; - case df::enums::tiletype_material::PLANT: - return RemoteFortressReader::PLANT; - break; - case df::enums::tiletype_material::HFS: - return RemoteFortressReader::HFS; - break; - case df::enums::tiletype_material::CAMPFIRE: - return RemoteFortressReader::CAMPFIRE; - break; - case df::enums::tiletype_material::FIRE: - return RemoteFortressReader::FIRE; - break; - case df::enums::tiletype_material::ASHES: - return RemoteFortressReader::ASHES; - break; - case df::enums::tiletype_material::MAGMA: - return RemoteFortressReader::MAGMA; - break; - case df::enums::tiletype_material::DRIFTWOOD: - return RemoteFortressReader::DRIFTWOOD; - break; - case df::enums::tiletype_material::POOL: - return RemoteFortressReader::POOL; - break; - case df::enums::tiletype_material::BROOK: - return RemoteFortressReader::BROOK; - break; - case df::enums::tiletype_material::RIVER: - return RemoteFortressReader::RIVER; - break; + switch (material) + { + case df::enums::tiletype_material::NONE: + return RemoteFortressReader::NO_MATERIAL; + break; + case df::enums::tiletype_material::AIR: + return RemoteFortressReader::AIR; + break; + case df::enums::tiletype_material::SOIL: + return RemoteFortressReader::SOIL; + break; + case df::enums::tiletype_material::STONE: + return RemoteFortressReader::STONE; + break; + case df::enums::tiletype_material::FEATURE: + return RemoteFortressReader::FEATURE; + break; + case df::enums::tiletype_material::LAVA_STONE: + return RemoteFortressReader::LAVA_STONE; + break; + case df::enums::tiletype_material::MINERAL: + return RemoteFortressReader::MINERAL; + break; + case df::enums::tiletype_material::FROZEN_LIQUID: + return RemoteFortressReader::FROZEN_LIQUID; + break; + case df::enums::tiletype_material::CONSTRUCTION: + return RemoteFortressReader::CONSTRUCTION; + break; + case df::enums::tiletype_material::GRASS_LIGHT: + return RemoteFortressReader::GRASS_LIGHT; + break; + case df::enums::tiletype_material::GRASS_DARK: + return RemoteFortressReader::GRASS_DARK; + break; + case df::enums::tiletype_material::GRASS_DRY: + return RemoteFortressReader::GRASS_DRY; + break; + case df::enums::tiletype_material::GRASS_DEAD: + return RemoteFortressReader::GRASS_DEAD; + break; + case df::enums::tiletype_material::PLANT: + return RemoteFortressReader::PLANT; + break; + case df::enums::tiletype_material::HFS: + return RemoteFortressReader::HFS; + break; + case df::enums::tiletype_material::CAMPFIRE: + return RemoteFortressReader::CAMPFIRE; + break; + case df::enums::tiletype_material::FIRE: + return RemoteFortressReader::FIRE; + break; + case df::enums::tiletype_material::ASHES: + return RemoteFortressReader::ASHES; + break; + case df::enums::tiletype_material::MAGMA: + return RemoteFortressReader::MAGMA; + break; + case df::enums::tiletype_material::DRIFTWOOD: + return RemoteFortressReader::DRIFTWOOD; + break; + case df::enums::tiletype_material::POOL: + return RemoteFortressReader::POOL; + break; + case df::enums::tiletype_material::BROOK: + return RemoteFortressReader::BROOK; + break; + case df::enums::tiletype_material::RIVER: + return RemoteFortressReader::RIVER; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_material::ROOT: - return RemoteFortressReader::ROOT; - break; - case df::enums::tiletype_material::TREE: - return RemoteFortressReader::TREE_MATERIAL; - break; - case df::enums::tiletype_material::MUSHROOM: - return RemoteFortressReader::MUSHROOM; - break; - case df::enums::tiletype_material::UNDERWORLD_GATE: - return RemoteFortressReader::UNDERWORLD_GATE; - break; + case df::enums::tiletype_material::ROOT: + return RemoteFortressReader::ROOT; + break; + case df::enums::tiletype_material::TREE: + return RemoteFortressReader::TREE_MATERIAL; + break; + case df::enums::tiletype_material::MUSHROOM: + return RemoteFortressReader::MUSHROOM; + break; + case df::enums::tiletype_material::UNDERWORLD_GATE: + return RemoteFortressReader::UNDERWORLD_GATE; + break; #endif - default: - return RemoteFortressReader::NO_MATERIAL; - break; - } - return RemoteFortressReader::NO_MATERIAL; + default: + return RemoteFortressReader::NO_MATERIAL; + break; + } + return RemoteFortressReader::NO_MATERIAL; } RemoteFortressReader::TiletypeSpecial TranslateSpecial(df::tiletype_special special) { - switch (special) - { - case df::enums::tiletype_special::NONE: - return RemoteFortressReader::NO_SPECIAL; - break; - case df::enums::tiletype_special::NORMAL: - return RemoteFortressReader::NORMAL; - break; - case df::enums::tiletype_special::RIVER_SOURCE: - return RemoteFortressReader::RIVER_SOURCE; - break; - case df::enums::tiletype_special::WATERFALL: - return RemoteFortressReader::WATERFALL; - break; - case df::enums::tiletype_special::SMOOTH: - return RemoteFortressReader::SMOOTH; - break; - case df::enums::tiletype_special::FURROWED: - return RemoteFortressReader::FURROWED; - break; - case df::enums::tiletype_special::WET: - return RemoteFortressReader::WET; - break; - case df::enums::tiletype_special::DEAD: - return RemoteFortressReader::DEAD; - break; - case df::enums::tiletype_special::WORN_1: - return RemoteFortressReader::WORN_1; - break; - case df::enums::tiletype_special::WORN_2: - return RemoteFortressReader::WORN_2; - break; - case df::enums::tiletype_special::WORN_3: - return RemoteFortressReader::WORN_3; - break; - case df::enums::tiletype_special::TRACK: - return RemoteFortressReader::TRACK; - break; + switch (special) + { + case df::enums::tiletype_special::NONE: + return RemoteFortressReader::NO_SPECIAL; + break; + case df::enums::tiletype_special::NORMAL: + return RemoteFortressReader::NORMAL; + break; + case df::enums::tiletype_special::RIVER_SOURCE: + return RemoteFortressReader::RIVER_SOURCE; + break; + case df::enums::tiletype_special::WATERFALL: + return RemoteFortressReader::WATERFALL; + break; + case df::enums::tiletype_special::SMOOTH: + return RemoteFortressReader::SMOOTH; + break; + case df::enums::tiletype_special::FURROWED: + return RemoteFortressReader::FURROWED; + break; + case df::enums::tiletype_special::WET: + return RemoteFortressReader::WET; + break; + case df::enums::tiletype_special::DEAD: + return RemoteFortressReader::DEAD; + break; + case df::enums::tiletype_special::WORN_1: + return RemoteFortressReader::WORN_1; + break; + case df::enums::tiletype_special::WORN_2: + return RemoteFortressReader::WORN_2; + break; + case df::enums::tiletype_special::WORN_3: + return RemoteFortressReader::WORN_3; + break; + case df::enums::tiletype_special::TRACK: + return RemoteFortressReader::TRACK; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_special::SMOOTH_DEAD: - return RemoteFortressReader::SMOOTH_DEAD; - break; + case df::enums::tiletype_special::SMOOTH_DEAD: + return RemoteFortressReader::SMOOTH_DEAD; + break; #endif - default: - return RemoteFortressReader::NO_SPECIAL; - break; - } - return RemoteFortressReader::NO_SPECIAL; + default: + return RemoteFortressReader::NO_SPECIAL; + break; + } + return RemoteFortressReader::NO_SPECIAL; } RemoteFortressReader::TiletypeShape TranslateShape(df::tiletype_shape shape) { - switch (shape) - { - case df::enums::tiletype_shape::NONE: - return RemoteFortressReader::NO_SHAPE; - break; - case df::enums::tiletype_shape::EMPTY: - return RemoteFortressReader::EMPTY; - break; - case df::enums::tiletype_shape::FLOOR: - return RemoteFortressReader::FLOOR; - break; - case df::enums::tiletype_shape::BOULDER: - return RemoteFortressReader::BOULDER; - break; - case df::enums::tiletype_shape::PEBBLES: - return RemoteFortressReader::PEBBLES; - break; - case df::enums::tiletype_shape::WALL: - return RemoteFortressReader::WALL; - break; - case df::enums::tiletype_shape::FORTIFICATION: - return RemoteFortressReader::FORTIFICATION; - break; - case df::enums::tiletype_shape::STAIR_UP: - return RemoteFortressReader::STAIR_UP; - break; - case df::enums::tiletype_shape::STAIR_DOWN: - return RemoteFortressReader::STAIR_DOWN; - break; - case df::enums::tiletype_shape::STAIR_UPDOWN: - return RemoteFortressReader::STAIR_UPDOWN; - break; - case df::enums::tiletype_shape::RAMP: - return RemoteFortressReader::RAMP; - break; - case df::enums::tiletype_shape::RAMP_TOP: - return RemoteFortressReader::RAMP_TOP; - break; - case df::enums::tiletype_shape::BROOK_BED: - return RemoteFortressReader::BROOK_BED; - break; - case df::enums::tiletype_shape::BROOK_TOP: - return RemoteFortressReader::BROOK_TOP; - break; + switch (shape) + { + case df::enums::tiletype_shape::NONE: + return RemoteFortressReader::NO_SHAPE; + break; + case df::enums::tiletype_shape::EMPTY: + return RemoteFortressReader::EMPTY; + break; + case df::enums::tiletype_shape::FLOOR: + return RemoteFortressReader::FLOOR; + break; + case df::enums::tiletype_shape::BOULDER: + return RemoteFortressReader::BOULDER; + break; + case df::enums::tiletype_shape::PEBBLES: + return RemoteFortressReader::PEBBLES; + break; + case df::enums::tiletype_shape::WALL: + return RemoteFortressReader::WALL; + break; + case df::enums::tiletype_shape::FORTIFICATION: + return RemoteFortressReader::FORTIFICATION; + break; + case df::enums::tiletype_shape::STAIR_UP: + return RemoteFortressReader::STAIR_UP; + break; + case df::enums::tiletype_shape::STAIR_DOWN: + return RemoteFortressReader::STAIR_DOWN; + break; + case df::enums::tiletype_shape::STAIR_UPDOWN: + return RemoteFortressReader::STAIR_UPDOWN; + break; + case df::enums::tiletype_shape::RAMP: + return RemoteFortressReader::RAMP; + break; + case df::enums::tiletype_shape::RAMP_TOP: + return RemoteFortressReader::RAMP_TOP; + break; + case df::enums::tiletype_shape::BROOK_BED: + return RemoteFortressReader::BROOK_BED; + break; + case df::enums::tiletype_shape::BROOK_TOP: + return RemoteFortressReader::BROOK_TOP; + break; #if DF_VERSION_INT > 40001 - case df::enums::tiletype_shape::BRANCH: - return RemoteFortressReader::BRANCH; - break; + case df::enums::tiletype_shape::BRANCH: + return RemoteFortressReader::BRANCH; + break; #endif #if DF_VERSION_INT < 40001 - case df::enums::tiletype_shape::TREE: - return RemoteFortressReader::TREE_SHAPE; - break; + case df::enums::tiletype_shape::TREE: + return RemoteFortressReader::TREE_SHAPE; + break; #endif #if DF_VERSION_INT > 40001 - case df::enums::tiletype_shape::TRUNK_BRANCH: - return RemoteFortressReader::TRUNK_BRANCH; - break; - case df::enums::tiletype_shape::TWIG: - return RemoteFortressReader::TWIG; - break; + case df::enums::tiletype_shape::TRUNK_BRANCH: + return RemoteFortressReader::TRUNK_BRANCH; + break; + case df::enums::tiletype_shape::TWIG: + return RemoteFortressReader::TWIG; + break; #endif - case df::enums::tiletype_shape::SAPLING: - return RemoteFortressReader::SAPLING; - break; - case df::enums::tiletype_shape::SHRUB: - return RemoteFortressReader::SHRUB; - break; - case df::enums::tiletype_shape::ENDLESS_PIT: - return RemoteFortressReader::EMPTY; - break; - default: - return RemoteFortressReader::NO_SHAPE; - break; - } - return RemoteFortressReader::NO_SHAPE; + case df::enums::tiletype_shape::SAPLING: + return RemoteFortressReader::SAPLING; + break; + case df::enums::tiletype_shape::SHRUB: + return RemoteFortressReader::SHRUB; + break; + case df::enums::tiletype_shape::ENDLESS_PIT: + return RemoteFortressReader::EMPTY; + break; + default: + return RemoteFortressReader::NO_SHAPE; + break; + } + return RemoteFortressReader::NO_SHAPE; } RemoteFortressReader::TiletypeVariant TranslateVariant(df::tiletype_variant variant) { - switch (variant) - { - case df::enums::tiletype_variant::NONE: - return RemoteFortressReader::NO_VARIANT; - break; - case df::enums::tiletype_variant::VAR_1: - return RemoteFortressReader::VAR_1; - break; - case df::enums::tiletype_variant::VAR_2: - return RemoteFortressReader::VAR_2; - break; - case df::enums::tiletype_variant::VAR_3: - return RemoteFortressReader::VAR_3; - break; - case df::enums::tiletype_variant::VAR_4: - return RemoteFortressReader::VAR_4; - break; - default: - return RemoteFortressReader::NO_VARIANT; - break; - } - return RemoteFortressReader::NO_VARIANT; + switch (variant) + { + case df::enums::tiletype_variant::NONE: + return RemoteFortressReader::NO_VARIANT; + break; + case df::enums::tiletype_variant::VAR_1: + return RemoteFortressReader::VAR_1; + break; + case df::enums::tiletype_variant::VAR_2: + return RemoteFortressReader::VAR_2; + break; + case df::enums::tiletype_variant::VAR_3: + return RemoteFortressReader::VAR_3; + break; + case df::enums::tiletype_variant::VAR_4: + return RemoteFortressReader::VAR_4; + break; + default: + return RemoteFortressReader::NO_VARIANT; + break; + } + return RemoteFortressReader::NO_VARIANT; } static command_result CheckHashes(color_ostream &stream, const EmptyMessage *in) { - clock_t start = clock(); - for (int i = 0; i < world->map.map_blocks.size(); i++) - { - df::map_block * block = world->map.map_blocks[i]; - fletcher16((uint8_t*)(block->tiletype), 16 * 16 * sizeof(df::enums::tiletype::tiletype)); - } - clock_t end = clock(); - double elapsed_secs = double(end - start) / CLOCKS_PER_SEC; - stream.print("Checking all hashes took %f seconds.", elapsed_secs); - return CR_OK; + clock_t start = clock(); + for (int i = 0; i < world->map.map_blocks.size(); i++) + { + df::map_block * block = world->map.map_blocks[i]; + fletcher16((uint8_t*)(block->tiletype), 16 * 16 * sizeof(df::enums::tiletype::tiletype)); + } + clock_t end = clock(); + double elapsed_secs = double(end - start) / CLOCKS_PER_SEC; + stream.print("Checking all hashes took %f seconds.", elapsed_secs); + return CR_OK; } void CopyMat(RemoteFortressReader::MatPair * mat, int type, int index) { - if (type >= MaterialInfo::FIGURE_BASE && type < MaterialInfo::PLANT_BASE) - { - df::historical_figure * figure = df::historical_figure::find(index); - if (figure) - { - type -= MaterialInfo::GROUP_SIZE; - index = figure->race; - } - } - mat->set_mat_type(type); - mat->set_mat_index(index); + if (type >= MaterialInfo::FIGURE_BASE && type < MaterialInfo::PLANT_BASE) + { + df::historical_figure * figure = df::historical_figure::find(index); + if (figure) + { + type -= MaterialInfo::GROUP_SIZE; + index = figure->race; + } + } + mat->set_mat_type(type); + mat->set_mat_index(index); } @@ -637,2249 +637,2263 @@ map hashes; bool IsTiletypeChanged(DFCoord pos) { - uint16_t hash; - df::map_block * block = Maps::getBlock(pos); - if (block) - hash = fletcher16((uint8_t*)(block->tiletype), 16 * 16 * (sizeof(df::enums::tiletype::tiletype))); - else - hash = 0; - if (hashes[pos] != hash) - { - hashes[pos] = hash; - return true; - } - return false; + uint16_t hash; + df::map_block * block = Maps::getBlock(pos); + if (block) + hash = fletcher16((uint8_t*)(block->tiletype), 16 * 16 * (sizeof(df::enums::tiletype::tiletype))); + else + hash = 0; + if (hashes[pos] != hash) + { + hashes[pos] = hash; + return true; + } + return false; } map waterHashes; bool IsDesignationChanged(DFCoord pos) { - uint16_t hash; - df::map_block * block = Maps::getBlock(pos); - if (block) - hash = fletcher16((uint8_t*)(block->designation), 16 * 16 * (sizeof(df::tile_designation))); - else - hash = 0; - if (waterHashes[pos] != hash) - { - waterHashes[pos] = hash; - return true; - } - return false; + uint16_t hash; + df::map_block * block = Maps::getBlock(pos); + if (block) + hash = fletcher16((uint8_t*)(block->designation), 16 * 16 * (sizeof(df::tile_designation))); + else + hash = 0; + if (waterHashes[pos] != hash) + { + waterHashes[pos] = hash; + return true; + } + return false; } map buildingHashes; bool IsBuildingChanged(DFCoord pos) { - df::map_block * block = Maps::getBlock(pos); - bool changed = false; - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) - { - DFCoord localPos = DFCoord(pos.x * 16 + x, pos.y * 16 + y, pos.z); - auto bld = block->occupancy[x][y].bits.building; - if (buildingHashes[pos] != bld) - { - buildingHashes[pos] = bld; - changed = true; - } - } - return changed; + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) + { + DFCoord localPos = DFCoord(pos.x * 16 + x, pos.y * 16 + y, pos.z); + auto bld = block->occupancy[x][y].bits.building; + if (buildingHashes[pos] != bld) + { + buildingHashes[pos] = bld; + changed = true; + } + } + return changed; } map spatterHashes; bool IsspatterChanged(DFCoord pos) { - df::map_block * block = Maps::getBlock(pos); - bool changed = false; - std::vector materials; + df::map_block * block = Maps::getBlock(pos); + bool changed = false; + std::vector materials; #if DF_VERSION_INT > 34011 - std::vector items; - if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) - return false; + std::vector items; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL, NULL, &items)) + return false; #else - if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL)) - return false; + if (!Maps::SortBlockEvents(block, NULL, NULL, &materials, NULL, NULL)) + return false; #endif - uint16_t hash = 0; + uint16_t hash = 0; - for (int i = 0; i < materials.size(); i++) - { - auto mat = materials[i]; - hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); - } + for (int i = 0; i < materials.size(); i++) + { + auto mat = materials[i]; + hash ^= fletcher16((uint8_t*)mat, sizeof(df::block_square_event_material_spatterst)); + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < items.size(); i++) - { - auto item = items[i]; - hash ^= fletcher16((uint8_t*)item, sizeof(df::block_square_event_item_spatterst)); - } + for (int i = 0; i < items.size(); i++) + { + auto item = items[i]; + hash ^= fletcher16((uint8_t*)item, sizeof(df::block_square_event_item_spatterst)); + } #endif - if (spatterHashes[pos] != hash) - { - spatterHashes[pos] = hash; - return true; - } - return false; + if (spatterHashes[pos] != hash) + { + spatterHashes[pos] = hash; + return true; + } + return false; } map itemHashes; bool isItemChanged(int i) { - uint16_t hash = 0; - auto item = df::item::find(i); - if (item) - { - hash = fletcher16((uint8_t*)item, sizeof(df::item)); - } - if (itemHashes[i] != hash) - { - itemHashes[i] = hash; - return true; - } - return false; + uint16_t hash = 0; + auto item = df::item::find(i); + if (item) + { + hash = fletcher16((uint8_t*)item, sizeof(df::item)); + } + if (itemHashes[i] != hash) + { + itemHashes[i] = hash; + return true; + } + return false; } bool areItemsChanged(vector * items) { - bool result = false; - for (int i = 0; i < items->size(); i++) - { - if (isItemChanged(items->at(i))) - result = true; - } - return result; + bool result = false; + for (int i = 0; i < items->size(); i++) + { + if (isItemChanged(items->at(i))) + result = true; + } + return result; } static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { - hashes.clear(); - waterHashes.clear(); - buildingHashes.clear(); - spatterHashes.clear(); - itemHashes.clear(); - return CR_OK; + hashes.clear(); + waterHashes.clear(); + buildingHashes.clear(); + spatterHashes.clear(); + itemHashes.clear(); + return CR_OK; } df::matter_state GetState(df::material * mat, uint16_t temp = 10015) { - df::matter_state state = matter_state::Solid; - if (temp >= mat->heat.melting_point) - state = df::matter_state::Liquid; - if (temp >= mat->heat.boiling_point) - state = matter_state::Gas; - return state; + df::matter_state state = matter_state::Solid; + if (temp >= mat->heat.melting_point) + state = df::matter_state::Liquid; + if (temp >= mat->heat.boiling_point) + state = matter_state::Gas; + return state; } static command_result GetMaterialList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - - - - df::world_raws *raws = &world->raws; - df::world_history *history = &world->history; - MaterialInfo mat; - for (int i = 0; i < raws->inorganics.size(); i++) - { - mat.decode(0, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(0); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); - } - } - for (int i = 0; i < 19; i++) - { - int k = -1; - if (i == 7) - k = 1;// for coal. - for (int j = -1; j <= k; j++) - { - mat.decode(i, j); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(i); - mat_def->mutable_mat_pair()->set_mat_index(j); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); - } - } - } - for (int i = 0; i < raws->creatures.all.size(); i++) - { - df::creature_raw * creature = raws->creatures.all[i]; - for (int j = 0; j < creature->material.size(); j++) - { - mat.decode(j + MaterialInfo::CREATURE_BASE, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(j + 19); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); - } - } - } - //for (int i = 0; i < history->figures.size(); i++) - //{ - // df::historical_figure * figure = history->figures[i]; - // if (figure->race < 0) - // continue; - // df::creature_raw * creature = raws->creatures.all[figure->race]; - // for (int j = 0; j < creature->material.size(); j++) - // { - // mat.decode(j + MaterialInfo::FIGURE_BASE, i); - // MaterialDefinition *mat_def = out->add_material_list(); - // mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); - // mat_def->mutable_mat_pair()->set_mat_index(i); - // stringstream id; - // id << "HF" << i << mat.getToken(); - // mat_def->set_id(id.str()); - // mat_def->set_name(mat.toString()); //find the name at cave temperature; - // if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) - // { - // df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; - // mat_def->mutable_state_color()->set_red(color->red * 255); - // mat_def->mutable_state_color()->set_green(color->green * 255); - // mat_def->mutable_state_color()->set_blue(color->blue * 255); - // } - // } - //} - for (int i = 0; i < raws->plants.all.size(); i++) - { - df::plant_raw * plant = raws->plants.all[i]; - for (int j = 0; j < plant->material.size(); j++) - { - mat.decode(j + 419, i); - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type(j + 419); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; - if (plant->material[j]->state_color[GetState(plant->material[j])] < raws->language.colors.size()) - { - ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); - } - } - } - return CR_OK; + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + + + + df::world_raws *raws = &world->raws; + df::world_history *history = &world->history; + MaterialInfo mat; + for (int i = 0; i < raws->inorganics.size(); i++) + { + mat.decode(0, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(0); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); + } + } + for (int i = 0; i < 19; i++) + { + int k = -1; + if (i == 7) + k = 1;// for coal. + for (int j = -1; j <= k; j++) + { + mat.decode(i, j); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(i); + mat_def->mutable_mat_pair()->set_mat_index(j); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); + } + } + } + for (int i = 0; i < raws->creatures.all.size(); i++) + { + df::creature_raw * creature = raws->creatures.all[i]; + for (int j = 0; j < creature->material.size(); j++) + { + mat.decode(j + MaterialInfo::CREATURE_BASE, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(j + 19); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); + } + } + } + //for (int i = 0; i < history->figures.size(); i++) + //{ + // df::historical_figure * figure = history->figures[i]; + // if (figure->race < 0) + // continue; + // df::creature_raw * creature = raws->creatures.all[figure->race]; + // for (int j = 0; j < creature->material.size(); j++) + // { + // mat.decode(j + MaterialInfo::FIGURE_BASE, i); + // MaterialDefinition *mat_def = out->add_material_list(); + // mat_def->mutable_mat_pair()->set_mat_type(j + MaterialInfo::FIGURE_BASE); + // mat_def->mutable_mat_pair()->set_mat_index(i); + // stringstream id; + // id << "HF" << i << mat.getToken(); + // mat_def->set_id(id.str()); + // mat_def->set_name(mat.toString()); //find the name at cave temperature; + // if (creature->material[j]->state_color[GetState(creature->material[j])] < raws->language.colors.size()) + // { + // df::descriptor_color *color = raws->language.colors[creature->material[j]->state_color[GetState(creature->material[j])]]; + // mat_def->mutable_state_color()->set_red(color->red * 255); + // mat_def->mutable_state_color()->set_green(color->green * 255); + // mat_def->mutable_state_color()->set_blue(color->blue * 255); + // } + // } + //} + for (int i = 0; i < raws->plants.all.size(); i++) + { + df::plant_raw * plant = raws->plants.all[i]; + for (int j = 0; j < plant->material.size(); j++) + { + mat.decode(j + 419, i); + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type(j + 419); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(mat.getToken()); + mat_def->set_name(mat.toString()); //find the name at cave temperature; + if (plant->material[j]->state_color[GetState(plant->material[j])] < raws->language.colors.size()) + { + ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); + } + } + } + return CR_OK; } static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - FOR_ENUM_ITEMS(item_type, it) - { - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(-1); - mat_def->set_id(ENUM_KEY_STR(item_type, it)); - if (it == item_type::BOX) - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(0); - mat_def->set_id("BOX_CHEST"); - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(1); - mat_def->set_id("BOX_BAG"); - } - int subtypes = Items::getSubtypeCount(it); - if (subtypes >= 0) - { - for (int i = 0; i < subtypes; i++) - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(i); - df::itemdef * item = Items::getSubtypeDef(it, i); - mat_def->set_id(item->id); - } - } - } - - - return CR_OK; + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + FOR_ENUM_ITEMS(item_type, it) + { + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(-1); + mat_def->set_id(ENUM_KEY_STR(item_type, it)); + if (it == item_type::BOX) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(0); + mat_def->set_id("BOX_CHEST"); + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(1); + mat_def->set_id("BOX_BAG"); + } + int subtypes = Items::getSubtypeCount(it); + if (subtypes >= 0) + { + for (int i = 0; i < subtypes; i++) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + df::itemdef * item = Items::getSubtypeDef(it, i); + mat_def->set_id(item->id); + } + } + } + + + return CR_OK; } static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } - df::world_raws *raws = &world->raws; - if (!raws) - return CR_OK;//'. + df::world_raws *raws = &world->raws; + if (!raws) + return CR_OK;//'. - for (int i = 0; i < raws->plants.all.size(); i++) - { - df::plant_raw * pp = raws->plants.all[i]; - if (!pp) - continue; - MaterialDefinition * basePlant = out->add_material_list(); - basePlant->set_id(pp->id + ":BASE"); - basePlant->set_name(pp->name); - basePlant->mutable_mat_pair()->set_mat_type(-1); - basePlant->mutable_mat_pair()->set_mat_index(i); + for (int i = 0; i < raws->plants.all.size(); i++) + { + df::plant_raw * pp = raws->plants.all[i]; + if (!pp) + continue; + MaterialDefinition * basePlant = out->add_material_list(); + basePlant->set_id(pp->id + ":BASE"); + basePlant->set_name(pp->name); + basePlant->mutable_mat_pair()->set_mat_type(-1); + basePlant->mutable_mat_pair()->set_mat_index(i); #if DF_VERSION_INT > 40001 - for (int g = 0; g < pp->growths.size(); g++) - { - df::plant_growth* growth = pp->growths[g]; - if (!growth) - continue; - for (int l = 0; l < GROWTH_LOCATIONS_SIZE; l++) - { - MaterialDefinition * out_growth = out->add_material_list(); - out_growth->set_id(pp->id + ":" + growth->id + +":" + growth_locations[l]); - out_growth->set_name(growth->name); - out_growth->mutable_mat_pair()->set_mat_type(g * 10 + l); - out_growth->mutable_mat_pair()->set_mat_index(i); - } - } + for (int g = 0; g < pp->growths.size(); g++) + { + df::plant_growth* growth = pp->growths[g]; + if (!growth) + continue; + for (int l = 0; l < GROWTH_LOCATIONS_SIZE; l++) + { + MaterialDefinition * out_growth = out->add_material_list(); + out_growth->set_id(pp->id + ":" + growth->id + +":" + growth_locations[l]); + out_growth->set_name(growth->name); + out_growth->mutable_mat_pair()->set_mat_type(g * 10 + l); + out_growth->mutable_mat_pair()->set_mat_index(i); + } + } #endif - } - return CR_OK; + } + return CR_OK; } void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - - MapExtras::Block * block = MC->BlockAtTile(DfBlock->map_pos); - - int trunk_percent[16][16]; - int tree_x[16][16]; - int tree_y[16][16]; - int tree_z[16][16]; - for (int xx = 0; xx < 16; xx++) - for (int yy = 0; yy < 16; yy++) - { - trunk_percent[xx][yy] = 255; - tree_x[xx][yy] = -3000; - tree_y[xx][yy] = -3000; - tree_z[xx][yy] = -3000; - } + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + + MapExtras::Block * block = MC->BlockAtTile(DfBlock->map_pos); + + int trunk_percent[16][16]; + int tree_x[16][16]; + int tree_y[16][16]; + int tree_z[16][16]; + for (int xx = 0; xx < 16; xx++) + for (int yy = 0; yy < 16; yy++) + { + trunk_percent[xx][yy] = 255; + tree_x[xx][yy] = -3000; + tree_y[xx][yy] = -3000; + tree_z[xx][yy] = -3000; + } #if DF_VERSION_INT > 34011 - df::map_block_column * column = df::global::world->map.column_index[(DfBlock->map_pos.x / 48) * 3][(DfBlock->map_pos.y / 48) * 3]; - for (int i = 0; i < column->plants.size(); i++) - { - df::plant* plant = column->plants[i]; - if (plant->tree_info == NULL) - continue; - df::plant_tree_info * tree_info = plant->tree_info; - if ( - plant->pos.z - tree_info->roots_depth > DfBlock->map_pos.z - || (plant->pos.z + tree_info->body_height) <= DfBlock->map_pos.z - || (plant->pos.x - tree_info->dim_x / 2) > (DfBlock->map_pos.x + 16) - || (plant->pos.x + tree_info->dim_x / 2) < (DfBlock->map_pos.x) - || (plant->pos.y - tree_info->dim_y / 2) > (DfBlock->map_pos.y + 16) - || (plant->pos.y + tree_info->dim_y / 2) < (DfBlock->map_pos.y) - ) - continue; - DFCoord localPos = plant->pos - DfBlock->map_pos; - for (int xx = 0; xx < tree_info->dim_x; xx++) - for (int yy = 0; yy < tree_info->dim_y; yy++) - { - int xxx = localPos.x - (tree_info->dim_x / 2) + xx; - int yyy = localPos.y - (tree_info->dim_y / 2) + yy; - if (xxx < 0 - || yyy < 0 - || xxx >= 16 - || yyy >= 16 - ) - continue; - df::plant_tree_tile tile; - if (-localPos.z < 0) - { - tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; - } - else - { - tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; - } - if (!tile.whole || tile.bits.blocked) - continue; - if (tree_info->body_height <= 1) - trunk_percent[xxx][yyy] = 0; - else - trunk_percent[xxx][yyy] = -localPos.z * 100 / (tree_info->body_height - 1); - tree_x[xxx][yyy] = xx - tree_info->dim_x / 2; - tree_y[xxx][yyy] = yy - tree_info->dim_y / 2; - tree_z[xxx][yyy] = localPos.z; - } - } + df::map_block_column * column = df::global::world->map.column_index[(DfBlock->map_pos.x / 48) * 3][(DfBlock->map_pos.y / 48) * 3]; + for (int i = 0; i < column->plants.size(); i++) + { + df::plant* plant = column->plants[i]; + if (plant->tree_info == NULL) + continue; + df::plant_tree_info * tree_info = plant->tree_info; + if ( + plant->pos.z - tree_info->roots_depth > DfBlock->map_pos.z + || (plant->pos.z + tree_info->body_height) <= DfBlock->map_pos.z + || (plant->pos.x - tree_info->dim_x / 2) > (DfBlock->map_pos.x + 16) + || (plant->pos.x + tree_info->dim_x / 2) < (DfBlock->map_pos.x) + || (plant->pos.y - tree_info->dim_y / 2) > (DfBlock->map_pos.y + 16) + || (plant->pos.y + tree_info->dim_y / 2) < (DfBlock->map_pos.y) + ) + continue; + DFCoord localPos = plant->pos - DfBlock->map_pos; + for (int xx = 0; xx < tree_info->dim_x; xx++) + for (int yy = 0; yy < tree_info->dim_y; yy++) + { + int xxx = localPos.x - (tree_info->dim_x / 2) + xx; + int yyy = localPos.y - (tree_info->dim_y / 2) + yy; + if (xxx < 0 + || yyy < 0 + || xxx >= 16 + || yyy >= 16 + ) + continue; + df::plant_tree_tile tile; + if (-localPos.z < 0) + { + tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; + } + else + { + tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; + } + if (!tile.whole || tile.bits.blocked) + continue; + if (tree_info->body_height <= 1) + trunk_percent[xxx][yyy] = 0; + else + trunk_percent[xxx][yyy] = -localPos.z * 100 / (tree_info->body_height - 1); + tree_x[xxx][yyy] = xx - tree_info->dim_x / 2; + tree_y[xxx][yyy] = yy - tree_info->dim_y / 2; + tree_z[xxx][yyy] = localPos.z; + } + } #endif - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - df::tiletype tile = DfBlock->tiletype[xx][yy]; - NetBlock->add_tiles(tile); - df::coord2d p = df::coord2d(xx, yy); - t_matpair baseMat = block->baseMaterialAt(p); - t_matpair staticMat = block->staticMaterialAt(p); - switch (tileMaterial(tile)) - { - case tiletype_material::FROZEN_LIQUID: - staticMat.mat_type = builtin_mats::WATER; - staticMat.mat_index = -1; - break; - default: - break; - } - CopyMat(NetBlock->add_materials(), staticMat.mat_type, staticMat.mat_index); - CopyMat(NetBlock->add_layer_materials(), 0, block->layerMaterialAt(p)); - CopyMat(NetBlock->add_vein_materials(), 0, block->veinMaterialAt(p)); - CopyMat(NetBlock->add_base_materials(), baseMat.mat_type, baseMat.mat_index); - RemoteFortressReader::MatPair * constructionItem = NetBlock->add_construction_items(); - CopyMat(constructionItem, -1, -1); - if (tileMaterial(tile) == tiletype_material::CONSTRUCTION) - { - df::construction *con = df::construction::find(DfBlock->map_pos + df::coord(xx, yy, 0)); - if (con) - { - CopyMat(constructionItem, con->item_type, con->item_subtype); - } - } - NetBlock->add_tree_percent(trunk_percent[xx][yy]); - NetBlock->add_tree_x(tree_x[xx][yy]); - NetBlock->add_tree_y(tree_y[xx][yy]); - NetBlock->add_tree_z(tree_z[xx][yy]); - } + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + df::tiletype tile = DfBlock->tiletype[xx][yy]; + NetBlock->add_tiles(tile); + df::coord2d p = df::coord2d(xx, yy); + t_matpair baseMat = block->baseMaterialAt(p); + t_matpair staticMat = block->staticMaterialAt(p); + switch (tileMaterial(tile)) + { + case tiletype_material::FROZEN_LIQUID: + staticMat.mat_type = builtin_mats::WATER; + staticMat.mat_index = -1; + break; + default: + break; + } + CopyMat(NetBlock->add_materials(), staticMat.mat_type, staticMat.mat_index); + CopyMat(NetBlock->add_layer_materials(), 0, block->layerMaterialAt(p)); + CopyMat(NetBlock->add_vein_materials(), 0, block->veinMaterialAt(p)); + CopyMat(NetBlock->add_base_materials(), baseMat.mat_type, baseMat.mat_index); + RemoteFortressReader::MatPair * constructionItem = NetBlock->add_construction_items(); + CopyMat(constructionItem, -1, -1); + if (tileMaterial(tile) == tiletype_material::CONSTRUCTION) + { + df::construction *con = df::construction::find(DfBlock->map_pos + df::coord(xx, yy, 0)); + if (con) + { + CopyMat(constructionItem, con->item_type, con->item_subtype); + } + } + NetBlock->add_tree_percent(trunk_percent[xx][yy]); + NetBlock->add_tree_x(tree_x[xx][yy]); + NetBlock->add_tree_y(tree_y[xx][yy]); + NetBlock->add_tree_z(tree_z[xx][yy]); + } } void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - df::tile_designation designation = DfBlock->designation[xx][yy]; - df::tile_occupancy occupancy = DfBlock->occupancy[xx][yy]; - int lava = 0; - int water = 0; - if (designation.bits.liquid_type == df::enums::tile_liquid::Magma) - lava = designation.bits.flow_size; - else - water = designation.bits.flow_size; - NetBlock->add_magma(lava); - NetBlock->add_water(water); - NetBlock->add_aquifer(designation.bits.water_table); - NetBlock->add_light(designation.bits.light); - NetBlock->add_outside(designation.bits.outside); - NetBlock->add_subterranean(designation.bits.subterranean); - NetBlock->add_water_salt(designation.bits.water_salt); - NetBlock->add_water_stagnant(designation.bits.water_stagnant); - if (gamemode && (*gamemode == game_mode::ADVENTURE)) - { - auto fog_of_war = DfBlock->fog_of_war[xx][yy]; - NetBlock->add_hidden(designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden); - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - NetBlock->add_tile_dig_designation_marker(false); - NetBlock->add_tile_dig_designation_auto(false); - } - else - { - NetBlock->add_hidden(designation.bits.hidden); + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + df::tile_designation designation = DfBlock->designation[xx][yy]; + df::tile_occupancy occupancy = DfBlock->occupancy[xx][yy]; + int lava = 0; + int water = 0; + if (designation.bits.liquid_type == df::enums::tile_liquid::Magma) + lava = designation.bits.flow_size; + else + water = designation.bits.flow_size; + NetBlock->add_magma(lava); + NetBlock->add_water(water); + NetBlock->add_aquifer(designation.bits.water_table); + NetBlock->add_light(designation.bits.light); + NetBlock->add_outside(designation.bits.outside); + NetBlock->add_subterranean(designation.bits.subterranean); + NetBlock->add_water_salt(designation.bits.water_salt); + NetBlock->add_water_stagnant(designation.bits.water_stagnant); + if (gamemode && (*gamemode == game_mode::ADVENTURE)) + { + auto fog_of_war = DfBlock->fog_of_war[xx][yy]; + NetBlock->add_hidden(designation.bits.dig == TileDigDesignation::NO_DIG || designation.bits.hidden); + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + NetBlock->add_tile_dig_designation_marker(false); + NetBlock->add_tile_dig_designation_auto(false); + } + else + { + NetBlock->add_hidden(designation.bits.hidden); #if DF_VERSION_INT > 34011 - NetBlock->add_tile_dig_designation_marker(occupancy.bits.dig_marked); - NetBlock->add_tile_dig_designation_auto(occupancy.bits.dig_auto); + NetBlock->add_tile_dig_designation_marker(occupancy.bits.dig_marked); + NetBlock->add_tile_dig_designation_auto(occupancy.bits.dig_auto); #endif - switch (designation.bits.dig) - { - case df::enums::tile_dig_designation::No: - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - break; - case df::enums::tile_dig_designation::Default: - NetBlock->add_tile_dig_designation(TileDigDesignation::DEFAULT_DIG); - break; - case df::enums::tile_dig_designation::UpDownStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::UP_DOWN_STAIR_DIG); - break; - case df::enums::tile_dig_designation::Channel: - NetBlock->add_tile_dig_designation(TileDigDesignation::CHANNEL_DIG); - break; - case df::enums::tile_dig_designation::Ramp: - NetBlock->add_tile_dig_designation(TileDigDesignation::RAMP_DIG); - break; - case df::enums::tile_dig_designation::DownStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::DOWN_STAIR_DIG); - break; - case df::enums::tile_dig_designation::UpStair: - NetBlock->add_tile_dig_designation(TileDigDesignation::UP_STAIR_DIG); - break; - default: - NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); - break; - } - } - } + switch (designation.bits.dig) + { + case df::enums::tile_dig_designation::No: + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + break; + case df::enums::tile_dig_designation::Default: + NetBlock->add_tile_dig_designation(TileDigDesignation::DEFAULT_DIG); + break; + case df::enums::tile_dig_designation::UpDownStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::UP_DOWN_STAIR_DIG); + break; + case df::enums::tile_dig_designation::Channel: + NetBlock->add_tile_dig_designation(TileDigDesignation::CHANNEL_DIG); + break; + case df::enums::tile_dig_designation::Ramp: + NetBlock->add_tile_dig_designation(TileDigDesignation::RAMP_DIG); + break; + case df::enums::tile_dig_designation::DownStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::DOWN_STAIR_DIG); + break; + case df::enums::tile_dig_designation::UpStair: + NetBlock->add_tile_dig_designation(TileDigDesignation::UP_STAIR_DIG); + break; + default: + NetBlock->add_tile_dig_designation(TileDigDesignation::NO_DIG); + break; + } + } + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < world->jobs.postings.size(); i++) - { - auto job = world->jobs.postings[i]->job; - if (job == nullptr) - continue; - if ( - job->pos.z > DfBlock->map_pos.z - || job->pos.z < DfBlock->map_pos.z - || job->pos.x >= (DfBlock->map_pos.x + 16) - || job->pos.x < (DfBlock->map_pos.x) - || job->pos.y >= (DfBlock->map_pos.y + 16) - || job->pos.y < (DfBlock->map_pos.y) - ) - continue; - - int index = (job->pos.x - DfBlock->map_pos.x) + (16 * (job->pos.y - DfBlock->map_pos.y)); - - switch (job->job_type) - { - case job_type::Dig: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - case job_type::CarveUpwardStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_STAIR_DIG); - break; - case job_type::CarveDownwardStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DOWN_STAIR_DIG); - break; - case job_type::CarveUpDownStaircase: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_DOWN_STAIR_DIG); - break; - case job_type::CarveRamp: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::RAMP_DIG); - break; - case job_type::DigChannel: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::CHANNEL_DIG); - break; - case job_type::FellTree: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - case job_type::GatherPlants: - NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); - break; - default: - break; - } - } + for (int i = 0; i < world->jobs.postings.size(); i++) + { + auto job = world->jobs.postings[i]->job; + if (job == nullptr) + continue; + if ( + job->pos.z > DfBlock->map_pos.z + || job->pos.z < DfBlock->map_pos.z + || job->pos.x >= (DfBlock->map_pos.x + 16) + || job->pos.x < (DfBlock->map_pos.x) + || job->pos.y >= (DfBlock->map_pos.y + 16) + || job->pos.y < (DfBlock->map_pos.y) + ) + continue; + + int index = (job->pos.x - DfBlock->map_pos.x) + (16 * (job->pos.y - DfBlock->map_pos.y)); + + switch (job->job_type) + { + case job_type::Dig: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::CarveUpwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_STAIR_DIG); + break; + case job_type::CarveDownwardStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DOWN_STAIR_DIG); + break; + case job_type::CarveUpDownStaircase: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::UP_DOWN_STAIR_DIG); + break; + case job_type::CarveRamp: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::RAMP_DIG); + break; + case job_type::DigChannel: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::CHANNEL_DIG); + break; + case job_type::FellTree: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + case job_type::GatherPlants: + NetBlock->set_tile_dig_designation(index, TileDigDesignation::DEFAULT_DIG); + break; + default: + break; + } + } #endif } void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC) { - for (int i = 0; i < df::global::world->buildings.all.size(); i++) - { - df::building * bld = df::global::world->buildings.all[i]; - if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y) - { - auto out_bld = NetBlock->add_buildings(); - out_bld->set_index(bld->id); - continue; - } - - int z2 = bld->z; - - if (bld->getType() == building_type::Well) - { - df::building_wellst * well_building = virtual_cast(bld); - if (well_building) - { - z2 = well_building->bucket_z; - } - } - if (bld->z < min.z || z2 >= max.z) - { - auto out_bld = NetBlock->add_buildings(); - out_bld->set_index(bld->id); - continue; - } - auto out_bld = NetBlock->add_buildings(); - CopyBuilding(i, out_bld); - df::building_actual* actualBuilding = virtual_cast(bld); - if (actualBuilding) - { - for (int i = 0; i < actualBuilding->contained_items.size(); i++) - { - auto buildingItem = out_bld->add_items(); - buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); - CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); - } - } - } + for (int i = 0; i < df::global::world->buildings.all.size(); i++) + { + df::building * bld = df::global::world->buildings.all[i]; + if (bld->x1 >= max.x || bld->y1 >= max.y || bld->x2 < min.x || bld->y2 < min.y) + { + auto out_bld = NetBlock->add_buildings(); + out_bld->set_index(bld->id); + continue; + } + + int z2 = bld->z; + + if (bld->getType() == building_type::Well) + { + df::building_wellst * well_building = virtual_cast(bld); + if (well_building) + { + z2 = well_building->bucket_z; + } + } + if (bld->z < min.z || z2 >= max.z) + { + auto out_bld = NetBlock->add_buildings(); + out_bld->set_index(bld->id); + continue; + } + auto out_bld = NetBlock->add_buildings(); + CopyBuilding(i, out_bld); + df::building_actual* actualBuilding = virtual_cast(bld); + if (actualBuilding) + { + for (int i = 0; i < actualBuilding->contained_items.size(); i++) + { + auto buildingItem = out_bld->add_items(); + buildingItem->set_mode(actualBuilding->contained_items[i]->use_mode); + CopyItem(buildingItem->mutable_item(), actualBuilding->contained_items[i]->item); + } + } + } } void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - std::vector materials; + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + std::vector materials; #if DF_VERSION_INT > 34011 - std::vector items; - std::vector grasses; - if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, &grasses, NULL, NULL, &items)) - return; + std::vector items; + std::vector grasses; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, &grasses, NULL, NULL, &items)) + return; #else - if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL)) - return; + if (!Maps::SortBlockEvents(DfBlock, NULL, NULL, &materials, NULL, NULL)) + return; #endif - for (int yy = 0; yy < 16; yy++) - for (int xx = 0; xx < 16; xx++) - { - auto send_pile = NetBlock->add_spatterpile(); - for (int i = 0; i < materials.size(); i++) - { - auto mat = materials[i]; - if (mat->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - send_spat->set_state((MatterState)mat->mat_state); - CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); - send_spat->set_amount(mat->amount[xx][yy]); - } + for (int yy = 0; yy < 16; yy++) + for (int xx = 0; xx < 16; xx++) + { + auto send_pile = NetBlock->add_spatterpile(); + for (int i = 0; i < materials.size(); i++) + { + auto mat = materials[i]; + if (mat->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + send_spat->set_state((MatterState)mat->mat_state); + CopyMat(send_spat->mutable_material(), mat->mat_type, mat->mat_index); + send_spat->set_amount(mat->amount[xx][yy]); + } #if DF_VERSION_INT > 34011 - for (int i = 0; i < items.size(); i++) - { - auto item = items[i]; - if (item->amount[xx][yy] == 0) - continue; - auto send_spat = send_pile->add_spatters(); - CopyMat(send_spat->mutable_material(), item->mattype, item->matindex); - send_spat->set_amount(item->amount[xx][yy]); - auto send_item = send_spat->mutable_item(); - send_item->set_mat_type(item->item_type); - send_item->set_mat_index(item->item_subtype); - } - int grassPercent = 0; - for (int i = 0; i < grasses.size(); i++) - { - auto grass = grasses[i]; - if (grass->amount[xx][yy] > grassPercent) - grassPercent = grass->amount[xx][yy]; - } - NetBlock->add_grass_percent(grassPercent); + for (int i = 0; i < items.size(); i++) + { + auto item = items[i]; + if (item->amount[xx][yy] == 0) + continue; + auto send_spat = send_pile->add_spatters(); + CopyMat(send_spat->mutable_material(), item->mattype, item->matindex); + send_spat->set_amount(item->amount[xx][yy]); + auto send_item = send_spat->mutable_item(); + send_item->set_mat_type(item->item_type); + send_item->set_mat_index(item->item_subtype); + } + int grassPercent = 0; + for (int i = 0; i < grasses.size(); i++) + { + auto grass = grasses[i]; + if (grass->amount[xx][yy] > grassPercent) + grassPercent = grass->amount[xx][yy]; + } + NetBlock->add_grass_percent(grassPercent); #endif - } + } } void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { - NetItem->set_id(DfItem->id); - NetItem->set_flags1(DfItem->flags.whole); - NetItem->set_flags2(DfItem->flags2.whole); - auto pos = NetItem->mutable_pos(); - pos->set_x(DfItem->pos.x); - pos->set_y(DfItem->pos.y); - pos->set_z(DfItem->pos.z); - auto mat = NetItem->mutable_material(); - mat->set_mat_index(DfItem->getMaterialIndex()); - mat->set_mat_type(DfItem->getMaterial()); - auto type = NetItem->mutable_type(); - type->set_mat_type(DfItem->getType()); - type->set_mat_index(DfItem->getSubtype()); - if (DfItem->getType() == item_type::BOX) - { - type->set_mat_index(DfItem->isBag()); - } - VIRTUAL_CAST_VAR(actual_item, df::item_actual, DfItem); - if (actual_item) - { - NetItem->set_stack_size(actual_item->stack_size); - } - VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); - if (constructed_item) - { - for (int i = 0; i < constructed_item->improvements.size(); i++) - { - auto improvement = constructed_item->improvements[i]; - if (!improvement || improvement->getType() != improvement_type::THREAD) - continue; - - auto improvement_thread = virtual_cast(improvement); - if (!improvement_thread || improvement_thread->dye.mat_type < 0) - continue; - - DFHack::MaterialInfo info; - if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) - continue; - - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } - else if (DfItem->getType() == item_type::THREAD) - { - auto thread = virtual_cast(DfItem); - if (thread && thread->dye_mat_type >= 0) - { - DFHack::MaterialInfo info; - if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } + NetItem->set_id(DfItem->id); + NetItem->set_flags1(DfItem->flags.whole); + NetItem->set_flags2(DfItem->flags2.whole); + auto pos = NetItem->mutable_pos(); + pos->set_x(DfItem->pos.x); + pos->set_y(DfItem->pos.y); + pos->set_z(DfItem->pos.z); + auto mat = NetItem->mutable_material(); + mat->set_mat_index(DfItem->getMaterialIndex()); + mat->set_mat_type(DfItem->getMaterial()); + auto type = NetItem->mutable_type(); + type->set_mat_type(DfItem->getType()); + type->set_mat_index(DfItem->getSubtype()); + if (DfItem->getType() == item_type::BOX) + { + type->set_mat_index(DfItem->isBag()); + } + VIRTUAL_CAST_VAR(actual_item, df::item_actual, DfItem); + if (actual_item) + { + NetItem->set_stack_size(actual_item->stack_size); + } + VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); + if (constructed_item) + { + for (int i = 0; i < constructed_item->improvements.size(); i++) + { + auto improvement = constructed_item->improvements[i]; + if (!improvement || improvement->getType() != improvement_type::THREAD) + continue; + + auto improvement_thread = virtual_cast(improvement); + if (!improvement_thread || improvement_thread->dye.mat_type < 0) + continue; + + DFHack::MaterialInfo info; + if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) + continue; + + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } + else if (DfItem->getType() == item_type::THREAD) + { + auto thread = virtual_cast(DfItem); + if (thread && thread->dye_mat_type >= 0) + { + DFHack::MaterialInfo info; + if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + } } void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { - NetBlock->set_map_x(DfBlock->map_pos.x); - NetBlock->set_map_y(DfBlock->map_pos.y); - NetBlock->set_map_z(DfBlock->map_pos.z); - for (int i = 0; i < DfBlock->items.size(); i++) - { - int id = DfBlock->items[i]; + NetBlock->set_map_x(DfBlock->map_pos.x); + NetBlock->set_map_y(DfBlock->map_pos.y); + NetBlock->set_map_z(DfBlock->map_pos.z); + for (int i = 0; i < DfBlock->items.size(); i++) + { + int id = DfBlock->items[i]; - auto item = df::item::find(id); - if (item) - CopyItem(NetBlock->add_items(), item); - } + auto item = df::item::find(id); + if (item) + CopyItem(NetBlock->add_items(), item); + } } static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) { - int x, y, z; - DFHack::Maps::getPosition(x, y, z); - out->set_map_x(x); - out->set_map_y(y); - MapExtras::MapCache MC; - int center_x = (in->min_x() + in->max_x()) / 2; - int center_y = (in->min_y() + in->max_y()) / 2; - - int NUMBER_OF_POINTS = ((in->max_x() - center_x + 1) * 2) * ((in->max_y() - center_y + 1) * 2); - int blocks_needed; - if (in->has_blocks_needed()) - blocks_needed = in->blocks_needed(); - else - blocks_needed = NUMBER_OF_POINTS*(in->max_z() - in->min_z()); - int blocks_sent = 0; - int min_x = in->min_x(); - int min_y = in->min_y(); - int max_x = in->max_x(); - int max_y = in->max_y(); - int min_z = in->min_z(); - int max_z = in->max_z(); - bool sentBuildings = false; //Always send all the buildings needed on the first block, and none on the rest. - //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); - for (int zz = max_z - 1; zz >= min_z; zz--) - { - // (di, dj) is a vector - direction in which we move right now - int di = 1; - int dj = 0; - // length of current segment - int segment_length = 1; - // current position (i, j) and how much of current segment we passed - int i = center_x; - int j = center_y; - int segment_passed = 0; - for (int k = 0; k < NUMBER_OF_POINTS; ++k) - { - if (blocks_sent >= blocks_needed) - break; - if (!(i < min_x || i >= max_x || j < min_y || j >= max_y)) - { - DFCoord pos = DFCoord(i, j, zz); - df::map_block * block = DFHack::Maps::getBlock(pos); - if (block != NULL) - { - int nonAir = 0; - for (int xxx = 0; xxx < 16; xxx++) - for (int yyy = 0; yyy < 16; yyy++) - { - if ((DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::None && - DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::Open) - || block->designation[xxx][yyy].bits.flow_size > 0 - || block->occupancy[xxx][yyy].bits.building > 0) - nonAir++; - } - if (nonAir > 0 || !sentBuildings) - { - bool tileChanged = IsTiletypeChanged(pos); - bool desChanged = IsDesignationChanged(pos); - bool spatterChanged = IsspatterChanged(pos); - bool buildingChanged = !sentBuildings; - bool itemsChanged = areItemsChanged(&block->items); - //bool bldChanged = IsBuildingChanged(pos); - RemoteFortressReader::MapBlock *net_block; - if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) - net_block = out->add_map_blocks(); - if (tileChanged) - { - CopyBlock(block, net_block, &MC, pos); - blocks_sent++; - } - if (desChanged) - CopyDesignation(block, net_block, &MC, pos); - if (buildingChanged) - { - CopyBuildings(DFCoord(min_x * 16, min_y * 16, min_z), DFCoord(max_x * 16, max_y * 16, max_z), net_block, &MC); - sentBuildings = true; - } - if (spatterChanged) - Copyspatters(block, net_block, &MC, pos); - if (itemsChanged) - CopyItems(block, net_block, &MC, pos); - } - } - } - - // make a step, add 'direction' vector (di, dj) to current position (i, j) - i += di; - j += dj; - ++segment_passed; - //System.out.println(i + " " + j); - - if (segment_passed == segment_length) - { - // done with current segment - segment_passed = 0; - - // 'rotate' directions - int buffer = di; - di = -dj; - dj = buffer; - - // increase segment length if necessary - if (dj == 0) { - ++segment_length; - } - } - } - } - MC.trash(); - return CR_OK; + int x, y, z; + DFHack::Maps::getPosition(x, y, z); + out->set_map_x(x); + out->set_map_y(y); + MapExtras::MapCache MC; + int center_x = (in->min_x() + in->max_x()) / 2; + int center_y = (in->min_y() + in->max_y()) / 2; + + int NUMBER_OF_POINTS = ((in->max_x() - center_x + 1) * 2) * ((in->max_y() - center_y + 1) * 2); + int blocks_needed; + if (in->has_blocks_needed()) + blocks_needed = in->blocks_needed(); + else + blocks_needed = NUMBER_OF_POINTS*(in->max_z() - in->min_z()); + int blocks_sent = 0; + int min_x = in->min_x(); + int min_y = in->min_y(); + int max_x = in->max_x(); + int max_y = in->max_y(); + int min_z = in->min_z(); + int max_z = in->max_z(); + bool sentBuildings = false; //Always send all the buildings needed on the first block, and none on the rest. + //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); + for (int zz = max_z - 1; zz >= min_z; zz--) + { + // (di, dj) is a vector - direction in which we move right now + int di = 1; + int dj = 0; + // length of current segment + int segment_length = 1; + // current position (i, j) and how much of current segment we passed + int i = center_x; + int j = center_y; + int segment_passed = 0; + for (int k = 0; k < NUMBER_OF_POINTS; ++k) + { + if (blocks_sent >= blocks_needed) + break; + if (!(i < min_x || i >= max_x || j < min_y || j >= max_y)) + { + DFCoord pos = DFCoord(i, j, zz); + df::map_block * block = DFHack::Maps::getBlock(pos); + if (block != NULL) + { + int nonAir = 0; + for (int xxx = 0; xxx < 16; xxx++) + for (int yyy = 0; yyy < 16; yyy++) + { + if ((DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::None && + DFHack::tileShapeBasic(DFHack::tileShape(block->tiletype[xxx][yyy])) != df::tiletype_shape_basic::Open) + || block->designation[xxx][yyy].bits.flow_size > 0 + || block->occupancy[xxx][yyy].bits.building > 0) + nonAir++; + } + if (nonAir > 0 || !sentBuildings) + { + bool tileChanged = IsTiletypeChanged(pos); + bool desChanged = IsDesignationChanged(pos); + bool spatterChanged = IsspatterChanged(pos); + bool buildingChanged = !sentBuildings; + bool itemsChanged = areItemsChanged(&block->items); + //bool bldChanged = IsBuildingChanged(pos); + RemoteFortressReader::MapBlock *net_block; + if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) + net_block = out->add_map_blocks(); + if (tileChanged) + { + CopyBlock(block, net_block, &MC, pos); + blocks_sent++; + } + if (desChanged) + CopyDesignation(block, net_block, &MC, pos); + if (buildingChanged) + { + CopyBuildings(DFCoord(min_x * 16, min_y * 16, min_z), DFCoord(max_x * 16, max_y * 16, max_z), net_block, &MC); + sentBuildings = true; + } + if (spatterChanged) + Copyspatters(block, net_block, &MC, pos); + if (itemsChanged) + CopyItems(block, net_block, &MC, pos); + } + } + } + + // make a step, add 'direction' vector (di, dj) to current position (i, j) + i += di; + j += dj; + ++segment_passed; + //System.out.println(i + " " + j); + + if (segment_passed == segment_length) + { + // done with current segment + segment_passed = 0; + + // 'rotate' directions + int buffer = di; + di = -dj; + dj = buffer; + + // increase segment length if necessary + if (dj == 0) { + ++segment_length; + } + } + } + } + MC.trash(); + return CR_OK; } static command_result GetTiletypeList(color_ostream &stream, const EmptyMessage *in, TiletypeList *out) { - int count = 0; - FOR_ENUM_ITEMS(tiletype, tt) - { - Tiletype * type = out->add_tiletype_list(); - type->set_id(tt); - type->set_name(ENUM_KEY_STR(tiletype, tt)); - const char * name = tileName(tt); - if (name != NULL && name[0] != 0) - type->set_caption(name); - type->set_shape(TranslateShape(tileShape(tt))); - type->set_special(TranslateSpecial(tileSpecial(tt))); - type->set_material(TranslateMaterial(tileMaterial(tt))); - type->set_variant(TranslateVariant(tileVariant(tt))); - type->set_direction(tileDirection(tt).getStr()); - count++; - } - return CR_OK; + int count = 0; + FOR_ENUM_ITEMS(tiletype, tt) + { + Tiletype * type = out->add_tiletype_list(); + type->set_id(tt); + type->set_name(ENUM_KEY_STR(tiletype, tt)); + const char * name = tileName(tt); + if (name != NULL && name[0] != 0) + type->set_caption(name); + type->set_shape(TranslateShape(tileShape(tt))); + type->set_special(TranslateSpecial(tileSpecial(tt))); + type->set_material(TranslateMaterial(tileMaterial(tt))); + type->set_variant(TranslateVariant(tileVariant(tt))); + type->set_direction(tileDirection(tt).getStr()); + count++; + } + return CR_OK; } static command_result GetPlantList(color_ostream &stream, const BlockRequest *in, PlantList *out) { - int min_x = in->min_x() / 3; - int min_y = in->min_y() / 3; - int min_z = in->min_z(); - int max_x = in->max_x() / 3; - int max_y = in->max_y() / 3; - int max_z = in->max_z(); + int min_x = in->min_x() / 3; + int min_y = in->min_y() / 3; + int min_z = in->min_z(); + int max_x = in->max_x() / 3; + int max_y = in->max_y() / 3; + int max_z = in->max_z(); #if DF_VERSION_INT < 40001 - //plants are gotten differently here + //plants are gotten differently here #else - for (int xx = min_x; xx < max_x; xx++) - for (int yy = min_y; yy < max_y; yy++) - { - if (xx < 0 || yy < 0 || xx >= world->map.x_count_block || yy >= world->map.y_count_block) - continue; - df::map_block_column * column = world->map.column_index[xx][yy]; - for (int i = 0; i < column->plants.size(); i++) - { - df::plant * plant = column->plants[i]; - if (!plant->tree_info) - { - if (plant->pos.z < min_z || plant->pos.z >= max_z) - continue; - if (plant->pos.x < in->min_x() * 16 || plant->pos.x >= in->max_x() * 16) - continue; - if (plant->pos.y < in->min_y() * 16 || plant->pos.y >= in->max_y() * 16) - continue; - } - else - { - if (plant->pos.z - plant->tree_info->roots_depth < min_z || plant->pos.z + plant->tree_info->body_height > max_z) - continue; - if (plant->pos.x - plant->tree_info->dim_x / 2 < in->min_x() * 16 || plant->pos.x + plant->tree_info->dim_x / 2 >= in->max_x() * 16) - continue; - if (plant->pos.y - plant->tree_info->dim_y / 2 < in->min_y() * 16 || plant->pos.y + plant->tree_info->dim_y / 2 >= in->max_y() * 16) - continue; - } - RemoteFortressReader::PlantDef * out_plant = out->add_plant_list(); - out_plant->set_index(plant->material); - out_plant->set_pos_x(plant->pos.x); - out_plant->set_pos_y(plant->pos.y); - out_plant->set_pos_z(plant->pos.z); - } - } + for (int xx = min_x; xx < max_x; xx++) + for (int yy = min_y; yy < max_y; yy++) + { + if (xx < 0 || yy < 0 || xx >= world->map.x_count_block || yy >= world->map.y_count_block) + continue; + df::map_block_column * column = world->map.column_index[xx][yy]; + for (int i = 0; i < column->plants.size(); i++) + { + df::plant * plant = column->plants[i]; + if (!plant->tree_info) + { + if (plant->pos.z < min_z || plant->pos.z >= max_z) + continue; + if (plant->pos.x < in->min_x() * 16 || plant->pos.x >= in->max_x() * 16) + continue; + if (plant->pos.y < in->min_y() * 16 || plant->pos.y >= in->max_y() * 16) + continue; + } + else + { + if (plant->pos.z - plant->tree_info->roots_depth < min_z || plant->pos.z + plant->tree_info->body_height > max_z) + continue; + if (plant->pos.x - plant->tree_info->dim_x / 2 < in->min_x() * 16 || plant->pos.x + plant->tree_info->dim_x / 2 >= in->max_x() * 16) + continue; + if (plant->pos.y - plant->tree_info->dim_y / 2 < in->min_y() * 16 || plant->pos.y + plant->tree_info->dim_y / 2 >= in->max_y() * 16) + continue; + } + RemoteFortressReader::PlantDef * out_plant = out->add_plant_list(); + out_plant->set_index(plant->material); + out_plant->set_pos_x(plant->pos.x); + out_plant->set_pos_y(plant->pos.y); + out_plant->set_pos_z(plant->pos.z); + } + } #endif - return CR_OK; + return CR_OK; } static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in, UnitList *out) { - return GetUnitListInside(stream, NULL, out); + return GetUnitListInside(stream, NULL, out); } static command_result GetUnitListInside(color_ostream &stream, const BlockRequest *in, UnitList *out) { - auto world = df::global::world; - for (int i = 0; i < world->units.all.size(); i++) - { - df::unit * unit = world->units.all[i]; - auto send_unit = out->add_creature_list(); - send_unit->set_id(unit->id); - send_unit->set_pos_x(unit->pos.x); - send_unit->set_pos_y(unit->pos.y); - send_unit->set_pos_z(unit->pos.z); - send_unit->mutable_race()->set_mat_type(unit->race); - send_unit->mutable_race()->set_mat_index(unit->caste); - if (in != NULL) - { - if (unit->pos.z < in->min_z() || unit->pos.z >= in->max_z()) - continue; - if (unit->pos.x < in->min_x() * 16 || unit->pos.x >= in->max_x() * 16) - continue; - if (unit->pos.y < in->min_y() * 16 || unit->pos.y >= in->max_y() * 16) - continue; - } - ConvertDfColor(Units::getProfessionColor(unit), send_unit->mutable_profession_color()); - send_unit->set_flags1(unit->flags1.whole); - send_unit->set_flags2(unit->flags2.whole); - send_unit->set_flags3(unit->flags3.whole); - send_unit->set_is_soldier(ENUM_ATTR(profession, military, unit->profession)); - auto size_info = send_unit->mutable_size_info(); - size_info->set_size_cur(unit->body.size_info.size_cur); - size_info->set_size_base(unit->body.size_info.size_base); - size_info->set_area_cur(unit->body.size_info.area_cur); - size_info->set_area_base(unit->body.size_info.area_base); - size_info->set_length_cur(unit->body.size_info.length_cur); - size_info->set_length_base(unit->body.size_info.length_base); - if (unit->name.has_name) - { - send_unit->set_name(DF2UTF(Translation::TranslateName(Units::getVisibleName(unit)))); - } - - auto appearance = send_unit->mutable_appearance(); - for (int j = 0; j < unit->appearance.body_modifiers.size(); j++) - appearance->add_body_modifiers(unit->appearance.body_modifiers[j]); - for (int j = 0; j < unit->appearance.bp_modifiers.size(); j++) - appearance->add_bp_modifiers(unit->appearance.bp_modifiers[j]); - for (int j = 0; j < unit->appearance.colors.size(); j++) - appearance->add_colors(unit->appearance.colors[j]); - appearance->set_size_modifier(unit->appearance.size_modifier); - - send_unit->set_profession_id(unit->profession); - - std::vector pvec; - - if (Units::getNoblePositions(&pvec, unit)) - { - for (int j = 0; j < pvec.size(); j++) - { - auto noble_positon = pvec[j]; - send_unit->add_noble_positions(noble_positon.position->code); - } - } - - send_unit->set_rider_id(unit->relationship_ids[df::unit_relationship_type::RiderMount]); - - auto creatureRaw = world->raws.creatures.all[unit->race]; - auto casteRaw = creatureRaw->caste[unit->caste]; - - for (int j = 0; j < unit->appearance.tissue_style_type.size(); j++) - { - auto type = unit->appearance.tissue_style_type[j]; - if (type < 0) - continue; - int style_raw_index = binsearch_index(casteRaw->tissue_styles, &df::tissue_style_raw::id, type); - auto styleRaw = casteRaw->tissue_styles[style_raw_index]; - if (styleRaw->token == "HAIR") - { - auto send_style = appearance->mutable_hair(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "BEARD") - { - auto send_style = appearance->mutable_beard(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "MOUSTACHE") - { - auto send_style = appearance->mutable_moustache(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - else if (styleRaw->token == "SIDEBURNS") - { - auto send_style = appearance->mutable_sideburns(); - send_style->set_length(unit->appearance.tissue_length[j]); - send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); - } - } - - for (int j = 0; j < unit->inventory.size(); j++) - { - auto inventory_item = unit->inventory[j]; - auto sent_item = send_unit->add_inventory(); - sent_item->set_mode((InventoryMode)inventory_item->mode); - CopyItem(sent_item->mutable_item(), inventory_item->item); - } - - if (unit->flags1.bits.projectile) - { - for (auto proj = world->proj_list.next; proj != NULL; proj = proj->next) - { - STRICT_VIRTUAL_CAST_VAR(item, df::proj_unitst, proj->item); - if (item == NULL) - continue; - if (item->unit != unit) - continue; - send_unit->set_subpos_x(item->pos_x / 100000.0); - send_unit->set_subpos_y(item->pos_y / 100000.0); - send_unit->set_subpos_z(item->pos_z / 140000.0); - } - } - } - return CR_OK; + auto world = df::global::world; + for (int i = 0; i < world->units.all.size(); i++) + { + df::unit * unit = world->units.all[i]; + auto send_unit = out->add_creature_list(); + send_unit->set_id(unit->id); + send_unit->set_pos_x(unit->pos.x); + send_unit->set_pos_y(unit->pos.y); + send_unit->set_pos_z(unit->pos.z); + send_unit->mutable_race()->set_mat_type(unit->race); + send_unit->mutable_race()->set_mat_index(unit->caste); + if (in != NULL) + { + if (unit->pos.z < in->min_z() || unit->pos.z >= in->max_z()) + continue; + if (unit->pos.x < in->min_x() * 16 || unit->pos.x >= in->max_x() * 16) + continue; + if (unit->pos.y < in->min_y() * 16 || unit->pos.y >= in->max_y() * 16) + continue; + } + ConvertDfColor(Units::getProfessionColor(unit), send_unit->mutable_profession_color()); + send_unit->set_flags1(unit->flags1.whole); + send_unit->set_flags2(unit->flags2.whole); + send_unit->set_flags3(unit->flags3.whole); + send_unit->set_is_soldier(ENUM_ATTR(profession, military, unit->profession)); + auto size_info = send_unit->mutable_size_info(); + size_info->set_size_cur(unit->body.size_info.size_cur); + size_info->set_size_base(unit->body.size_info.size_base); + size_info->set_area_cur(unit->body.size_info.area_cur); + size_info->set_area_base(unit->body.size_info.area_base); + size_info->set_length_cur(unit->body.size_info.length_cur); + size_info->set_length_base(unit->body.size_info.length_base); + if (unit->name.has_name) + { + send_unit->set_name(DF2UTF(Translation::TranslateName(Units::getVisibleName(unit)))); + } + + auto appearance = send_unit->mutable_appearance(); + for (int j = 0; j < unit->appearance.body_modifiers.size(); j++) + appearance->add_body_modifiers(unit->appearance.body_modifiers[j]); + for (int j = 0; j < unit->appearance.bp_modifiers.size(); j++) + appearance->add_bp_modifiers(unit->appearance.bp_modifiers[j]); + for (int j = 0; j < unit->appearance.colors.size(); j++) + appearance->add_colors(unit->appearance.colors[j]); + appearance->set_size_modifier(unit->appearance.size_modifier); + + send_unit->set_profession_id(unit->profession); + + std::vector pvec; + + if (Units::getNoblePositions(&pvec, unit)) + { + for (int j = 0; j < pvec.size(); j++) + { + auto noble_positon = pvec[j]; + send_unit->add_noble_positions(noble_positon.position->code); + } + } + + send_unit->set_rider_id(unit->relationship_ids[df::unit_relationship_type::RiderMount]); + + auto creatureRaw = world->raws.creatures.all[unit->race]; + auto casteRaw = creatureRaw->caste[unit->caste]; + + for (int j = 0; j < unit->appearance.tissue_style_type.size(); j++) + { + auto type = unit->appearance.tissue_style_type[j]; + if (type < 0) + continue; + int style_raw_index = binsearch_index(casteRaw->tissue_styles, &df::tissue_style_raw::id, type); + auto styleRaw = casteRaw->tissue_styles[style_raw_index]; + if (styleRaw->token == "HAIR") + { + auto send_style = appearance->mutable_hair(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "BEARD") + { + auto send_style = appearance->mutable_beard(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "MOUSTACHE") + { + auto send_style = appearance->mutable_moustache(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + else if (styleRaw->token == "SIDEBURNS") + { + auto send_style = appearance->mutable_sideburns(); + send_style->set_length(unit->appearance.tissue_length[j]); + send_style->set_style((HairStyle)unit->appearance.tissue_style[j]); + } + } + + for (int j = 0; j < unit->inventory.size(); j++) + { + auto inventory_item = unit->inventory[j]; + auto sent_item = send_unit->add_inventory(); + sent_item->set_mode((InventoryMode)inventory_item->mode); + CopyItem(sent_item->mutable_item(), inventory_item->item); + } + + if (unit->flags1.bits.projectile) + { + for (auto proj = world->proj_list.next; proj != NULL; proj = proj->next) + { + STRICT_VIRTUAL_CAST_VAR(item, df::proj_unitst, proj->item); + if (item == NULL) + continue; + if (item->unit != unit) + continue; + send_unit->set_subpos_x(item->pos_x / 100000.0); + send_unit->set_subpos_y(item->pos_y / 100000.0); + send_unit->set_subpos_z(item->pos_z / 140000.0); + } + } + } + return CR_OK; } static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in, ViewInfo *out) { - int x, y, z, w, h, cx, cy, cz; - Gui::getWindowSize(w, h); - Gui::getViewCoords(x, y, z); - Gui::getCursorCoords(cx, cy, cz); + int x, y, z, w, h, cx, cy, cz; + Gui::getWindowSize(w, h); + Gui::getViewCoords(x, y, z); + Gui::getCursorCoords(cx, cy, cz); #if DF_VERSION_INT > 34011 - auto embark = Gui::getViewscreenByType(0); - if (embark) - { - df::embark_location location = embark->location; - df::world_data * data = df::global::world->world_data; - if (data && data->region_map) - { - z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; - } - } + auto embark = Gui::getViewscreenByType(0); + if (embark) + { + df::embark_location location = embark->location; + df::world_data * data = df::global::world->world_data; + if (data && data->region_map) + { + z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; + } + } #endif - out->set_view_pos_x(x); - out->set_view_pos_y(y); - out->set_view_pos_z(z); - out->set_view_size_x(w); - out->set_view_size_y(h); - out->set_cursor_pos_x(cx); - out->set_cursor_pos_y(cy); - out->set_cursor_pos_z(cz); - - if (gamemode && *gamemode == GameMode::ADVENTURE) - out->set_follow_unit_id(world->units.active[0]->id); - else - out->set_follow_unit_id(ui->follow_unit); - out->set_follow_item_id(ui->follow_item); - return CR_OK; + out->set_view_pos_x(x); + out->set_view_pos_y(y); + out->set_view_pos_z(z); + out->set_view_size_x(w); + out->set_view_size_y(h); + out->set_cursor_pos_x(cx); + out->set_cursor_pos_y(cy); + out->set_cursor_pos_z(cz); + + if (gamemode && *gamemode == GameMode::ADVENTURE) + out->set_follow_unit_id(world->units.active[0]->id); + else + out->set_follow_unit_id(ui->follow_unit); + out->set_follow_item_id(ui->follow_item); + return CR_OK; } static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, MapInfo *out) { - if (!Maps::IsValid()) - return CR_FAILURE; - uint32_t size_x, size_y, size_z; - int32_t pos_x, pos_y, pos_z; - Maps::getSize(size_x, size_y, size_z); - Maps::getPosition(pos_x, pos_y, pos_z); - out->set_block_size_x(size_x); - out->set_block_size_y(size_y); - out->set_block_size_z(size_z); - out->set_block_pos_x(pos_x); - out->set_block_pos_y(pos_y); - out->set_block_pos_z(pos_z); - out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); - out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); - out->set_save_name(df::global::world->cur_savegame.save_dir); - return CR_OK; + if (!Maps::IsValid()) + return CR_FAILURE; + uint32_t size_x, size_y, size_z; + int32_t pos_x, pos_y, pos_z; + Maps::getSize(size_x, size_y, size_z); + Maps::getPosition(pos_x, pos_y, pos_z); + out->set_block_size_x(size_x); + out->set_block_size_y(size_y); + out->set_block_size_z(size_z); + out->set_block_pos_x(pos_x); + out->set_block_pos_y(pos_y); + out->set_block_pos_z(pos_z); + out->set_world_name(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, false))); + out->set_world_name_english(DF2UTF(Translation::TranslateName(&df::global::world->world_data->name, true))); + out->set_save_name(df::global::world->cur_savegame.save_dir); + return CR_OK; } DFCoord GetMapCenter() { - DFCoord output; + DFCoord output; #if DF_VERSION_INT > 34011 - auto embark = Gui::getViewscreenByType(0); - if (embark) - { - df::embark_location location = embark->location; - output.x = (location.region_pos.x * 16) + 8; - output.y = (location.region_pos.y * 16) + 8; - output.z = 100; - df::world_data * data = df::global::world->world_data; - if (data && data->region_map) - { - output.z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; - } - } - else + auto embark = Gui::getViewscreenByType(0); + if (embark) + { + df::embark_location location = embark->location; + output.x = (location.region_pos.x * 16) + 8; + output.y = (location.region_pos.y * 16) + 8; + output.z = 100; + df::world_data * data = df::global::world->world_data; + if (data && data->region_map) + { + output.z = data->region_map[location.region_pos.x][location.region_pos.y].elevation; + } + } + else #endif - if (Maps::IsValid()) - { - int x, y, z; - Maps::getPosition(x, y, z); - output = DFCoord(x, y, z); - } + if (Maps::IsValid()) + { + int x, y, z; + Maps::getPosition(x, y, z); + output = DFCoord(x, y, z); + } #if DF_VERSION_INT > 34011 - else - for (int i = 0; i < df::global::world->armies.all.size(); i++) - { - df::army * thisArmy = df::global::world->armies.all[i]; - if (thisArmy->flags.is_set(df::enums::army_flags::player)) - { - output.x = (thisArmy->pos.x / 3) - 1; - output.y = (thisArmy->pos.y / 3) - 1; - output.z = thisArmy->pos.z; - } - } + else + for (int i = 0; i < df::global::world->armies.all.size(); i++) + { + df::army * thisArmy = df::global::world->armies.all[i]; + if (thisArmy->flags.is_set(df::enums::army_flags::player)) + { + output.x = (thisArmy->pos.x / 3) - 1; + output.y = (thisArmy->pos.y / 3) - 1; + output.z = thisArmy->pos.z; + } + } #endif - return output; + return output; } static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - if (!data->region_map) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); - auto poles = data->flip_latitude; + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); + auto poles = data->flip_latitude; #if DF_VERSION_INT > 34011 - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - for (int yy = 0; yy < height; yy++) - for (int xx = 0; xx < width; xx++) - { - df::region_map_entry * map_entry = &data->region_map[xx][yy]; - df::world_region * region = data->regions[map_entry->region_id]; - out->add_elevation(map_entry->elevation); - out->add_rainfall(map_entry->rainfall); - out->add_vegetation(map_entry->vegetation); - out->add_temperature(map_entry->temperature); - out->add_evilness(map_entry->evilness); - out->add_drainage(map_entry->drainage); - out->add_volcanism(map_entry->volcanism); - out->add_savagery(map_entry->savagery); - out->add_salinity(map_entry->salinity); - auto clouds = out->add_clouds(); + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + out->add_elevation(map_entry->elevation); + out->add_rainfall(map_entry->rainfall); + out->add_vegetation(map_entry->vegetation); + out->add_temperature(map_entry->temperature); + out->add_evilness(map_entry->evilness); + out->add_drainage(map_entry->drainage); + out->add_volcanism(map_entry->volcanism); + out->add_savagery(map_entry->savagery); + out->add_salinity(map_entry->salinity); + auto clouds = out->add_clouds(); #if DF_VERSION_INT > 34011 - clouds->set_cirrus(map_entry->clouds.bits.cirrus); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); #else - clouds->set_cirrus(map_entry->clouds.bits.striped); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); + clouds->set_cirrus(map_entry->clouds.bits.striped); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); #endif - if (region->type == world_region_type::Lake) - { - out->add_water_elevation(region->lake_surface); - } - else - out->add_water_elevation(99); - } - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); - - - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + if (region->type == world_region_type::Lake) + { + out->add_water_elevation(region->lake_surface); + } + else + out->add_water_elevation(99); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); + + + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static void SetRegionTile(RegionTile * out, df::region_map_entry * e1) { - df::world_region * region = df::world_region::find(e1->region_id); - df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); - out->set_rainfall(e1->rainfall); - out->set_vegetation(e1->vegetation); - out->set_temperature(e1->temperature); - out->set_evilness(e1->evilness); - out->set_drainage(e1->drainage); - out->set_volcanism(e1->volcanism); - out->set_savagery(e1->savagery); - out->set_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->set_water_elevation(region->lake_surface); - else - out->set_water_elevation(99); - - int topLayer = 0; - for (int i = 0; i < geoBiome->layers.size(); i++) - { - auto layer = geoBiome->layers[i]; - if (layer->top_height == 0) - { - topLayer = layer->mat_index; - } - if (layer->type != geo_layer_type::SOIL - && layer->type != geo_layer_type::SOIL_OCEAN - && layer->type != geo_layer_type::SOIL_SAND) - { - auto mat = out->add_stone_materials(); - mat->set_mat_index(layer->mat_index); - mat->set_mat_type(0); - } - } - auto surfaceMat = out->mutable_surface_material(); - surfaceMat->set_mat_index(topLayer); - surfaceMat->set_mat_type(0); - - for (int i = 0; i < region->population.size(); i++) - { - auto pop = region->population[i]; - if (pop->type == world_population_type::Grass) - { - auto plantMat = out->add_plant_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - else if (pop->type == world_population_type::Tree) - { - auto plantMat = out->add_tree_materials(); - - plantMat->set_mat_index(pop->plant); - plantMat->set_mat_type(419); - } - } + df::world_region * region = df::world_region::find(e1->region_id); + df::world_geo_biome * geoBiome = df::world_geo_biome::find(e1->geo_index); + out->set_rainfall(e1->rainfall); + out->set_vegetation(e1->vegetation); + out->set_temperature(e1->temperature); + out->set_evilness(e1->evilness); + out->set_drainage(e1->drainage); + out->set_volcanism(e1->volcanism); + out->set_savagery(e1->savagery); + out->set_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->set_water_elevation(region->lake_surface); + else + out->set_water_elevation(99); + + int topLayer = 0; + for (int i = 0; i < geoBiome->layers.size(); i++) + { + auto layer = geoBiome->layers[i]; + if (layer->top_height == 0) + { + topLayer = layer->mat_index; + } + if (layer->type != geo_layer_type::SOIL + && layer->type != geo_layer_type::SOIL_OCEAN + && layer->type != geo_layer_type::SOIL_SAND) + { + auto mat = out->add_stone_materials(); + mat->set_mat_index(layer->mat_index); + mat->set_mat_type(0); + } + } + auto surfaceMat = out->mutable_surface_material(); + surfaceMat->set_mat_index(topLayer); + surfaceMat->set_mat_type(0); + + for (int i = 0; i < region->population.size(); i++) + { + auto pop = region->population[i]; + if (pop->type == world_population_type::Grass) + { + auto plantMat = out->add_plant_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + else if (pop->type == world_population_type::Tree) + { + auto plantMat = out->add_tree_materials(); + + plantMat->set_mat_index(pop->plant); + plantMat->set_mat_type(419); + } + } #if DF_VERSION_INT >= 43005 - out->set_snow(e1->snowfall); + out->set_snow(e1->snowfall); #endif } static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out) { - if (!df::global::world->world_data) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - if (!data->region_map) - { - out->set_world_width(0); - out->set_world_height(0); - return CR_FAILURE; - } - int width = data->world_width; - int height = data->world_height; - out->set_world_width(width); - out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); + if (!df::global::world->world_data) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + if (!data->region_map) + { + out->set_world_width(0); + out->set_world_height(0); + return CR_FAILURE; + } + int width = data->world_width; + int height = data->world_height; + out->set_world_width(width); + out->set_world_height(height); + out->set_name(Translation::TranslateName(&(data->name), false)); + out->set_name_english(Translation::TranslateName(&(data->name), true)); #if DF_VERSION_INT > 34011 - auto poles = data->flip_latitude; - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + auto poles = data->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - for (int yy = 0; yy < height; yy++) - for (int xx = 0; xx < width; xx++) - { - df::region_map_entry * map_entry = &data->region_map[xx][yy]; - df::world_region * region = data->regions[map_entry->region_id]; - - auto regionTile = out->add_region_tiles(); - regionTile->set_elevation(map_entry->elevation); - SetRegionTile(regionTile, map_entry); - auto clouds = out->add_clouds(); + for (int yy = 0; yy < height; yy++) + for (int xx = 0; xx < width; xx++) + { + df::region_map_entry * map_entry = &data->region_map[xx][yy]; + df::world_region * region = data->regions[map_entry->region_id]; + + auto regionTile = out->add_region_tiles(); + regionTile->set_elevation(map_entry->elevation); + SetRegionTile(regionTile, map_entry); + auto clouds = out->add_clouds(); #if DF_VERSION_INT > 34011 - clouds->set_cirrus(map_entry->clouds.bits.cirrus); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); + clouds->set_cirrus(map_entry->clouds.bits.cirrus); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.cumulus); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_front((RemoteFortressReader::FrontType)map_entry->clouds.bits.front); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.stratus); #else - clouds->set_cirrus(map_entry->clouds.bits.striped); - clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); - clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); - clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); + clouds->set_cirrus(map_entry->clouds.bits.striped); + clouds->set_cumulus((RemoteFortressReader::CumulusType)map_entry->clouds.bits.density); + clouds->set_fog((RemoteFortressReader::FogType)map_entry->clouds.bits.fog); + clouds->set_stratus((RemoteFortressReader::StratusType)map_entry->clouds.bits.darkness); #endif - } - DFCoord pos = GetMapCenter(); - out->set_center_x(pos.x); - out->set_center_y(pos.y); - out->set_center_z(pos.z); + } + DFCoord pos = GetMapCenter(); + out->set_center_x(pos.x); + out->set_center_y(pos.y); + out->set_center_z(pos.z); - out->set_cur_year(World::ReadCurrentYear()); - out->set_cur_year_tick(World::ReadCurrentTick()); - return CR_OK; + out->set_cur_year(World::ReadCurrentYear()); + out->set_cur_year_tick(World::ReadCurrentTick()); + return CR_OK; } static void AddRegionTiles(WorldMap * out, df::region_map_entry * e1, df::world_data * worldData) { - df::world_region * region = worldData->regions[e1->region_id]; - out->add_rainfall(e1->rainfall); - out->add_vegetation(e1->vegetation); - out->add_temperature(e1->temperature); - out->add_evilness(e1->evilness); - out->add_drainage(e1->drainage); - out->add_volcanism(e1->volcanism); - out->add_savagery(e1->savagery); - out->add_salinity(e1->salinity); - if (region->type == world_region_type::Lake) - out->add_water_elevation(region->lake_surface); - else - out->add_water_elevation(99); + df::world_region * region = worldData->regions[e1->region_id]; + out->add_rainfall(e1->rainfall); + out->add_vegetation(e1->vegetation); + out->add_temperature(e1->temperature); + out->add_evilness(e1->evilness); + out->add_drainage(e1->drainage); + out->add_volcanism(e1->volcanism); + out->add_savagery(e1->savagery); + out->add_salinity(e1->salinity); + if (region->type == world_region_type::Lake) + out->add_water_elevation(region->lake_surface); + else + out->add_water_elevation(99); } static void AddRegionTiles(WorldMap * out, df::coord2d pos, df::world_data * worldData) { - if (pos.x < 0) - pos.x = 0; - if (pos.y < 0) - pos.y = 0; - if (pos.x >= worldData->world_width) - pos.x = worldData->world_width - 1; - if (pos.y >= worldData->world_height) - pos.y = worldData->world_height - 1; - AddRegionTiles(out, &worldData->region_map[pos.x][pos.y], worldData); + if (pos.x < 0) + pos.x = 0; + if (pos.y < 0) + pos.y = 0; + if (pos.x >= worldData->world_width) + pos.x = worldData->world_width - 1; + if (pos.y >= worldData->world_height) + pos.y = worldData->world_height - 1; + AddRegionTiles(out, &worldData->region_map[pos.x][pos.y], worldData); } static void AddRegionTiles(RegionTile * out, df::coord2d pos, df::world_data * worldData) { - if (pos.x < 0) - pos.x = 0; - if (pos.y < 0) - pos.y = 0; - if (pos.x >= worldData->world_width) - pos.x = worldData->world_width - 1; - if (pos.y >= worldData->world_height) - pos.y = worldData->world_height - 1; - SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); + if (pos.x < 0) + pos.x = 0; + if (pos.y < 0) + pos.y = 0; + if (pos.x >= worldData->world_width) + pos.x = worldData->world_width - 1; + if (pos.y >= worldData->world_height) + pos.y = worldData->world_height - 1; + SetRegionTile(out, &worldData->region_map[pos.x][pos.y]); } static df::coord2d ShiftCoords(df::coord2d source, int direction) { - switch (direction) - { - case 1: - return df::coord2d(source.x - 1, source.y + 1); - case 2: - return df::coord2d(source.x, source.y + 1); - case 3: - return df::coord2d(source.x + 1, source.y + 1); - case 4: - return df::coord2d(source.x - 1, source.y); - case 5: - return source; - case 6: - return df::coord2d(source.x + 1, source.y); - case 7: - return df::coord2d(source.x - 1, source.y - 1); - case 8: - return df::coord2d(source.x, source.y - 1); - case 9: - return df::coord2d(source.x + 1, source.y - 1); - default: - return source; - } + switch (direction) + { + case 1: + return df::coord2d(source.x - 1, source.y + 1); + case 2: + return df::coord2d(source.x, source.y + 1); + case 3: + return df::coord2d(source.x + 1, source.y + 1); + case 4: + return df::coord2d(source.x - 1, source.y); + case 5: + return source; + case 6: + return df::coord2d(source.x + 1, source.y); + case 7: + return df::coord2d(source.x - 1, source.y - 1); + case 8: + return df::coord2d(source.x, source.y - 1); + case 9: + return df::coord2d(source.x + 1, source.y - 1); + default: + return source; + } } static void CopyLocalMap(df::world_data * worldData, df::world_region_details* worldRegionDetails, WorldMap * out) { - int pos_x = worldRegionDetails->pos.x; - int pos_y = worldRegionDetails->pos.y; - out->set_map_x(pos_x); - out->set_map_y(pos_y); - out->set_world_width(17); - out->set_world_height(17); - char name[256]; - sprintf(name, "Region %d, %d", pos_x, pos_y); - out->set_name_english(name); - out->set_name(name); + int pos_x = worldRegionDetails->pos.x; + int pos_y = worldRegionDetails->pos.y; + out->set_map_x(pos_x); + out->set_map_y(pos_y); + out->set_world_width(17); + out->set_world_height(17); + char name[256]; + sprintf(name, "Region %d, %d", pos_x, pos_y); + out->set_name_english(name); + out->set_name(name); #if DF_VERSION_INT > 34011 - auto poles = worldData->flip_latitude; - switch (poles) - { - case df::world_data::None: - out->set_world_poles(WorldPoles::NO_POLES); - break; - case df::world_data::North: - out->set_world_poles(WorldPoles::NORTH_POLE); - break; - case df::world_data::South: - out->set_world_poles(WorldPoles::SOUTH_POLE); - break; - case df::world_data::Both: - out->set_world_poles(WorldPoles::BOTH_POLES); - break; - default: - break; - } + auto poles = worldData->flip_latitude; + switch (poles) + { + case df::world_data::None: + out->set_world_poles(WorldPoles::NO_POLES); + break; + case df::world_data::North: + out->set_world_poles(WorldPoles::NORTH_POLE); + break; + case df::world_data::South: + out->set_world_poles(WorldPoles::SOUTH_POLE); + break; + case df::world_data::Both: + out->set_world_poles(WorldPoles::BOTH_POLES); + break; + default: + break; + } #else - out->set_world_poles(WorldPoles::NO_POLES); + out->set_world_poles(WorldPoles::NO_POLES); #endif - df::world_region_details * south = NULL; - df::world_region_details * east = NULL; - df::world_region_details * southEast = NULL; - - for (int i = 0; i < worldData->region_details.size(); i++) - { - auto region = worldData->region_details[i]; - if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) - southEast = region; - else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) - east = region; - else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) - south = region; - } - - for (int yy = 0; yy < 17; yy++) - for (int xx = 0; xx < 17; xx++) - { - //This is because the bottom row doesn't line up. - if (xx == 16 && yy == 16 && southEast != NULL) - { - out->add_elevation(southEast->elevation[0][0]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); - } - else if (xx == 16 && east != NULL) - { - out->add_elevation(east->elevation[0][yy]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); - } - else if (yy == 16 && south != NULL) - { - out->add_elevation(south->elevation[xx][0]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); - } - else - { - out->add_elevation(worldRegionDetails->elevation[xx][yy]); - AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); - } - - if (xx == 16 || yy == 16) - { - out->add_river_tiles(); - } - else - { - auto riverTile = out->add_river_tiles(); - auto east = riverTile->mutable_east(); - auto north = riverTile->mutable_north(); - auto south = riverTile->mutable_south(); - auto west = riverTile->mutable_west(); - - north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); - north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); - north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); - north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); - - south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); - south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); - south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); - south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); - - west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); - west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); - west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); - west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); - - east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); - east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); - east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); - east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); - } - } + df::world_region_details * south = NULL; + df::world_region_details * east = NULL; + df::world_region_details * southEast = NULL; + + for (int i = 0; i < worldData->region_details.size(); i++) + { + auto region = worldData->region_details[i]; + if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) + southEast = region; + else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) + east = region; + else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) + south = region; + } + + for (int yy = 0; yy < 17; yy++) + for (int xx = 0; xx < 17; xx++) + { + //This is because the bottom row doesn't line up. + if (xx == 16 && yy == 16 && southEast != NULL) + { + out->add_elevation(southEast->elevation[0][0]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); + } + else if (xx == 16 && east != NULL) + { + out->add_elevation(east->elevation[0][yy]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); + } + else if (yy == 16 && south != NULL) + { + out->add_elevation(south->elevation[xx][0]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); + } + else + { + out->add_elevation(worldRegionDetails->elevation[xx][yy]); + AddRegionTiles(out, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); + } + + if (xx == 16 || yy == 16) + { + out->add_river_tiles(); + } + else + { + auto riverTile = out->add_river_tiles(); + auto east = riverTile->mutable_east(); + auto north = riverTile->mutable_north(); + auto south = riverTile->mutable_south(); + auto west = riverTile->mutable_west(); + + north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); + north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); + north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); + north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); + + south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); + south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); + south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); + south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); + + west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); + west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); + west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); + west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); + + east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); + east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); + east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); + east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + } + } } static void CopyLocalMap(df::world_data * worldData, df::world_region_details* worldRegionDetails, RegionMap * out) { - int pos_x = worldRegionDetails->pos.x; - int pos_y = worldRegionDetails->pos.y; - out->set_map_x(pos_x); - out->set_map_y(pos_y); - char name[256]; - sprintf(name, "Region %d, %d", pos_x, pos_y); - out->set_name_english(name); - out->set_name(name); - - - df::world_region_details * south = NULL; - df::world_region_details * east = NULL; - df::world_region_details * southEast = NULL; - - for (int i = 0; i < worldData->region_details.size(); i++) - { - auto region = worldData->region_details[i]; - if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) - southEast = region; - else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) - east = region; - else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) - south = region; - } - - RegionTile* outputTiles[17][17]; - - for (int yy = 0; yy < 17; yy++) - for (int xx = 0; xx < 17; xx++) - { - auto tile = out->add_tiles(); - outputTiles[xx][yy] = tile; - //This is because the bottom row doesn't line up. - if (xx == 16 && yy == 16 && southEast != NULL) - { - tile->set_elevation(southEast->elevation[0][0]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); - } - else if (xx == 16 && east != NULL) - { - tile->set_elevation(east->elevation[0][yy]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); - } - else if (yy == 16 && south != NULL) - { - tile->set_elevation(south->elevation[xx][0]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); - } - else - { - tile->set_elevation(worldRegionDetails->elevation[xx][yy]); - AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); - } - - auto riverTile = tile->mutable_river_tiles(); - auto east = riverTile->mutable_east(); - auto north = riverTile->mutable_north(); - auto south = riverTile->mutable_south(); - auto west = riverTile->mutable_west(); - - if (xx < 16) - { - north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); - north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); - north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); - north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); - } - else - { - north->set_active(0); - north->set_elevation(100); - north->set_min_pos(-30000); - north->set_max_pos(-30000); - } - - if (yy < 16 && xx < 16) - { - south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); - south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); - south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); - south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); - } - else - { - south->set_active(0); - south->set_elevation(100); - south->set_min_pos(-30000); - south->set_max_pos(-30000); - } - - if (yy < 16) - { - west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); - west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); - west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); - west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); - } - else - { - west->set_active(0); - west->set_elevation(100); - west->set_min_pos(-30000); - west->set_max_pos(-30000); - } - - if (xx < 16 && yy < 16) - { - east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); - east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); - east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); - east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); - } - else - { - east->set_active(0); - east->set_elevation(100); - east->set_min_pos(-30000); - east->set_max_pos(-30000); - } - } - - auto regionMap = worldData->region_map[pos_x][pos_y]; - - for (int i = 0; i < worldData->sites.size(); i++) - { - df::world_site* site = worldData->sites[i]; - if (!site) - continue; - - int region_min_x = pos_x * 16; - int region_min_y = pos_y * 16; - - if ((site->global_min_x >(region_min_x + 16)) || - (site->global_min_y > (region_min_y + 16)) || - (site->global_max_x < (region_min_x)) || - (site->global_max_y < (region_min_y))) - continue; - - if (site->realization == NULL) - continue; - - auto realization = site->realization; - for (int site_x = 0; site_x < 17; site_x++) - for (int site_y = 0; site_y < 17; site_y++) - { - int region_x = site->global_min_x - region_min_x + site_x; - int region_y = site->global_min_y - region_min_y + site_y; - - if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) - continue; - - for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) - { - auto in_building = realization->building_map[site_x][site_y].buildings[j]; - auto out_building = outputTiles[region_x][region_y]->add_buildings(); - - out_building->set_id(in_building->id); + int pos_x = worldRegionDetails->pos.x; + int pos_y = worldRegionDetails->pos.y; + out->set_map_x(pos_x); + out->set_map_y(pos_y); + char name[256]; + sprintf(name, "Region %d, %d", pos_x, pos_y); + out->set_name_english(name); + out->set_name(name); + + + df::world_region_details * south = NULL; + df::world_region_details * east = NULL; + df::world_region_details * southEast = NULL; + + for (int i = 0; i < worldData->region_details.size(); i++) + { + auto region = worldData->region_details[i]; + if (region->pos.x == pos_x + 1 && region->pos.y == pos_y + 1) + southEast = region; + else if (region->pos.x == pos_x + 1 && region->pos.y == pos_y) + east = region; + else if (region->pos.x == pos_x && region->pos.y == pos_y + 1) + south = region; + } + + RegionTile* outputTiles[17][17]; + + for (int yy = 0; yy < 17; yy++) + for (int xx = 0; xx < 17; xx++) + { + auto tile = out->add_tiles(); + outputTiles[xx][yy] = tile; + //This is because the bottom row doesn't line up. + if (xx == 16 && yy == 16 && southEast != NULL) + { + tile->set_elevation(southEast->elevation[0][0]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y + 1), (southEast->biome[0][0])), worldData); + } + else if (xx == 16 && east != NULL) + { + tile->set_elevation(east->elevation[0][yy]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x + 1, pos_y), (east->biome[0][yy])), worldData); + } + else if (yy == 16 && south != NULL) + { + tile->set_elevation(south->elevation[xx][0]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y + 1), (south->biome[xx][0])), worldData); + } + else + { + tile->set_elevation(worldRegionDetails->elevation[xx][yy]); + AddRegionTiles(tile, ShiftCoords(df::coord2d(pos_x, pos_y), (worldRegionDetails->biome[xx][yy])), worldData); + } + + auto riverTile = tile->mutable_river_tiles(); + auto east = riverTile->mutable_east(); + auto north = riverTile->mutable_north(); + auto south = riverTile->mutable_south(); + auto west = riverTile->mutable_west(); + + if (xx < 16) + { + north->set_active(worldRegionDetails->rivers_vertical.active[xx][yy]); + north->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy]); + north->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy]); + north->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy]); + } + else + { + north->set_active(0); + north->set_elevation(100); + north->set_min_pos(-30000); + north->set_max_pos(-30000); + } + + if (yy < 16 && xx < 16) + { + south->set_active(worldRegionDetails->rivers_vertical.active[xx][yy + 1]); + south->set_elevation(worldRegionDetails->rivers_vertical.elevation[xx][yy + 1]); + south->set_min_pos(worldRegionDetails->rivers_vertical.x_min[xx][yy + 1]); + south->set_max_pos(worldRegionDetails->rivers_vertical.x_max[xx][yy + 1]); + } + else + { + south->set_active(0); + south->set_elevation(100); + south->set_min_pos(-30000); + south->set_max_pos(-30000); + } + + if (yy < 16) + { + west->set_active(worldRegionDetails->rivers_horizontal.active[xx][yy]); + west->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx][yy]); + west->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx][yy]); + west->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx][yy]); + } + else + { + west->set_active(0); + west->set_elevation(100); + west->set_min_pos(-30000); + west->set_max_pos(-30000); + } + + if (xx < 16 && yy < 16) + { + east->set_active(worldRegionDetails->rivers_horizontal.active[xx + 1][yy]); + east->set_elevation(worldRegionDetails->rivers_horizontal.elevation[xx + 1][yy]); + east->set_min_pos(worldRegionDetails->rivers_horizontal.y_min[xx + 1][yy]); + east->set_max_pos(worldRegionDetails->rivers_horizontal.y_max[xx + 1][yy]); + } + else + { + east->set_active(0); + east->set_elevation(100); + east->set_min_pos(-30000); + east->set_max_pos(-30000); + } + } + + auto regionMap = worldData->region_map[pos_x][pos_y]; + + for (int i = 0; i < worldData->sites.size(); i++) + { + df::world_site* site = worldData->sites[i]; + if (!site) + continue; + + int region_min_x = pos_x * 16; + int region_min_y = pos_y * 16; + + if ((site->global_min_x >(region_min_x + 16)) || + (site->global_min_y > (region_min_y + 16)) || + (site->global_max_x < (region_min_x)) || + (site->global_max_y < (region_min_y))) + continue; + + if (site->realization == NULL) + continue; + + auto realization = site->realization; + for (int site_x = 0; site_x < 17; site_x++) + for (int site_y = 0; site_y < 17; site_y++) + { + int region_x = site->global_min_x - region_min_x + site_x; + int region_y = site->global_min_y - region_min_y + site_y; + + if (region_x < 0 || region_y < 0 || region_x >= 16 || region_y >= 16) + continue; + + for (int j = 0; j < realization->building_map[site_x][site_y].buildings.size(); j++) + { + auto in_building = realization->building_map[site_x][site_y].buildings[j]; + auto out_building = outputTiles[region_x][region_y]->add_buildings(); + + out_building->set_id(in_building->id); #if DF_VERSION_INT > 34011 - out_building->set_type((SiteRealizationBuildingType)in_building->type); + out_building->set_type((SiteRealizationBuildingType)in_building->type); #endif - out_building->set_min_x(in_building->min_x - (site_x * 48)); - out_building->set_min_y(in_building->min_y - (site_y * 48)); - out_building->set_max_x(in_building->max_x - (site_x * 48)); - out_building->set_max_y(in_building->max_y - (site_y * 48)); + out_building->set_min_x(in_building->min_x - (site_x * 48)); + out_building->set_min_y(in_building->min_y - (site_y * 48)); + out_building->set_max_x(in_building->max_x - (site_x * 48)); + out_building->set_max_y(in_building->max_y - (site_y * 48)); - CopyMat(out_building->mutable_material(), in_building->item.mat_type, in_building->item.mat_index); + CopyMat(out_building->mutable_material(), in_building->item.mat_type, in_building->item.mat_index); #if DF_VERSION_INT >= 43005 - STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); - if (tower_info) - { - CopyMat(out_building->mutable_material(), tower_info->wall_item.mat_type, tower_info->wall_item.mat_index); - - auto out_tower = out_building->mutable_tower_info(); - out_tower->set_roof_z(tower_info->roof_z); - out_tower->set_round(tower_info->shape.bits.round); - out_tower->set_goblin(tower_info->shape.bits.goblin); - } - STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); - if (wall_info) - { - CopyMat(out_building->mutable_material(), wall_info->wall_item.mat_type, wall_info->wall_item.mat_index); - - auto out_wall = out_building->mutable_wall_info(); - - out_wall->set_start_x(wall_info->start_x - (site_x * 48)); - out_wall->set_start_y(wall_info->start_y - (site_y * 48)); - out_wall->set_start_z(wall_info->start_z); - out_wall->set_end_x(wall_info->end_x - (site_x * 48)); - out_wall->set_end_y(wall_info->end_y - (site_y * 48)); - out_wall->set_end_z(wall_info->end_z); - } + STRICT_VIRTUAL_CAST_VAR(tower_info, df::site_realization_building_info_castle_towerst, in_building->building_info); + if (tower_info) + { + CopyMat(out_building->mutable_material(), tower_info->wall_item.mat_type, tower_info->wall_item.mat_index); + + auto out_tower = out_building->mutable_tower_info(); + out_tower->set_roof_z(tower_info->roof_z); + out_tower->set_round(tower_info->shape.bits.round); + out_tower->set_goblin(tower_info->shape.bits.goblin); + } + STRICT_VIRTUAL_CAST_VAR(wall_info, df::site_realization_building_info_castle_wallst, in_building->building_info); + if (wall_info) + { + CopyMat(out_building->mutable_material(), wall_info->wall_item.mat_type, wall_info->wall_item.mat_index); + + auto out_wall = out_building->mutable_wall_info(); + + out_wall->set_start_x(wall_info->start_x - (site_x * 48)); + out_wall->set_start_y(wall_info->start_y - (site_y * 48)); + out_wall->set_start_z(wall_info->start_z); + out_wall->set_end_x(wall_info->end_x - (site_x * 48)); + out_wall->set_end_y(wall_info->end_y - (site_y * 48)); + out_wall->set_end_z(wall_info->end_z); + } #endif - } + } - } - } + } + } } static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) { - if (!df::global::world->world_data) - { - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - for (int i = 0; i < data->region_details.size(); i++) - { - df::world_region_details * region = data->region_details[i]; - if (!region) - continue; - WorldMap * regionMap = out->add_world_maps(); - CopyLocalMap(data, region, regionMap); - } - return CR_OK; + if (!df::global::world->world_data) + { + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + for (int i = 0; i < data->region_details.size(); i++) + { + df::world_region_details * region = data->region_details[i]; + if (!region) + continue; + WorldMap * regionMap = out->add_world_maps(); + CopyLocalMap(data, region, regionMap); + } + return CR_OK; } static command_result GetRegionMapsNew(color_ostream &stream, const EmptyMessage *in, RegionMaps *out) { - if (!df::global::world->world_data) - { - return CR_FAILURE; - } - df::world_data * data = df::global::world->world_data; - for (int i = 0; i < data->region_details.size(); i++) - { - df::world_region_details * region = data->region_details[i]; - if (!region) - continue; - RegionMap * regionMap = out->add_region_maps(); - CopyLocalMap(data, region, regionMap); - } - return CR_OK; + if (!df::global::world->world_data) + { + return CR_FAILURE; + } + df::world_data * data = df::global::world->world_data; + for (int i = 0; i < data->region_details.size(); i++) + { + df::world_region_details * region = data->region_details[i]; + if (!region) + continue; + RegionMap * regionMap = out->add_region_maps(); + CopyLocalMap(data, region, regionMap); + } + return CR_OK; } static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage *in, CreatureRawList *out) { - return GetPartialCreatureRaws(stream, NULL, out); + return GetPartialCreatureRaws(stream, NULL, out); } static command_result GetPartialCreatureRaws(color_ostream &stream, const ListRequest *in, CreatureRawList *out) { - if (!df::global::world) - return CR_FAILURE; + if (!df::global::world) + return CR_FAILURE; - df::world * world = df::global::world; + df::world * world = df::global::world; - int list_start = 0; - int list_end = world->raws.creatures.all.size(); + int list_start = 0; + int list_end = world->raws.creatures.all.size(); - if (in != nullptr) - { - list_start = in->list_start(); - if (in->list_end() < list_end) - list_end = in->list_end(); - } + if (in != nullptr) + { + list_start = in->list_start(); + if (in->list_end() < list_end) + list_end = in->list_end(); + } - for (int i = list_start; i < list_end; i++) - { - df::creature_raw * orig_creature = world->raws.creatures.all[i]; + for (int i = list_start; i < list_end; i++) + { + df::creature_raw * orig_creature = world->raws.creatures.all[i]; - auto send_creature = out->add_creature_raws(); + auto send_creature = out->add_creature_raws(); - send_creature->set_index(i); - send_creature->set_creature_id(orig_creature->creature_id); - send_creature->add_name(orig_creature->name[0]); - send_creature->add_name(orig_creature->name[1]); - send_creature->add_name(orig_creature->name[2]); + send_creature->set_index(i); + send_creature->set_creature_id(orig_creature->creature_id); + send_creature->add_name(orig_creature->name[0]); + send_creature->add_name(orig_creature->name[1]); + send_creature->add_name(orig_creature->name[2]); - send_creature->add_general_baby_name(orig_creature->general_baby_name[0]); - send_creature->add_general_baby_name(orig_creature->general_baby_name[1]); + send_creature->add_general_baby_name(orig_creature->general_baby_name[0]); + send_creature->add_general_baby_name(orig_creature->general_baby_name[1]); - send_creature->add_general_child_name(orig_creature->general_child_name[0]); - send_creature->add_general_child_name(orig_creature->general_child_name[1]); + send_creature->add_general_child_name(orig_creature->general_child_name[0]); + send_creature->add_general_child_name(orig_creature->general_child_name[1]); - send_creature->set_creature_tile(orig_creature->creature_tile); - send_creature->set_creature_soldier_tile(orig_creature->creature_soldier_tile); + send_creature->set_creature_tile(orig_creature->creature_tile); + send_creature->set_creature_soldier_tile(orig_creature->creature_soldier_tile); - ConvertDfColor(orig_creature->color, send_creature->mutable_color()); + ConvertDfColor(orig_creature->color, send_creature->mutable_color()); - send_creature->set_adultsize(orig_creature->adultsize); + send_creature->set_adultsize(orig_creature->adultsize); - for (int j = 0; j < orig_creature->caste.size(); j++) - { - auto orig_caste = orig_creature->caste[j]; - if (!orig_caste) - continue; - auto send_caste = send_creature->add_caste(); + for (int j = 0; j < orig_creature->caste.size(); j++) + { + auto orig_caste = orig_creature->caste[j]; + if (!orig_caste) + continue; + auto send_caste = send_creature->add_caste(); - send_caste->set_index(j); + send_caste->set_index(j); - send_caste->set_caste_id(orig_caste->caste_id); + send_caste->set_caste_id(orig_caste->caste_id); - send_caste->add_caste_name(orig_caste->caste_name[0]); - send_caste->add_caste_name(orig_caste->caste_name[1]); - send_caste->add_caste_name(orig_caste->caste_name[2]); + send_caste->add_caste_name(orig_caste->caste_name[0]); + send_caste->add_caste_name(orig_caste->caste_name[1]); + send_caste->add_caste_name(orig_caste->caste_name[2]); - send_caste->add_baby_name(orig_caste->baby_name[0]); - send_caste->add_baby_name(orig_caste->baby_name[1]); + send_caste->add_baby_name(orig_caste->baby_name[0]); + send_caste->add_baby_name(orig_caste->baby_name[1]); - send_caste->add_child_name(orig_caste->child_name[0]); - send_caste->add_child_name(orig_caste->child_name[1]); - send_caste->set_gender(orig_caste->gender); + send_caste->add_child_name(orig_caste->child_name[0]); + send_caste->add_child_name(orig_caste->child_name[1]); + send_caste->set_gender(orig_caste->gender); - for (int partIndex = 0; partIndex < orig_caste->body_info.body_parts.size(); partIndex++) - { - auto orig_part = orig_caste->body_info.body_parts[partIndex]; - if (!orig_part) - continue; - auto send_part = send_caste->add_body_parts(); + for (int partIndex = 0; partIndex < orig_caste->body_info.body_parts.size(); partIndex++) + { + auto orig_part = orig_caste->body_info.body_parts[partIndex]; + if (!orig_part) + continue; + auto send_part = send_caste->add_body_parts(); - send_part->set_token(orig_part->token); - send_part->set_category(orig_part->category); - send_part->set_parent(orig_part->con_part_id); + send_part->set_token(orig_part->token); + send_part->set_category(orig_part->category); + send_part->set_parent(orig_part->con_part_id); - for (int partFlagIndex = 0; partFlagIndex <= ENUM_LAST_ITEM(body_part_raw_flags); partFlagIndex++) - { - send_part->add_flags(orig_part->flags.is_set((body_part_raw_flags::body_part_raw_flags)partFlagIndex)); - } + for (int partFlagIndex = 0; partFlagIndex <= ENUM_LAST_ITEM(body_part_raw_flags); partFlagIndex++) + { + send_part->add_flags(orig_part->flags.is_set((body_part_raw_flags::body_part_raw_flags)partFlagIndex)); + } - for (int layerIndex = 0; layerIndex < orig_part->layers.size(); layerIndex++) - { - auto orig_layer = orig_part->layers[layerIndex]; - if (!orig_layer) - continue; - auto send_layer = send_part->add_layers(); + for (int layerIndex = 0; layerIndex < orig_part->layers.size(); layerIndex++) + { + auto orig_layer = orig_part->layers[layerIndex]; + if (!orig_layer) + continue; + auto send_layer = send_part->add_layers(); - send_layer->set_layer_name(orig_layer->layer_name); - send_layer->set_tissue_id(orig_layer->tissue_id); - send_layer->set_layer_depth(orig_layer->layer_depth); - for (int layerModIndex = 0; layerModIndex < orig_layer->bp_modifiers.size(); layerModIndex++) - { - send_layer->add_bp_modifiers(orig_layer->bp_modifiers[layerModIndex]); - } - } + send_layer->set_layer_name(orig_layer->layer_name); + send_layer->set_tissue_id(orig_layer->tissue_id); + send_layer->set_layer_depth(orig_layer->layer_depth); + for (int layerModIndex = 0; layerModIndex < orig_layer->bp_modifiers.size(); layerModIndex++) + { + send_layer->add_bp_modifiers(orig_layer->bp_modifiers[layerModIndex]); + } + } - send_part->set_relsize(orig_part->relsize); - } + send_part->set_relsize(orig_part->relsize); + } - send_caste->set_total_relsize(orig_caste->body_info.total_relsize); + send_caste->set_total_relsize(orig_caste->body_info.total_relsize); - for (int k = 0; k < orig_caste->bp_appearance.modifiers.size(); k++) - { - auto send_mod = send_caste->add_modifiers(); - auto orig_mod = orig_caste->bp_appearance.modifiers[k]; - send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); + for (int k = 0; k < orig_caste->bp_appearance.modifiers.size(); k++) + { + auto send_mod = send_caste->add_modifiers(); + auto orig_mod = orig_caste->bp_appearance.modifiers[k]; + send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); #if DF_VERSION_INT > 34011 - if (orig_mod->growth_rate > 0) - { - send_mod->set_mod_min(orig_mod->growth_min); - send_mod->set_mod_max(orig_mod->growth_max); - } - else + if (orig_mod->growth_rate > 0) + { + send_mod->set_mod_min(orig_mod->growth_min); + send_mod->set_mod_max(orig_mod->growth_max); + } + else #endif - { - send_mod->set_mod_min(orig_mod->ranges[0]); - send_mod->set_mod_max(orig_mod->ranges[6]); - } - - } - for (int k = 0; k < orig_caste->bp_appearance.modifier_idx.size(); k++) - { - send_caste->add_modifier_idx(orig_caste->bp_appearance.modifier_idx[k]); - send_caste->add_part_idx(orig_caste->bp_appearance.part_idx[k]); - send_caste->add_layer_idx(orig_caste->bp_appearance.layer_idx[k]); - } - for (int k = 0; k < orig_caste->body_appearance_modifiers.size(); k++) - { - auto send_mod = send_caste->add_body_appearance_modifiers(); - auto orig_mod = orig_caste->body_appearance_modifiers[k]; - - send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); + { + send_mod->set_mod_min(orig_mod->ranges[0]); + send_mod->set_mod_max(orig_mod->ranges[6]); + } + + } + for (int k = 0; k < orig_caste->bp_appearance.modifier_idx.size(); k++) + { + send_caste->add_modifier_idx(orig_caste->bp_appearance.modifier_idx[k]); + send_caste->add_part_idx(orig_caste->bp_appearance.part_idx[k]); + send_caste->add_layer_idx(orig_caste->bp_appearance.layer_idx[k]); + } + for (int k = 0; k < orig_caste->body_appearance_modifiers.size(); k++) + { + auto send_mod = send_caste->add_body_appearance_modifiers(); + auto orig_mod = orig_caste->body_appearance_modifiers[k]; + + send_mod->set_type(ENUM_KEY_STR(appearance_modifier_type, orig_mod->type)); #if DF_VERSION_INT > 34011 - if (orig_mod->growth_rate > 0) - { - send_mod->set_mod_min(orig_mod->growth_min); - send_mod->set_mod_max(orig_mod->growth_max); - } - else + if (orig_mod->growth_rate > 0) + { + send_mod->set_mod_min(orig_mod->growth_min); + send_mod->set_mod_max(orig_mod->growth_max); + } + else #endif - { - send_mod->set_mod_min(orig_mod->ranges[0]); - send_mod->set_mod_max(orig_mod->ranges[6]); - } - } - for (int k = 0; k < orig_caste->color_modifiers.size(); k++) - { - auto send_mod = send_caste->add_color_modifiers(); - auto orig_mod = orig_caste->color_modifiers[k]; - - for (int l = 0; l < orig_mod->pattern_index.size(); l++) - { - auto orig_pattern = world->raws.language.patterns[orig_mod->pattern_index[l]]; - auto send_pattern = send_mod->add_patterns(); - - for (int m = 0; m < orig_pattern->colors.size(); m++) - { - auto send_color = send_pattern->add_colors(); - auto orig_color = world->raws.language.colors[orig_pattern->colors[m]]; - send_color->set_red(orig_color->red * 255.0); - send_color->set_green(orig_color->green * 255.0); - send_color->set_blue(orig_color->blue * 255.0); - } - - send_pattern->set_id(orig_pattern->id); - send_pattern->set_pattern((PatternType)orig_pattern->pattern); - } - - for (int l = 0; l < orig_mod->body_part_id.size(); l++) - { - send_mod->add_body_part_id(orig_mod->body_part_id[l]); - send_mod->add_tissue_layer_id(orig_mod->tissue_layer_id[l]); - send_mod->set_start_date(orig_mod->start_date); - send_mod->set_end_date(orig_mod->end_date); - send_mod->set_part(orig_mod->part); - } - } - - send_caste->set_description(orig_caste->description); - send_caste->set_adult_size(orig_caste->misc.adult_size); - } - - for (int j = 0; j < orig_creature->tissue.size(); j++) - { - auto orig_tissue = orig_creature->tissue[j]; - auto send_tissue = send_creature->add_tissues(); - - send_tissue->set_id(orig_tissue->id); - send_tissue->set_name(orig_tissue->tissue_name_singular); - send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); - - CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); - } - } - - return CR_OK; + { + send_mod->set_mod_min(orig_mod->ranges[0]); + send_mod->set_mod_max(orig_mod->ranges[6]); + } + } + for (int k = 0; k < orig_caste->color_modifiers.size(); k++) + { + auto send_mod = send_caste->add_color_modifiers(); + auto orig_mod = orig_caste->color_modifiers[k]; + + for (int l = 0; l < orig_mod->pattern_index.size(); l++) + { + auto orig_pattern = world->raws.language.patterns[orig_mod->pattern_index[l]]; + auto send_pattern = send_mod->add_patterns(); + + for (int m = 0; m < orig_pattern->colors.size(); m++) + { + auto send_color = send_pattern->add_colors(); + auto orig_color = world->raws.language.colors[orig_pattern->colors[m]]; + send_color->set_red(orig_color->red * 255.0); + send_color->set_green(orig_color->green * 255.0); + send_color->set_blue(orig_color->blue * 255.0); + } + + send_pattern->set_id(orig_pattern->id); + send_pattern->set_pattern((PatternType)orig_pattern->pattern); + } + + for (int l = 0; l < orig_mod->body_part_id.size(); l++) + { + send_mod->add_body_part_id(orig_mod->body_part_id[l]); + send_mod->add_tissue_layer_id(orig_mod->tissue_layer_id[l]); + send_mod->set_start_date(orig_mod->start_date); + send_mod->set_end_date(orig_mod->end_date); + send_mod->set_part(orig_mod->part); + } + } + + send_caste->set_description(orig_caste->description); + send_caste->set_adult_size(orig_caste->misc.adult_size); + } + + for (int j = 0; j < orig_creature->tissue.size(); j++) + { + auto orig_tissue = orig_creature->tissue[j]; + auto send_tissue = send_creature->add_tissues(); + + send_tissue->set_id(orig_tissue->id); + send_tissue->set_name(orig_tissue->tissue_name_singular); + send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); + + CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); + } + } + + return CR_OK; } static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out) { - GetPartialPlantRaws(stream, nullptr, out); - return CR_OK; + GetPartialPlantRaws(stream, nullptr, out); + return CR_OK; } static command_result GetPartialPlantRaws(color_ostream &stream, const ListRequest *in, PlantRawList *out) { - if (!df::global::world) - return CR_FAILURE; - - df::world * world = df::global::world; - - int list_start = 0; - int list_end = world->raws.plants.all.size(); - - if (in != nullptr) - { - list_start = in->list_start(); - if (in->list_end() < list_end) - list_end = in->list_end(); - } - - for (int i = 0; i < world->raws.plants.all.size(); i++) - { - df::plant_raw* plant_local = world->raws.plants.all[i]; - PlantRaw* plant_remote = out->add_plant_raws(); - - plant_remote->set_index(i); - plant_remote->set_id(plant_local->id); - plant_remote->set_name(plant_local->name); - if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) - plant_remote->set_tile(plant_local->tiles.shrub_tile); - else - plant_remote->set_tile(plant_local->tiles.tree_tile); + if (!df::global::world) + return CR_FAILURE; + + df::world * world = df::global::world; + + int list_start = 0; + int list_end = world->raws.plants.all.size(); + + if (in != nullptr) + { + list_start = in->list_start(); + if (in->list_end() < list_end) + list_end = in->list_end(); + } + + for (int i = 0; i < world->raws.plants.all.size(); i++) + { + df::plant_raw* plant_local = world->raws.plants.all[i]; + PlantRaw* plant_remote = out->add_plant_raws(); + + plant_remote->set_index(i); + plant_remote->set_id(plant_local->id); + plant_remote->set_name(plant_local->name); + if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) + plant_remote->set_tile(plant_local->tiles.shrub_tile); + else + plant_remote->set_tile(plant_local->tiles.tree_tile); #if DF_VERSION_INT > 34011 - for (int j = 0; j < plant_local->growths.size(); j++) - { - df::plant_growth* growth_local = plant_local->growths[j]; - TreeGrowth * growth_remote = plant_remote->add_growths(); - growth_remote->set_index(j); - growth_remote->set_id(growth_local->id); - growth_remote->set_name(growth_local->name); - for (int k = 0; k < growth_local->prints.size(); k++) - { - df::plant_growth_print* print_local = growth_local->prints[k]; - GrowthPrint* print_remote = growth_remote->add_prints(); - print_remote->set_priority(print_local->priority); - print_remote->set_color(print_local->color[0] | (print_local->color[2] * 8)); - print_remote->set_timing_start(print_local->timing_start); - print_remote->set_timing_end(print_local->timing_end); - print_remote->set_tile(print_local->tile_growth); - } - growth_remote->set_timing_start(growth_local->timing_1); - growth_remote->set_timing_end(growth_local->timing_2); - growth_remote->set_twigs(growth_local->locations.bits.twigs); - growth_remote->set_light_branches(growth_local->locations.bits.light_branches); - growth_remote->set_heavy_branches(growth_local->locations.bits.heavy_branches); - growth_remote->set_trunk(growth_local->locations.bits.trunk); - growth_remote->set_roots(growth_local->locations.bits.roots); - growth_remote->set_cap(growth_local->locations.bits.cap); - growth_remote->set_sapling(growth_local->locations.bits.sapling); - growth_remote->set_timing_start(growth_local->timing_1); - growth_remote->set_timing_end(growth_local->timing_2); - growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); - growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); - CopyMat(growth_remote->mutable_mat(), growth_local->mat_type, growth_local->mat_index); - } + for (int j = 0; j < plant_local->growths.size(); j++) + { + df::plant_growth* growth_local = plant_local->growths[j]; + TreeGrowth * growth_remote = plant_remote->add_growths(); + growth_remote->set_index(j); + growth_remote->set_id(growth_local->id); + growth_remote->set_name(growth_local->name); + for (int k = 0; k < growth_local->prints.size(); k++) + { + df::plant_growth_print* print_local = growth_local->prints[k]; + GrowthPrint* print_remote = growth_remote->add_prints(); + print_remote->set_priority(print_local->priority); + print_remote->set_color(print_local->color[0] | (print_local->color[2] * 8)); + print_remote->set_timing_start(print_local->timing_start); + print_remote->set_timing_end(print_local->timing_end); + print_remote->set_tile(print_local->tile_growth); + } + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_twigs(growth_local->locations.bits.twigs); + growth_remote->set_light_branches(growth_local->locations.bits.light_branches); + growth_remote->set_heavy_branches(growth_local->locations.bits.heavy_branches); + growth_remote->set_trunk(growth_local->locations.bits.trunk); + growth_remote->set_roots(growth_local->locations.bits.roots); + growth_remote->set_cap(growth_local->locations.bits.cap); + growth_remote->set_sapling(growth_local->locations.bits.sapling); + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); + growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); + CopyMat(growth_remote->mutable_mat(), growth_local->mat_type, growth_local->mat_index); + } #endif - } - return CR_OK; + } + return CR_OK; } static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out) { - df::graphic * gps = df::global::gps; - out->set_width(gps->dimx); - out->set_height(gps->dimy); - for (int i = 0; i < (gps->dimx * gps->dimy); i++) - { - int index = i * 4; - auto tile = out->add_tiles(); - tile->set_character(gps->screen[index]); - tile->set_foreground(gps->screen[index + 1] | (gps->screen[index + 3] * 8)); - tile->set_background(gps->screen[index + 2]); - } - - return CR_OK; + df::graphic * gps = df::global::gps; + out->set_width(gps->dimx); + out->set_height(gps->dimy); + for (int i = 0; i < (gps->dimx * gps->dimy); i++) + { + int index = i * 4; + auto tile = out->add_tiles(); + tile->set_character(gps->screen[index]); + tile->set_foreground(gps->screen[index + 1] | (gps->screen[index + 3] * 8)); + tile->set_background(gps->screen[index + 2]); + } + + return CR_OK; } static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in) { #if DF_VERSION_INT > 34011 - SDL::Event e; - e.key.type = in->type(); - e.key.state = in->state(); - e.key.ksym.mod = (SDL::Mod)in->mod(); - e.key.ksym.scancode = in->scancode(); - e.key.ksym.sym = (SDL::Key)in->sym(); - e.key.ksym.unicode = in->unicode(); - SDL_PushEvent(&e); + SDL::Event e; + e.key.type = in->type(); + e.key.state = in->state(); + e.key.ksym.mod = (SDL::Mod)in->mod(); + e.key.ksym.scancode = in->scancode(); + e.key.ksym.sym = (SDL::Key)in->sym(); + e.key.ksym.unicode = in->unicode(); + SDL_PushEvent(&e); #endif - return CR_OK; + return CR_OK; } static command_result SendDigCommand(color_ostream &stream, const DigCommand *in) { - MapExtras::MapCache mc; - - for (int i = 0; i < in->locations_size(); i++) - { - auto pos = in->locations(i); - auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); - switch (in->designation()) - { - case NO_DIG: - des.bits.dig = tile_dig_designation::No; - break; - case DEFAULT_DIG: - des.bits.dig = tile_dig_designation::Default; - break; - case UP_DOWN_STAIR_DIG: - des.bits.dig = tile_dig_designation::UpDownStair; - break; - case CHANNEL_DIG: - des.bits.dig = tile_dig_designation::Channel; - break; - case RAMP_DIG: - des.bits.dig = tile_dig_designation::Ramp; - break; - case DOWN_STAIR_DIG: - des.bits.dig = tile_dig_designation::DownStair; - break; - case UP_STAIR_DIG: - des.bits.dig = tile_dig_designation::UpStair; - break; - default: - break; - } - mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); + MapExtras::MapCache mc; + + for (int i = 0; i < in->locations_size(); i++) + { + auto pos = in->locations(i); + auto des = mc.designationAt(DFCoord(pos.x(), pos.y(), pos.z())); + switch (in->designation()) + { + case NO_DIG: + des.bits.dig = tile_dig_designation::No; + break; + case DEFAULT_DIG: + des.bits.dig = tile_dig_designation::Default; + break; + case UP_DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpDownStair; + break; + case CHANNEL_DIG: + des.bits.dig = tile_dig_designation::Channel; + break; + case RAMP_DIG: + des.bits.dig = tile_dig_designation::Ramp; + break; + case DOWN_STAIR_DIG: + des.bits.dig = tile_dig_designation::DownStair; + break; + case UP_STAIR_DIG: + des.bits.dig = tile_dig_designation::UpStair; + break; + default: + break; + } + mc.setDesignationAt(DFCoord(pos.x(), pos.y(), pos.z()), des); #if DF_VERSION_INT >= 43005 - //remove and job postings related. - for (df::job_list_link * listing = &(world->jobs.list); listing != NULL; listing = listing->next) - { - if (listing->item == NULL) - continue; - auto type = listing->item->job_type; - switch (type) - { - case df::enums::job_type::CarveFortification: - case df::enums::job_type::DetailWall: - case df::enums::job_type::DetailFloor: - case df::enums::job_type::Dig: - case df::enums::job_type::CarveUpwardStaircase: - case df::enums::job_type::CarveDownwardStaircase: - case df::enums::job_type::CarveUpDownStaircase: - case df::enums::job_type::CarveRamp: - case df::enums::job_type::DigChannel: - case df::enums::job_type::FellTree: - case df::enums::job_type::GatherPlants: - case df::enums::job_type::RemoveConstruction: - case df::enums::job_type::CarveTrack: - { - if (listing->item->pos == DFCoord(pos.x(), pos.y(), pos.z())) - { - Job::removeJob(listing->item); - goto JOB_FOUND; - } - break; - } - default: - continue; - } - } - JOB_FOUND: - continue; + //remove and job postings related. + for (df::job_list_link * listing = &(world->jobs.list); listing != NULL; listing = listing->next) + { + if (listing->item == NULL) + continue; + auto type = listing->item->job_type; + switch (type) + { + case df::enums::job_type::CarveFortification: + case df::enums::job_type::DetailWall: + case df::enums::job_type::DetailFloor: + case df::enums::job_type::Dig: + case df::enums::job_type::CarveUpwardStaircase: + case df::enums::job_type::CarveDownwardStaircase: + case df::enums::job_type::CarveUpDownStaircase: + case df::enums::job_type::CarveRamp: + case df::enums::job_type::DigChannel: + case df::enums::job_type::FellTree: + case df::enums::job_type::GatherPlants: + case df::enums::job_type::RemoveConstruction: + case df::enums::job_type::CarveTrack: + { + if (listing->item->pos == DFCoord(pos.x(), pos.y(), pos.z())) + { + Job::removeJob(listing->item); + goto JOB_FOUND; + } + break; + } + default: + continue; + } + } + JOB_FOUND: + continue; #endif - } + } - mc.WriteAll(); - return CR_OK; + mc.WriteAll(); + return CR_OK; } static command_result SetPauseState(color_ostream &stream, const SingleBool *in) { - DFHack::World::SetPauseState(in->value()); - return CR_OK; + DFHack::World::SetPauseState(in->value()); + return CR_OK; } static command_result GetPauseState(color_ostream &stream, const EmptyMessage *in, SingleBool *out) { - out->set_value(World::ReadPauseState()); - return CR_OK; + out->set_value(World::ReadPauseState()); + return CR_OK; } static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out) { - out->set_dfhack_version(DFHACK_VERSION); + out->set_dfhack_version(DFHACK_VERSION); #if DF_VERSION_INT == 34011 - out->set_dwarf_fortress_version("0.34.11"); + out->set_dwarf_fortress_version("0.34.11"); #else - out->set_dwarf_fortress_version(DF_VERSION); + out->set_dwarf_fortress_version(DF_VERSION); #endif - out->set_remote_fortress_reader_version(RFR_VERSION); - return CR_OK; + out->set_remote_fortress_reader_version(RFR_VERSION); + return CR_OK; } +int lastSentReportID = -1; + static command_result GetReports(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Status * out) { - for (int i = 0; i < world->status.reports.size(); i++) - { - auto local_rep = world->status.reports[i]; - if (!local_rep) - continue; - auto send_rep = out->add_reports(); - send_rep->set_type(local_rep->type); - send_rep->set_text(DF2UTF(local_rep->text)); - ConvertDfColor(local_rep->color | (local_rep->bright ? 8 : 0), send_rep->mutable_color()); - send_rep->set_duration(local_rep->duration); - send_rep->set_continuation(local_rep->flags.bits.continuation); - send_rep->set_unconscious(local_rep->flags.bits.unconscious); - send_rep->set_announcement(local_rep->flags.bits.announcement); - send_rep->set_repeat_count(local_rep->repeat_count); - ConvertDFCoord(local_rep->pos, send_rep->mutable_pos()); - send_rep->set_id(local_rep->id); - send_rep->set_year(local_rep->year); - send_rep->set_time(local_rep->time); - } - return CR_OK; + //First find the last report we sent, so it doesn't get resent. + int lastSentIndex = -1; + for (int i = world->status.reports.size() - 1; i >= 0; i--) + { + auto local_rep = world->status.reports[i]; + if (local_rep->id <= lastSentReportID) + { + lastSentIndex = i; + break; + } + } + for (int i = lastSentIndex + 1; i < world->status.reports.size(); i++) + { + auto local_rep = world->status.reports[i]; + if (!local_rep) + continue; + auto send_rep = out->add_reports(); + send_rep->set_type(local_rep->type); + send_rep->set_text(DF2UTF(local_rep->text)); + ConvertDfColor(local_rep->color | (local_rep->bright ? 8 : 0), send_rep->mutable_color()); + send_rep->set_duration(local_rep->duration); + send_rep->set_continuation(local_rep->flags.bits.continuation); + send_rep->set_unconscious(local_rep->flags.bits.unconscious); + send_rep->set_announcement(local_rep->flags.bits.announcement); + send_rep->set_repeat_count(local_rep->repeat_count); + ConvertDFCoord(local_rep->pos, send_rep->mutable_pos()); + send_rep->set_id(local_rep->id); + send_rep->set_year(local_rep->year); + send_rep->set_time(local_rep->time); + lastSentReportID = local_rep->id; + } + return CR_OK; } \ No newline at end of file From 9cc392e45781e2ee8bccf002203d0f5f24f11ad7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 20 Dec 2017 23:44:11 -0500 Subject: [PATCH 036/170] Authors.rst: Add Kromtec (dfhack/scripts#36) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 2537abfd1..fc4b71dd1 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -55,6 +55,7 @@ Jonas Ask kane-t kane-t Kelly Kinkade ab9rf Kris Parker kaypy +Kromtec Kromtec Kurik Amudnil Lethosor lethosor Mason11987 Mason11987 From d6a51f65eb4ad9f281ec01f9eb08b61996e434e0 Mon Sep 17 00:00:00 2001 From: PatrikLundell Date: Fri, 22 Dec 2017 13:42:59 +0100 Subject: [PATCH 037/170] Blocked errant line feed at full buffer --- library/Console-windows.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 3dc687642..3caacd924 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -62,7 +62,7 @@ using namespace DFHack; using namespace tthread; // FIXME: maybe make configurable with an ini option? -#define MAX_CONSOLE_LINES 999; +#define MAX_CONSOLE_LINES 999 namespace DFHack { @@ -165,7 +165,7 @@ namespace DFHack // Blank to EOL char* tmp = (char*)malloc(inf.dwSize.X); memset(tmp, ' ', inf.dwSize.X); - output(tmp, inf.dwSize.X, 0, inf.dwCursorPosition.Y); + blankout(tmp, inf.dwSize.X, 0, inf.dwCursorPosition.Y); free(tmp); COORD coord = {0, inf.dwCursorPosition.Y}; // Windows uses 0-based coordinates SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); @@ -210,6 +210,13 @@ namespace DFHack } } + void blankout(const char* str, size_t len, int x, int y) + { + COORD pos = { (SHORT)x, (SHORT)y }; + DWORD count = 0; + WriteConsoleOutputCharacterA(console_out, str, len, pos, &count); + } + void output(const char* str, size_t len, int x, int y) { COORD pos = { (SHORT)x, (SHORT)y }; @@ -248,7 +255,7 @@ namespace DFHack // Blank to EOL char* tmp = (char*)malloc(inf.dwSize.X - (plen + len)); memset(tmp, ' ', inf.dwSize.X - (plen + len)); - output(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y); + blankout(tmp, inf.dwSize.X - (plen + len), len + plen, inf.dwCursorPosition.Y); free(tmp); } inf.dwCursorPosition.X = (SHORT)(cooked_cursor + plen); From e7a95155ab3b17bdc93ef5221cc7dbd5a0c1d23b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 20:18:55 -0500 Subject: [PATCH 038/170] Lua API: add get_vector() and support for renaming class methods See dfhack/df-structures@5bdb0e8 --- library/DataStaticsFields.cpp | 1 + library/xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index d6a622a9e..d6f0414bb 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -60,4 +60,5 @@ namespace df { #define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) #define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name #define METHOD(mode, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::name) +#define METHOD_N(mode, func, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::func) #define FLD_END struct_field_info::END diff --git a/library/xml b/library/xml index c531a0901..31ea71c77 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c531a09019e521fabb3c943bb49f831f635c309f +Subproject commit 31ea71c778beba46f941296a89fa579d5261dab4 From 2b534bef5f7f596e2501a0236d78fff07f7e4496 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 20:20:38 -0500 Subject: [PATCH 039/170] Update scripts (exportlegends, create-unit) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 8b6507ed7..922aa7926 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8b6507ed7e8841afe35ee8e156f08edbb7c59f45 +Subproject commit 922aa79268cbad01834bd742cdf184c625cd80ad From 1c9748553e7ee112c395c8a1c0707f17df64deb7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 20:49:24 -0500 Subject: [PATCH 040/170] Remove warn-stuck-trees from onLoad.init-example --- onLoad.init-example | 1 - 1 file changed, 1 deletion(-) diff --git a/onLoad.init-example b/onLoad.init-example index 08dd536a7..1d32f07c9 100644 --- a/onLoad.init-example +++ b/onLoad.init-example @@ -1,2 +1 @@ repeat -name warn-starving -time 10 -timeUnits days -command [ warn-starving ] -repeat -name warn-stuck-trees -time 10 -timeUnits days -command [ warn-stuck-trees ] From 98e1842427786aca9d04c56dbbbefb21809c4ef5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 21:15:16 -0500 Subject: [PATCH 041/170] List removed scripts to silence docs-related build failure --- docs/Scripts-removed.rst | 14 ++++++++++++++ index.rst | 1 + 2 files changed, 15 insertions(+) create mode 100644 docs/Scripts-removed.rst diff --git a/docs/Scripts-removed.rst b/docs/Scripts-removed.rst new file mode 100644 index 000000000..4490110ba --- /dev/null +++ b/docs/Scripts-removed.rst @@ -0,0 +1,14 @@ +############### +Removed scripts +############### + +The following scripts were removed for various reasons. + +.. contents:: + :depth: 2 + +.. _warn-stuck-trees: + +warn-stuck-trees +================ +The corresponding DF bug, :bug:`9252` was fixed in DF 0.44.01. diff --git a/index.rst b/index.rst index 1f647907b..5cba99e2c 100644 --- a/index.rst +++ b/index.rst @@ -50,6 +50,7 @@ Other Contents /docs/Authors /LICENSE /NEWS + /docs/Scripts-removed For Developers ============== From d90ee0edf883bf9e53b00140cd238cf3415fe8a4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 21:15:30 -0500 Subject: [PATCH 042/170] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 31ea71c77..bfeb74b74 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 31ea71c778beba46f941296a89fa579d5261dab4 +Subproject commit bfeb74b748a2af231352a11df3123af7d8ccc199 diff --git a/scripts b/scripts index 922aa7926..6934b9d47 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 922aa79268cbad01834bd742cdf184c625cd80ad +Subproject commit 6934b9d47ccce5908395998133c14c91497f0935 From c10f7ee77a6532a8d2bfa2eccc37d4a03b9b1908 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 21:44:18 -0500 Subject: [PATCH 043/170] Authors: add @ZechyW (dfhack/scripts#40) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index fc4b71dd1..4223fb5ee 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -133,6 +133,7 @@ Vjek Warmist warmist Wes Malone wesQ3 Will Rogers wjrogers +ZechyW ZechyW Zhentar Zhentar zilpin zilpin ======================= ======================= =========================== From 86dc58f22e1d532b6ff6404ba1d8f7f2253ca92d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 22:08:04 -0500 Subject: [PATCH 044/170] Update changelogs --- NEWS.rst | 33 +++++++++++++++++++++++++++++++++ docs/NEWS-dev.rst | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 673ae31f9..851df0f56 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -42,6 +42,39 @@ DFHack future Lua --- - Added a new ``dfhack.console`` API +- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, + e.g. ``df.unit.get_vector() == df.global.world.units.all`` + +New Scripts +----------- +- `devel/check-other-ids`: Checks the validity of "other" vectors in the + ``world`` global +- `gui/cp437-table`: An in-game CP437 table + +Fixes +----- +- Fixed issues with the console output color affecting the prompt on Windows +- `createitem`: stopped items from teleporting away in some forts +- `gui/gm-unit`: can now edit mining skill +- `gui/quickcmd`: stopped error from adding too many commands + +Misc Improvements +----------------- +- The console now provides suggestions for built-in commands +- `devel/export-dt-ini`: avoid hardcoding flags +- `exportlegends`: + + - reordered some tags to match DF's order + - added progress indicators for exporting long lists + +- `gui/gm-editor`: added enum names to enum edit dialogs +- `gui/gm-unit`: made skill search case-insensitive +- `gui/rename`: added "clear" and "special characters" options +- `remotefortressreader`: includes item stack sizes and some performance improvements + +Removed +------- +- `warn-stuck-trees`: the corresponding DF bug was fixed in 0.44.01 DFHack 0.43.05-r3 ================= diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 8dfe2866b..e44bdf96c 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,48 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.02-beta1 +==================== + +Fixes +----- +- Fixed issues with the console output color affecting the prompt on Windows +- `createitem`: stopped items from teleporting away in some forts +- `gui/gm-unit`: can now edit mining skill +- `gui/quickcmd`: stopped error from adding too many commands +- `modtools/create-unit`: fixed error when domesticating units + +Structures +---------- +- Located ``start_dwarf_count`` offset for all builds except 64-bit Linux; + `startdwarf` should work now +- Added ``buildings_other_id.DISPLAY_CASE`` +- Fixed ``viewscreen_titlest.start_savegames`` alignment +- Fixed ``unit`` alignment +- Identified ``historical_entity.unknown1b.deities`` (deity IDs) + +API Changes +----------- +- Lua; Exposed ``get_vector()`` (from C++) for all types that support + ``find()``, e.g. ``df.unit.get_vector() == df.global.world.units.all`` + +Additions/Removals +------------------ +- Added `devel/check-other-ids`: Checks the validity of "other" vectors in the + ``world`` global +- Added `gui/cp437-table`: An in-game CP437 table +- Removed `warn-stuck-trees`: the corresponding DF bug was fixed in 0.44.01 + +Other Changes +------------- +- The console now provides suggestions for built-in commands +- `devel/export-dt-ini`: avoid hardcoding flags +- `gui/gm-editor`: added enum names to enum edit dialogs +- `gui/gm-unit`: made skill search case-insensitive +- `gui/rename`: added "clear" and "special characters" options +- `remotefortressreader`: includes item stack sizes and some performance improvements + + DFHack 0.44.02-alpha1 ===================== From 2e505fae289028da5211cd1a663814c672d36e41 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 22:09:09 -0500 Subject: [PATCH 045/170] Reorder sections in NEWS (future only) --- NEWS.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 851df0f56..66963fff2 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -12,13 +12,13 @@ Sections for each release are added as required, and consist solely of the following in order as subheadings:: - Internals - Lua - Ruby New [Internal Commands | Plugins | Scripts | Tweaks | Features] Fixes Misc Improvements Removed + Internals + Lua + Ruby When referring to a script, plugin, or command, use backticks (```) to create a link to the relevant documentation - and check that the docs are @@ -39,12 +39,6 @@ Changelog DFHack future ============= -Lua ---- -- Added a new ``dfhack.console`` API -- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, - e.g. ``df.unit.get_vector() == df.global.world.units.all`` - New Scripts ----------- - `devel/check-other-ids`: Checks the validity of "other" vectors in the @@ -76,6 +70,13 @@ Removed ------- - `warn-stuck-trees`: the corresponding DF bug was fixed in 0.44.01 +Lua +--- +- Added a new ``dfhack.console`` API +- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, + e.g. ``df.unit.get_vector() == df.global.world.units.all`` + + DFHack 0.43.05-r3 ================= From 6175d7c151b1297298a566aad50d0bcb1460469b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 23 Dec 2017 22:09:35 -0500 Subject: [PATCH 046/170] Bump to 0.44.02-beta1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d55cd9e43..4e47a12d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ endif() # set up versioning. set(DF_VERSION "0.44.02") -SET(DFHACK_RELEASE "alpha1") +SET(DFHACK_RELEASE "beta1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 22bdc6227cc08e67cb1767f44594566fd56de3d0 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 24 Dec 2017 10:50:30 +0530 Subject: [PATCH 047/170] add more world mode options to world info --- library/RemoteTools.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 77374ea0c..8b62d7ab7 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -395,15 +395,21 @@ static command_result GetWorldInfo(color_ostream &stream, { case game_type::DWARF_MAIN: case game_type::DWARF_RECLAIM: - out->set_mode(GetWorldInfoOut::MODE_DWARF); + case game_type::DWARF_ARENA: + case game_type::DWARF_TUTORIAL: + case game_type::DWARF_UNRETIRE: + out->set_mode(GetWorldInfoOut::MODE_DWARF); out->set_civ_id(ui->civ_id); out->set_site_id(ui->site_id); out->set_group_id(ui->group_id); out->set_race_id(ui->race_id); break; - case game_type::ADVENTURE_MAIN: - out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); + case game_type::ADVENTURE_MAIN: + case game_type::ADVENTURE_ARENA: + case game_type::ADVENTURE_DUNGEON: + case game_type::ADVENTURE_WORLD_DEBUG: + out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); if (auto unit = vector_get(world->units.active, 0)) out->set_player_unit_id(unit->id); From 73c6209f875c4032c7f0cf6a5c67f607bce393a1 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 24 Dec 2017 17:22:50 +0530 Subject: [PATCH 048/170] Remove extra These don't actually act the same. --- library/RemoteTools.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 8b62d7ab7..90f4104ca 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -395,8 +395,6 @@ static command_result GetWorldInfo(color_ostream &stream, { case game_type::DWARF_MAIN: case game_type::DWARF_RECLAIM: - case game_type::DWARF_ARENA: - case game_type::DWARF_TUTORIAL: case game_type::DWARF_UNRETIRE: out->set_mode(GetWorldInfoOut::MODE_DWARF); out->set_civ_id(ui->civ_id); @@ -407,8 +405,6 @@ static command_result GetWorldInfo(color_ostream &stream, case game_type::ADVENTURE_MAIN: case game_type::ADVENTURE_ARENA: - case game_type::ADVENTURE_DUNGEON: - case game_type::ADVENTURE_WORLD_DEBUG: out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); if (auto unit = vector_get(world->units.active, 0)) From 1408f7bfb3e863ec24f7375c397ba50dc01cccac Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 24 Dec 2017 18:33:25 +0530 Subject: [PATCH 049/170] Add a command to remotely send simple movement commands to an adventurer. --- plugins/proto/AdventureControl.proto | 11 ++ plugins/remotefortressreader/CMakeLists.txt | 3 + .../adventure_control.cpp | 162 ++++++++++++++++++ .../remotefortressreader/adventure_control.h | 9 + .../remotefortressreader.cpp | 2 + 5 files changed, 187 insertions(+) create mode 100644 plugins/proto/AdventureControl.proto create mode 100644 plugins/remotefortressreader/adventure_control.cpp create mode 100644 plugins/remotefortressreader/adventure_control.h diff --git a/plugins/proto/AdventureControl.proto b/plugins/proto/AdventureControl.proto new file mode 100644 index 000000000..4db1afdf7 --- /dev/null +++ b/plugins/proto/AdventureControl.proto @@ -0,0 +1,11 @@ +package AdventureControl; + +//Attempts to provide a complete framework for reading everything from a fortress needed for vizualization +option optimize_for = LITE_RUNTIME; + +import "RemoteFortressReader.proto"; + +message MoveCommandParams +{ + optional RemoteFortressReader.Coord direction = 1; +} \ No newline at end of file diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index ee6383a3c..72b7c94cc 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -2,16 +2,19 @@ PROJECT (remotefortressreader) # A list of source files SET(PROJECT_SRCS remotefortressreader.cpp + adventure_control.cpp building_reader.cpp ) # A list of headers SET(PROJECT_HDRS + adventure_control.h building_reader.h df_version_int.h ) #proto files to include. SET(PROJECT_PROTO ../../proto/RemoteFortressReader + ../../proto/AdventureControl ) SET_SOURCE_FILES_PROPERTIES( ${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp new file mode 100644 index 000000000..d5e713080 --- /dev/null +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -0,0 +1,162 @@ +#include "adventure_control.h" +#include "DataDefs.h" + +#include "df/viewscreen.h" + +#include "modules/Gui.h" + +using namespace AdventureControl; +using namespace df::enums; +using namespace DFHack; +using namespace Gui; + + +command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) +{ + auto viewScreen = getCurViewscreen(); + if (!in->has_direction()) + return CR_WRONG_USAGE; + auto dir = in->direction(); + switch (dir.x()) + { + case -1: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_NW_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_NW); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_NW_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_W_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_W); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_W_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_SW_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_SW); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_SW_UP); + break; + } + break; + } + break; + case 0: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_N_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_N); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_N_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_DOWN); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_S_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_S); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_S_UP); + break; + } + break; + } + break; + case 1: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_NE_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_NE); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_NE_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_E_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_E); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_E_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_SE_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_SE); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_SE_UP); + break; + } + break; + } + break; + } + return CR_OK; +} \ No newline at end of file diff --git a/plugins/remotefortressreader/adventure_control.h b/plugins/remotefortressreader/adventure_control.h new file mode 100644 index 000000000..f4d912019 --- /dev/null +++ b/plugins/remotefortressreader/adventure_control.h @@ -0,0 +1,9 @@ +#ifndef ADVENTURE_CONTROL_H +#define ADVENTURE_CONTROL_H + +#include "RemoteClient.h" +#include "AdventureControl.pb.h" + +DFHack::command_result MoveCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); + +#endif // !ADVENTURE_CONTROL_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 93df40dac..8eae24adb 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -113,6 +113,7 @@ #include "df/unit_relationship_type.h" +#include "adventure_control.h" #include "building_reader.h" using namespace DFHack; @@ -286,6 +287,7 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("GetPauseState", GetPauseState, SF_ALLOW_REMOTE); svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); + svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); return svc; } From 692bce8507614028e8d854f2cb6a3791df2f61ed Mon Sep 17 00:00:00 2001 From: Lethosor Date: Sun, 24 Dec 2017 13:50:54 -0500 Subject: [PATCH 050/170] Tabs to spaces --- library/RemoteTools.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 90f4104ca..e29220fb7 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -395,17 +395,17 @@ static command_result GetWorldInfo(color_ostream &stream, { case game_type::DWARF_MAIN: case game_type::DWARF_RECLAIM: - case game_type::DWARF_UNRETIRE: - out->set_mode(GetWorldInfoOut::MODE_DWARF); + case game_type::DWARF_UNRETIRE: + out->set_mode(GetWorldInfoOut::MODE_DWARF); out->set_civ_id(ui->civ_id); out->set_site_id(ui->site_id); out->set_group_id(ui->group_id); out->set_race_id(ui->race_id); break; - case game_type::ADVENTURE_MAIN: - case game_type::ADVENTURE_ARENA: - out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); + case game_type::ADVENTURE_MAIN: + case game_type::ADVENTURE_ARENA: + out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); if (auto unit = vector_get(world->units.active, 0)) out->set_player_unit_id(unit->id); From d6a6bf008e2b51d8a38360e4e5b6933b7f1856e0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 24 Dec 2017 23:17:39 -0500 Subject: [PATCH 051/170] Update xml, stonesense Ref #1206 --- library/xml | 2 +- plugins/stonesense | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index bfeb74b74..f04f55fea 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bfeb74b748a2af231352a11df3123af7d8ccc199 +Subproject commit f04f55feaae9e234d88373cdf4491bde5fa346ef diff --git a/plugins/stonesense b/plugins/stonesense index be793a080..4c55e1439 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit be793a080e66db1ff79ac284070632ec1a896708 +Subproject commit 4c55e1439e4e9fa55f6b17147a346c9cde11f7b3 From 5d32253b6e028afb73fd8bdf62d2e5eae1f57225 Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 25 Dec 2017 22:00:45 +0530 Subject: [PATCH 052/170] added jumping ability to adventure control. --- .../adventure_control.cpp | 51 +++++++++++++++++++ .../remotefortressreader/adventure_control.h | 3 ++ .../remotefortressreader.cpp | 16 +++++- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index d5e713080..6e717ebd1 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -5,11 +5,23 @@ #include "modules/Gui.h" +#include + using namespace AdventureControl; using namespace df::enums; using namespace DFHack; using namespace Gui; +std::queue keyQueue; + +void KeyUpdate() +{ + if (!keyQueue.empty()) + { + getCurViewscreen()->feed_key(keyQueue.front()); + keyQueue.pop(); + } +} command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) { @@ -159,4 +171,43 @@ command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParam break; } return CR_OK; +} +command_result JumpCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) +{ + if (!in->has_direction()) + return CR_WRONG_USAGE; + auto dir = in->direction(); + keyQueue.push(interface_key::A_JUMP); + int x = dir.x(); + int y = dir.y(); + if (x > 0) + { + for (int i = 0; i < x; i++) + { + keyQueue.push(interface_key::CURSOR_RIGHT); + } + } + if (x < 0) + { + for (int i = 0; i > x; i--) + { + keyQueue.push(interface_key::CURSOR_LEFT); + } + } + if (y > 0) + { + for (int i = 0; i < y; i++) + { + keyQueue.push(interface_key::CURSOR_DOWN); + } + } + if (y < 0) + { + for (int i = 0; i > y; i--) + { + keyQueue.push(interface_key::CURSOR_UP); + } + } + keyQueue.push(interface_key::SELECT); + return CR_OK; } \ No newline at end of file diff --git a/plugins/remotefortressreader/adventure_control.h b/plugins/remotefortressreader/adventure_control.h index f4d912019..c84fe9722 100644 --- a/plugins/remotefortressreader/adventure_control.h +++ b/plugins/remotefortressreader/adventure_control.h @@ -5,5 +5,8 @@ #include "AdventureControl.pb.h" DFHack::command_result MoveCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); +DFHack::command_result JumpCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); +void KeyUpdate(); + #endif // !ADVENTURE_CONTROL_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 8eae24adb..8ebb75d79 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -234,6 +234,8 @@ command_result RemoteFortressReader_version(color_ostream &out, vector & return CR_OK; } +DFHACK_PLUGIN_IS_ENABLED(enableUpdates); + // Mandatory init function. If you have some global state, create it here. DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { @@ -248,7 +250,8 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); - return svc; + svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. @@ -300,6 +304,14 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) return CR_OK; } +DFhackCExport command_result plugin_onupdate(color_ostream &out) +{ + if (!enableUpdates) + return CR_OK; + KeyUpdate(); + return CR_OK; +} + uint16_t fletcher16(uint8_t const *data, size_t bytes) { uint16_t sum1 = 0xff, sum2 = 0xff; From 9adeeaeba1ef55a33931c710a5f098803973b387 Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 25 Dec 2017 22:13:49 +0530 Subject: [PATCH 053/170] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index f04f55fea..9c3466336 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f04f55feaae9e234d88373cdf4491bde5fa346ef +Subproject commit 9c3466336acb74fa5bc55efaa02fbddb09a1541f From f5fc7fe1a1cf231b70252e6b364a3d9c4fe57794 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 26 Dec 2017 00:08:05 +0530 Subject: [PATCH 054/170] Report the current adventure mode menu back to Armok Vision, currently including careful movement options. --- plugins/proto/AdventureControl.proto | 64 +++ .../adventure_control.cpp | 427 ++++++++++-------- .../remotefortressreader/adventure_control.h | 1 + .../remotefortressreader.cpp | 6 +- 4 files changed, 308 insertions(+), 190 deletions(-) diff --git a/plugins/proto/AdventureControl.proto b/plugins/proto/AdventureControl.proto index 4db1afdf7..3bef8d939 100644 --- a/plugins/proto/AdventureControl.proto +++ b/plugins/proto/AdventureControl.proto @@ -5,7 +5,71 @@ option optimize_for = LITE_RUNTIME; import "RemoteFortressReader.proto"; +enum AdvmodeMenu +{ + Default = 0; + Look = 1; + ConversationAddress = 2; + ConversationSelect = 3; + ConversationSpeak = 4; + Inventory = 5; + Drop = 6; + ThrowItem = 7; + Wear = 8; + Remove = 9; + Interact = 10; + Put = 11; + PutContainer = 12; + Eat = 13; + ThrowAim = 14; + Fire = 15; + Get = 16; + Unk17 = 17; + CombatPrefs = 18; + Companions = 19; + MovementPrefs = 20; + SpeedPrefs = 21; + InteractAction = 22; + MoveCarefully = 23; + Announcements = 24; + UseBuilding = 25; + Travel = 26; + Unk27 = 27; + Unk28 = 28; + SleepConfirm = 29; + SelectInteractionTarget = 30; + Unk31 = 31; + Unk32 = 32; + FallAction = 33; + ViewTracks = 34; + Jump = 35; + Unk36 = 36; + AttackConfirm = 37; + AttackType = 38; + AttackBodypart = 39; + AttackStrike = 40; + Unk41 = 41; + Unk42 = 42; + DodgeDirection = 43; + Unk44 = 44; + Unk45 = 45; + Build = 46; +} + message MoveCommandParams { optional RemoteFortressReader.Coord direction = 1; +} + +message MovementOption +{ + optional RemoteFortressReader.Coord dest = 1; + optional RemoteFortressReader.Coord source = 2; + optional RemoteFortressReader.Coord grab = 3; +} + +message MenuContents +{ + optional AdvmodeMenu current_menu = 1; + repeated MovementOption movements = 2; } \ No newline at end of file diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index 6e717ebd1..c3c2933ce 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -1,6 +1,13 @@ #include "adventure_control.h" #include "DataDefs.h" +#include "df/adventure_movement_attack_creaturest.h" +#include "df/adventure_movement_building_interactst.h" +#include "df/adventure_movement_climbst.h" +#include "df/adventure_movement_hold_itemst.h" +#include "df/adventure_movement_hold_tilest.h" +#include "df/adventure_movement_optionst.h" +#include "df/ui_advmode.h" #include "df/viewscreen.h" #include "modules/Gui.h" @@ -16,198 +23,242 @@ std::queue keyQueue; void KeyUpdate() { - if (!keyQueue.empty()) - { - getCurViewscreen()->feed_key(keyQueue.front()); - keyQueue.pop(); - } + if (!keyQueue.empty()) + { + getCurViewscreen()->feed_key(keyQueue.front()); + keyQueue.pop(); + } +} + +void SetCoord(df::coord in, RemoteFortressReader::Coord *out) +{ + out->set_x(in.x); + out->set_y(in.y); + out->set_z(in.z); } command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) { - auto viewScreen = getCurViewscreen(); - if (!in->has_direction()) - return CR_WRONG_USAGE; - auto dir = in->direction(); - switch (dir.x()) - { - case -1: - switch (dir.y()) - { - case -1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_NW_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_NW); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_NW_UP); - break; - } - break; - case 0: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_W_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_W); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_W_UP); - break; - } - break; - case 1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_SW_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_SW); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_SW_UP); - break; - } - break; - } - break; - case 0: - switch (dir.y()) - { - case -1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_N_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_N); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_N_UP); - break; - } - break; - case 0: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_DOWN); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_UP); - break; - } - break; - case 1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_S_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_S); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_S_UP); - break; - } - break; - } - break; - case 1: - switch (dir.y()) - { - case -1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_NE_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_NE); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_NE_UP); - break; - } - break; - case 0: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_E_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_E); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_E_UP); - break; - } - break; - case 1: - switch (dir.z()) - { - case -1: - viewScreen->feed_key(interface_key::A_MOVE_SE_DOWN); - break; - case 0: - viewScreen->feed_key(interface_key::A_MOVE_SE); - break; - case 1: - viewScreen->feed_key(interface_key::A_MOVE_SE_UP); - break; - } - break; - } - break; - } - return CR_OK; + auto viewScreen = getCurViewscreen(); + if (!in->has_direction()) + return CR_WRONG_USAGE; + if (!df::global::ui_advmode->menu == ui_advmode_menu::Default) + return CR_OK; + auto dir = in->direction(); + switch (dir.x()) + { + case -1: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_NW_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_NW); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_NW_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_W_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_W); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_W_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_SW_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_SW); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_SW_UP); + break; + } + break; + } + break; + case 0: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_N_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_N); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_N_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_DOWN); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_S_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_S); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_S_UP); + break; + } + break; + } + break; + case 1: + switch (dir.y()) + { + case -1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_NE_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_NE); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_NE_UP); + break; + } + break; + case 0: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_E_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_E); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_E_UP); + break; + } + break; + case 1: + switch (dir.z()) + { + case -1: + viewScreen->feed_key(interface_key::A_MOVE_SE_DOWN); + break; + case 0: + viewScreen->feed_key(interface_key::A_MOVE_SE); + break; + case 1: + viewScreen->feed_key(interface_key::A_MOVE_SE_UP); + break; + } + break; + } + break; + } + return CR_OK; } command_result JumpCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) { - if (!in->has_direction()) - return CR_WRONG_USAGE; - auto dir = in->direction(); - keyQueue.push(interface_key::A_JUMP); - int x = dir.x(); - int y = dir.y(); - if (x > 0) - { - for (int i = 0; i < x; i++) - { - keyQueue.push(interface_key::CURSOR_RIGHT); - } - } - if (x < 0) - { - for (int i = 0; i > x; i--) - { - keyQueue.push(interface_key::CURSOR_LEFT); - } - } - if (y > 0) - { - for (int i = 0; i < y; i++) - { - keyQueue.push(interface_key::CURSOR_DOWN); - } - } - if (y < 0) - { - for (int i = 0; i > y; i--) - { - keyQueue.push(interface_key::CURSOR_UP); - } - } - keyQueue.push(interface_key::SELECT); - return CR_OK; -} \ No newline at end of file + if (!in->has_direction()) + return CR_WRONG_USAGE; + if (!df::global::ui_advmode->menu == ui_advmode_menu::Default) + return CR_OK; + auto dir = in->direction(); + keyQueue.push(interface_key::A_JUMP); + int x = dir.x(); + int y = dir.y(); + if (x > 0) + { + for (int i = 0; i < x; i++) + { + keyQueue.push(interface_key::CURSOR_RIGHT); + } + } + if (x < 0) + { + for (int i = 0; i > x; i--) + { + keyQueue.push(interface_key::CURSOR_LEFT); + } + } + if (y > 0) + { + for (int i = 0; i < y; i++) + { + keyQueue.push(interface_key::CURSOR_DOWN); + } + } + if (y < 0) + { + for (int i = 0; i > y; i--) + { + keyQueue.push(interface_key::CURSOR_UP); + } + } + keyQueue.push(interface_key::SELECT); + return CR_OK; +} + +command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, MenuContents *out) +{ + auto advUi = df::global::ui_advmode; + + if (advUi == NULL) + return CR_FAILURE; + + out->set_current_menu((AdvmodeMenu)advUi->menu); + + switch (advUi->menu) + { + case ui_advmode_menu::MoveCarefully: + for (size_t i = 0; i < advUi->movements.size(); i++) + { + auto movement = advUi->movements[i]; + auto send_movement = out->add_movements(); + SetCoord(movement->source, send_movement->mutable_source()); + SetCoord(movement->dest, send_movement->mutable_dest()); + + STRICT_VIRTUAL_CAST_VAR(climbMovement, df::adventure_movement_climbst, movement); + if (climbMovement) + SetCoord(climbMovement->grab, send_movement->mutable_grab()); + STRICT_VIRTUAL_CAST_VAR(holdTileMovement, df::adventure_movement_hold_tilest, movement); + if (holdTileMovement) + SetCoord(holdTileMovement->grab, send_movement->mutable_grab()); + } + default: + break; + } + + return CR_OK; +} diff --git a/plugins/remotefortressreader/adventure_control.h b/plugins/remotefortressreader/adventure_control.h index c84fe9722..16d30aeee 100644 --- a/plugins/remotefortressreader/adventure_control.h +++ b/plugins/remotefortressreader/adventure_control.h @@ -6,6 +6,7 @@ DFHack::command_result MoveCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); DFHack::command_result JumpCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); +DFHack::command_result MenuQuery(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, AdventureControl::MenuContents *out); void KeyUpdate(); diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 8ebb75d79..ae392c7c1 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -130,6 +130,7 @@ REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(gamemode); +REQUIRE_GLOBAL(ui_advmode); #endif // Here go all the command declarations... @@ -291,8 +292,9 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); - svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); - return svc; + svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); + svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. From e6651171bfb19404376cbf2ed6d4a0afd046cccb Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 14:40:06 -0500 Subject: [PATCH 055/170] json: Improve IO-related error messages --- library/lua/json.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/lua/json.lua b/library/lua/json.lua index ac7aa6327..2b4b3a66a 100644 --- a/library/lua/json.lua +++ b/library/lua/json.lua @@ -21,6 +21,9 @@ function encode_file(data, path, ...) end local contents = encode(data, ...) local f = io.open(path, 'w') + if not f then + error('Could not write to ' .. tostring(path)) + end f:write(contents) f:close() end @@ -32,7 +35,7 @@ end function decode_file(path, ...) local f = io.open(path) if not f then - error('Could not open ' .. path) + error('Could not read from ' .. tostring(path)) end local contents = f:read('*all') f:close() From 0332a5c25aec0614d08d520923ec63132a583dba Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 20:13:15 -0500 Subject: [PATCH 056/170] Replace a call to abort() with a VTableMissing exception This makes some scripts crash less when the viewscreen vtable is unavailable, for example. --- library/DataDefs.cpp | 3 ++- library/LuaTypes.cpp | 9 +++++++++ library/MiscUtils.cpp | 4 ++++ library/include/Error.h | 8 ++++++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index c9586fcc0..ab50eb942 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -36,6 +36,7 @@ distribution. #include "DataDefs.h" #include "DataIdentity.h" #include "VTableInterpose.h" +#include "Error.h" #include "MiscUtils.h" @@ -310,7 +311,7 @@ void virtual_identity::adjust_vtable(virtual_ptr obj, virtual_identity *main) return; std::cerr << "Attempt to create class '" << getName() << "' without known vtable." << std::endl; - abort(); + throw DFHack::Error::VTableMissing(getName()); } virtual_ptr virtual_identity::clone(virtual_ptr obj) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 6e3c5d5cf..f30a1878e 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1086,6 +1086,11 @@ int LuaWrapper::method_wrapper_core(lua_State *state, function_identity_base *id std::string tmp = stl_sprintf("Invalid argument; expected: %s", vn ? vn : "?"); field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); } + catch (Error::VTableMissing &e) { + const char *cn = e.name(); + std::string tmp = stl_sprintf("Missing vtable address: %s", cn ? cn : "?"); + field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); + } catch (std::exception &e) { std::string tmp = stl_sprintf("C++ exception: %s", e.what()); field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); @@ -1110,6 +1115,10 @@ int Lua::CallWithCatch(lua_State *state, int (*fn)(lua_State*), const char *cont const char *vn = e.expr(); return luaL_error(state, "%s: Invalid argument; expected: %s", context, vn ? vn : "?"); } + catch (Error::VTableMissing &e) { + const char *cn = e.name(); + return luaL_error(state, "%s: Missing vtable address: %s", context, cn ? cn : "?"); + } catch (std::exception &e) { return luaL_error(state, "%s: C++ exception: %s", context, e.what()); } diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index a6bb4b412..bff7f07e1 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -49,6 +49,10 @@ const char *DFHack::Error::InvalidArgument::what() const throw() { return "DFHack::Error::InvalidArgument"; } +const char *DFHack::Error::VTableMissing::what() const throw() { + return "DFHack::Error::VTableMissing"; +} + std::string stl_sprintf(const char *fmt, ...) { va_list lst; va_start(lst, fmt); diff --git a/library/include/Error.h b/library/include/Error.h index 6b4781028..2d0baadfc 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -75,6 +75,14 @@ namespace DFHack #define CHECK_INVALID_ARGUMENT(expr) \ { if (!(expr)) throw DFHack::Error::InvalidArgument(#expr); } + class DFHACK_EXPORT VTableMissing : public All { + const char *name_; + public: + VTableMissing(const char *name_ = NULL) : name_(name_) {} + const char *name() const { return name_; } + virtual const char *what() const throw(); + }; + class DFHACK_EXPORT AllSymbols : public All{}; // Syntax errors and whatnot, the xml can't be read From 4d5c7c59273638d3593cadab2e7167cfbbfcd708 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 20:14:11 -0500 Subject: [PATCH 057/170] getKeyDisplay: use enabler::GetKeyDisplay() --- library/modules/Screen.cpp | 28 ---------------------------- library/xml | 2 +- 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 06faf610f..96f385d8d 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -372,12 +372,6 @@ bool Screen::hasActiveScreens(Plugin *plugin) } #ifdef _LINUX -// Link to the libgraphics class directly: -class DFHACK_EXPORT enabler_inputst { - public: - std::string GetKeyDisplay(int binding); -}; - class DFHACK_EXPORT renderer { unsigned char *screen; long *screentexpos; @@ -418,15 +412,6 @@ public: virtual bool get_mouse_coords(int &x, int &y) { return false; } virtual bool uses_opengl(); }; -#else -struct less_sz { - bool operator() (const string &a, const string &b) const { - if (a.size() < b.size()) return true; - if (a.size() > b.size()) return false; - return a < b; - } -}; -static std::map > *keydisplay = NULL; #endif void init_screen_module(Core *core) @@ -435,26 +420,13 @@ void init_screen_module(Core *core) renderer tmp; if (!strict_virtual_cast((virtual_ptr)&tmp)) cerr << "Could not fetch the renderer vtable." << std::endl; -#else - if (!core->vinfo->getAddress("keydisplay", keydisplay)) - keydisplay = NULL; #endif } string Screen::getKeyDisplay(df::interface_key key) { -#ifdef _LINUX - auto enabler = (enabler_inputst*)df::global::enabler; if (enabler) return enabler->GetKeyDisplay(key); -#else - if (keydisplay) - { - auto it = keydisplay->find(key); - if (it != keydisplay->end() && !it->second.empty()) - return *it->second.begin(); - } -#endif return "?"; } diff --git a/library/xml b/library/xml index f04f55fea..559c23baa 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f04f55feaae9e234d88373cdf4491bde5fa346ef +Subproject commit 559c23baa06f68d62a0ba674669389273bfcfb97 From b9f6f3adc614e8fc58e725bf138983ac0cfd956d Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 20:14:18 -0500 Subject: [PATCH 058/170] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6934b9d47..a12daa56c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6934b9d47ccce5908395998133c14c91497f0935 +Subproject commit a12daa56cba2219153f4e974aa9217c888f6279c From 0eff9fa084da7602ed5dc3623f125f85f3140742 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 22:48:54 -0500 Subject: [PATCH 059/170] Bump version to 0.44.03-alpha1 and update submodules --- CMakeLists.txt | 4 ++-- library/xml | 2 +- scripts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e47a12d6..5672eaab7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,8 +140,8 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.44.02") -SET(DFHACK_RELEASE "beta1") +set(DF_VERSION "0.44.03") +SET(DFHACK_RELEASE "alpha1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/xml b/library/xml index 559c23baa..71ac8d257 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 559c23baa06f68d62a0ba674669389273bfcfb97 +Subproject commit 71ac8d257fe05a6b161adf933796a9721b7890fd diff --git a/scripts b/scripts index a12daa56c..33169f442 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a12daa56cba2219153f4e974aa9217c888f6279c +Subproject commit 33169f44258188dddfae3775e8cee0d06b4e209e From 11c60424166074409f64bb28b398b8aa3cfa9d16 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 25 Dec 2017 23:01:42 -0500 Subject: [PATCH 060/170] Update NEWS-dev --- docs/NEWS-dev.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index e44bdf96c..6bed2e344 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,15 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.03-alpha1 +===================== + +Other Changes +------------- +- Lua: Improved ``json`` I/O error messages +- Lua: Stopped a crash when trying to create instances of classes whose vtable + addresses are not available + DFHack 0.44.02-beta1 ==================== From e9e5113ff7a29500301879628cbc6816c956b1b3 Mon Sep 17 00:00:00 2001 From: Japa Mala Illo Date: Tue, 26 Dec 2017 12:34:46 +0530 Subject: [PATCH 061/170] Add careful movement type to proto. Not used yet. --- plugins/proto/AdventureControl.proto | 112 ++++++++++-------- .../adventure_control.cpp | 16 +++ .../remotefortressreader/adventure_control.h | 2 + .../remotefortressreader.cpp | 5 +- 4 files changed, 86 insertions(+), 49 deletions(-) diff --git a/plugins/proto/AdventureControl.proto b/plugins/proto/AdventureControl.proto index 3bef8d939..9c41fdfad 100644 --- a/plugins/proto/AdventureControl.proto +++ b/plugins/proto/AdventureControl.proto @@ -7,53 +7,70 @@ import "RemoteFortressReader.proto"; enum AdvmodeMenu { - Default = 0; - Look = 1; - ConversationAddress = 2; - ConversationSelect = 3; - ConversationSpeak = 4; - Inventory = 5; - Drop = 6; - ThrowItem = 7; - Wear = 8; - Remove = 9; - Interact = 10; - Put = 11; - PutContainer = 12; - Eat = 13; - ThrowAim = 14; - Fire = 15; - Get = 16; - Unk17 = 17; - CombatPrefs = 18; - Companions = 19; - MovementPrefs = 20; - SpeedPrefs = 21; - InteractAction = 22; - MoveCarefully = 23; - Announcements = 24; - UseBuilding = 25; - Travel = 26; - Unk27 = 27; - Unk28 = 28; - SleepConfirm = 29; - SelectInteractionTarget = 30; - Unk31 = 31; - Unk32 = 32; - FallAction = 33; - ViewTracks = 34; - Jump = 35; - Unk36 = 36; - AttackConfirm = 37; - AttackType = 38; - AttackBodypart = 39; - AttackStrike = 40; - Unk41 = 41; - Unk42 = 42; - DodgeDirection = 43; - Unk44 = 44; - Unk45 = 45; - Build = 46; + Default = 0; + Look = 1; + ConversationAddress = 2; + ConversationSelect = 3; + ConversationSpeak = 4; + Inventory = 5; + Drop = 6; + ThrowItem = 7; + Wear = 8; + Remove = 9; + Interact = 10; + Put = 11; + PutContainer = 12; + Eat = 13; + ThrowAim = 14; + Fire = 15; + Get = 16; + Unk17 = 17; + CombatPrefs = 18; + Companions = 19; + MovementPrefs = 20; + SpeedPrefs = 21; + InteractAction = 22; + MoveCarefully = 23; + Announcements = 24; + UseBuilding = 25; + Travel = 26; + Unk27 = 27; + Unk28 = 28; + SleepConfirm = 29; + SelectInteractionTarget = 30; + Unk31 = 31; + Unk32 = 32; + FallAction = 33; + ViewTracks = 34; + Jump = 35; + Unk36 = 36; + AttackConfirm = 37; + AttackType = 38; + AttackBodypart = 39; + AttackStrike = 40; + Unk41 = 41; + Unk42 = 42; + DodgeDirection = 43; + Unk44 = 44; + Unk45 = 45; + Build = 46; +} + +enum CarefulMovementType +{ + DEFAULT_MOVEMENT = 0; + RELEASE_ITEM_HOLD = 1; + RELEASE_TILE_HOLD = 2; + ATTACK_CREATURE = 3; + HOLD_TILE = 4; + MOVE = 5; + CLIMB = 6; + HOLD_ITEM = 7; + BUILDING_INTERACT = 8; + ITEM_INTERACT = 9; + ITEM_INTERACT_GUIDE = 10; + ITEM_INTERACT_RIDE = 11; + ITEM_INTERACT_PUSH = 12; } message MoveCommandParams @@ -66,6 +83,7 @@ message MovementOption optional RemoteFortressReader.Coord dest = 1; optional RemoteFortressReader.Coord source = 2; optional RemoteFortressReader.Coord grab = 3; + optional CarefulMovementType movement_type = 4; } message MenuContents diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index c3c2933ce..971869ac4 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -188,6 +188,7 @@ command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParam } return CR_OK; } + command_result JumpCommand(DFHack::color_ostream &stream, const MoveCommandParams *in) { if (!in->has_direction()) @@ -262,3 +263,18 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, return CR_OK; } + +command_result MovementSelectCommand(DFHack::color_ostream &stream, const dfproto::IntMessage *in) +{ + if (!(df::global::ui_advmode->menu == ui_advmode_menu::MoveCarefully)) + return CR_OK; + int choice = in->value(); + int page = choice / 5; + int select = choice % 5; + for (int i = 0; i < page; i++) + { + keyQueue.push(interface_key::SECONDSCROLL_PAGEDOWN); + } + keyQueue.push((interface_key::interface_key)(interface_key::OPTION1 + select)); + return CR_OK; +} diff --git a/plugins/remotefortressreader/adventure_control.h b/plugins/remotefortressreader/adventure_control.h index 16d30aeee..b01558047 100644 --- a/plugins/remotefortressreader/adventure_control.h +++ b/plugins/remotefortressreader/adventure_control.h @@ -7,6 +7,8 @@ DFHack::command_result MoveCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); DFHack::command_result JumpCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); DFHack::command_result MenuQuery(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, AdventureControl::MenuContents *out); +DFHack::command_result MovementSelectCommand(DFHack::color_ostream &stream, const dfproto::IntMessage *in); + void KeyUpdate(); diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index ae392c7c1..71f519680 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -293,8 +293,9 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); - svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); - return svc; + svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); + svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. From cdfe1cf1c7b088ab71304b5980c9dfe00af290a7 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 26 Dec 2017 22:21:36 +0530 Subject: [PATCH 062/170] add a few more hotkeys to adventure control --- plugins/proto/AdventureControl.proto | 12 ++++ .../adventure_control.cpp | 58 +++++++++++++++++++ .../remotefortressreader/adventure_control.h | 1 + .../remotefortressreader.cpp | 5 +- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/plugins/proto/AdventureControl.proto b/plugins/proto/AdventureControl.proto index 9c41fdfad..a5785d7a3 100644 --- a/plugins/proto/AdventureControl.proto +++ b/plugins/proto/AdventureControl.proto @@ -73,6 +73,13 @@ enum CarefulMovementType ITEM_INTERACT_PUSH = 12; } +enum MiscMoveType +{ + SET_CLIMB = 0; + SET_STAND = 1; + SET_CANCEL = 2; +} + message MoveCommandParams { optional RemoteFortressReader.Coord direction = 1; @@ -90,4 +97,9 @@ message MenuContents { optional AdvmodeMenu current_menu = 1; repeated MovementOption movements = 2; +} + +message MiscMoveParams +{ + optional MiscMoveType type = 1; } \ No newline at end of file diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index 971869ac4..1e1f26452 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -240,6 +240,33 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, out->set_current_menu((AdvmodeMenu)advUi->menu); +// /$$$$$$$$ /$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$$$ +//| $$_____/|_ $$_/| $$ / $$| $$$ /$$$| $$_____/ +//| $$ | $$ | $$/ $$/| $$$$ /$$$$| $$ +//| $$$$$ | $$ \ $$$$/ | $$ $$/$$ $$| $$$$$ +//| $$__/ | $$ >$$ $$ | $$ $$$| $$| $$__/ +//| $$ | $$ /$$/\ $$| $$\ $ | $$| $$ +//| $$ /$$$$$$| $$ \ $$| $$ \/ | $$| $$$$$$$$ +//|__/ |______/|__/ |__/|__/ |__/|________/ +// +// +// +// /$$$$$$$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ +//|__ $$__/| $$ |__/ |__/ | $$ |__/ | $$ | $$ | $$ +// | $$ | $$$$$$$ /$$ /$$$$$$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$ /$$$$$$$ | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$ +// | $$ | $$__ $$| $$ /$$_____/ | $$ /$$_____/ |____ $$ /$$_____/|_ $$_/ | $$ | $$ /$$__ $$| $$ /$$__ $$ | $$__ $$ |____ $$ /$$_____/| $$ /$$/ +// | $$ | $$ \ $$| $$| $$$$$$ | $$| $$$$$$ /$$$$$$$ | $$$$$$ | $$ | $$ | $$| $$ \ $$| $$| $$ | $$ | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ +// | $$ | $$ | $$| $$ \____ $$ | $$ \____ $$ /$$__ $$ \____ $$ | $$ /$$| $$ | $$| $$ | $$| $$| $$ | $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ +// | $$ | $$ | $$| $$ /$$$$$$$/ | $$ /$$$$$$$/ | $$$$$$$ /$$$$$$$/ | $$$$/| $$$$$$/| $$$$$$$/| $$| $$$$$$$ | $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ +// |__/ |__/ |__/|__/|_______/ |__/|_______/ \_______/ |_______/ \___/ \______/ | $$____/ |__/ \_______/ |__/ |__/ \_______/ \_______/|__/ \__/ +// | $$ +// | $$ +// |__/ + if (advUi->menu == ui_advmode_menu::FallAction) + { + getCurViewscreen()->feed_key(interface_key::OPTION1); + } + switch (advUi->menu) { case ui_advmode_menu::MoveCarefully: @@ -252,10 +279,16 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, STRICT_VIRTUAL_CAST_VAR(climbMovement, df::adventure_movement_climbst, movement); if (climbMovement) + { SetCoord(climbMovement->grab, send_movement->mutable_grab()); + send_movement->set_movement_type(CarefulMovementType::CLIMB); + } STRICT_VIRTUAL_CAST_VAR(holdTileMovement, df::adventure_movement_hold_tilest, movement); if (holdTileMovement) + { SetCoord(holdTileMovement->grab, send_movement->mutable_grab()); + send_movement->set_movement_type(CarefulMovementType::HOLD_TILE); + } } default: break; @@ -278,3 +311,28 @@ command_result MovementSelectCommand(DFHack::color_ostream &stream, const dfprot keyQueue.push((interface_key::interface_key)(interface_key::OPTION1 + select)); return CR_OK; } + +command_result MiscMoveCommand(DFHack::color_ostream &stream, const MiscMoveParams *in) +{ + if (!df::global::ui_advmode->menu == ui_advmode_menu::Default) + return CR_OK; + + auto type = in->type(); + + switch (type) + { + case AdventureControl::SET_CLIMB: + getCurViewscreen()->feed_key(interface_key::A_HOLD); + break; + case AdventureControl::SET_STAND: + getCurViewscreen()->feed_key(interface_key::A_STANCE); + break; + case AdventureControl::SET_CANCEL: + getCurViewscreen()->feed_key(interface_key::LEAVESCREEN); + break; + default: + break; + } + + return CR_OK; +} diff --git a/plugins/remotefortressreader/adventure_control.h b/plugins/remotefortressreader/adventure_control.h index b01558047..bc674e427 100644 --- a/plugins/remotefortressreader/adventure_control.h +++ b/plugins/remotefortressreader/adventure_control.h @@ -8,6 +8,7 @@ DFHack::command_result MoveCommand(DFHack::color_ostream &stream, const Adventur DFHack::command_result JumpCommand(DFHack::color_ostream &stream, const AdventureControl::MoveCommandParams *in); DFHack::command_result MenuQuery(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, AdventureControl::MenuContents *out); DFHack::command_result MovementSelectCommand(DFHack::color_ostream &stream, const dfproto::IntMessage *in); +DFHack::command_result MiscMoveCommand(DFHack::color_ostream &stream, const AdventureControl::MiscMoveParams *in); void KeyUpdate(); diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 71f519680..118e0704e 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -294,8 +294,9 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); - svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE); - return svc; + svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE); + svc->addFunction("MiscMoveCommand", MiscMoveCommand, SF_ALLOW_REMOTE); + return svc; } // This is called right before the plugin library is removed from memory. From 7288f95c51f3e1841e875f7a13165bd386050fc0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Dec 2017 12:52:18 -0500 Subject: [PATCH 063/170] Update NEWS.rst too --- NEWS.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 66963fff2..07267a8ab 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -75,6 +75,9 @@ Lua - Added a new ``dfhack.console`` API - Exposed ``get_vector()`` (from C++) for all types that support ``find()``, e.g. ``df.unit.get_vector() == df.global.world.units.all`` +- Improved ``json`` I/O error messages +- Stopped a crash when trying to create instances of classes whose vtable + addresses are not available DFHack 0.43.05-r3 From 4007c394384ebce6bdfeadb5dc48568ff41dbcdc Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Dec 2017 12:54:08 -0500 Subject: [PATCH 064/170] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 71ac8d257..f713075c4 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 71ac8d257fe05a6b161adf933796a9721b7890fd +Subproject commit f713075c4dab5e3d8af475a8cf0f3be026f94d53 From 8123736de7bc3c87583ea0367696c2e477d3e6d7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Dec 2017 20:36:27 -0500 Subject: [PATCH 065/170] Update Authors (dfhack/scripts#27) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 4223fb5ee..0f7e06811 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -17,6 +17,7 @@ AndreasPK AndreasPK Angus Mezick amezick Antalia tamarakorr Anuradha Dissanayake falconne +Atkana Atkana AtomicChicken AtomicChicken belal jimhester Ben Lubar BenLubar From 94e6e89b3154380ec71d4cf8350f57e5ea2ce710 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 26 Dec 2017 20:36:37 -0500 Subject: [PATCH 066/170] Update xml, scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index f713075c4..24bd450fd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f713075c4dab5e3d8af475a8cf0f3be026f94d53 +Subproject commit 24bd450fdabe8be6483ad73f1355c0fd30571b05 diff --git a/scripts b/scripts index 33169f442..78904a56d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 33169f44258188dddfae3775e8cee0d06b4e209e +Subproject commit 78904a56d41082e433b4c2e9f4983702f2a9bced From d7ea397ab27698c44d93db3433556ac3b200ae4c Mon Sep 17 00:00:00 2001 From: Japa Mala Illo Date: Wed, 27 Dec 2017 11:15:40 +0530 Subject: [PATCH 067/170] update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 9c3466336..24bd450fd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9c3466336acb74fa5bc55efaa02fbddb09a1541f +Subproject commit 24bd450fdabe8be6483ad73f1355c0fd30571b05 From e72474613ffa5f59e612594046d569a7c46feedb Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Dec 2017 13:48:53 -0500 Subject: [PATCH 068/170] Add new PutItemOnDisplay job to labor management plugins Also add building_type::DisplayFurniture to labormanager Fixes #1208 --- library/xml | 2 +- plugins/autohauler.cpp | 3 ++- plugins/autolabor.cpp | 3 ++- plugins/labormanager/joblabormapper.cpp | 5 ++++- plugins/labormanager/labormanager.cpp | 3 ++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/library/xml b/library/xml index 24bd450fd..301807985 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 24bd450fdabe8be6483ad73f1355c0fd30571b05 +Subproject commit 301807985eefb4db88416a0f5a7f7b94aadfb667 diff --git a/plugins/autohauler.cpp b/plugins/autohauler.cpp index 7a3f8a3d8..62914c784 100644 --- a/plugins/autohauler.cpp +++ b/plugins/autohauler.cpp @@ -405,7 +405,8 @@ static const dwarf_state dwarf_states[] = { BUSY /* MakeRing */, BUSY /* MakeEarring */, BUSY /* MakeBracelet */, - BUSY /* MakeGem */ + BUSY /* MakeGem */, + BUSY /* PutItemOnDisplay */, }; // Mode assigned to labors. Either it's a hauling job, or it's not. diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index 95863ffb5..a894a2891 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -373,7 +373,8 @@ static const dwarf_state dwarf_states[] = { BUSY /* MakeRing */, BUSY /* MakeEarring */, BUSY /* MakeBracelet */, - BUSY /* MakeGem */ + BUSY /* MakeGem */, + BUSY /* PutItemOnDisplay */, }; struct labor_info diff --git a/plugins/labormanager/joblabormapper.cpp b/plugins/labormanager/joblabormapper.cpp index 051331137..d16bfafcf 100644 --- a/plugins/labormanager/joblabormapper.cpp +++ b/plugins/labormanager/joblabormapper.cpp @@ -358,6 +358,7 @@ public: case df::building_type::GrateWall: case df::building_type::Bookcase: case df::building_type::Instrument: + case df::building_type::DisplayFurniture: return df::unit_labor::HAUL_FURNITURE; case df::building_type::Trap: case df::building_type::GearAssembly: @@ -463,6 +464,7 @@ public: case df::building_type::GrateWall: case df::building_type::Bookcase: case df::building_type::Instrument: + case df::building_type::DisplayFurniture: return df::unit_labor::HAUL_FURNITURE; case df::building_type::AnimalTrap: return df::unit_labor::TRAPPER; @@ -882,6 +884,7 @@ JobLaborMapper::JobLaborMapper() job_to_labor_table[df::job_type::MakeEarring] = jlf_make_object; job_to_labor_table[df::job_type::MakeBracelet] = jlf_make_object; job_to_labor_table[df::job_type::MakeGem] = jlf_make_object; + job_to_labor_table[df::job_type::PutItemOnDisplay] = jlf_const(df::unit_labor::HAUL_ITEM); job_to_labor_table[df::job_type::StoreItemInLocation] = jlf_no_labor; // StoreItemInLocation }; @@ -917,4 +920,4 @@ df::unit_labor JobLaborMapper::find_job_labor(df::job* j) return labor; } -/* End of labor deducer */ \ No newline at end of file +/* End of labor deducer */ diff --git a/plugins/labormanager/labormanager.cpp b/plugins/labormanager/labormanager.cpp index 3a026d1ea..42e718488 100644 --- a/plugins/labormanager/labormanager.cpp +++ b/plugins/labormanager/labormanager.cpp @@ -377,7 +377,8 @@ static const dwarf_state dwarf_states[] = { BUSY /* MakeRing */, BUSY /* MakeEarring */, BUSY /* MakeBracelet */, - BUSY /* MakeGem */ + BUSY /* MakeGem */, + BUSY /* PutItemOnDisplay */, }; struct labor_info From a3a0ed03a384fc311bc5031c1d7e7e786a60ff38 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 27 Dec 2017 13:50:02 -0500 Subject: [PATCH 069/170] Update scripts (gui/gm-editor) --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 78904a56d..92ea8f43e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 78904a56d41082e433b4c2e9f4983702f2a9bced +Subproject commit 92ea8f43ef7ace7e609a83e061d18ddbcf1f56e2 From fde1e284f4822491b3d07202585c59ac487a6e79 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 28 Dec 2017 16:19:45 -0500 Subject: [PATCH 070/170] Gui::getAnyItem: support viewscreen_assign_display_itemst --- library/modules/Gui.cpp | 10 ++++++++++ library/xml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 0631e0ed7..d6eedcef7 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -74,6 +74,7 @@ using namespace DFHack; #include "df/ui_unit_view_mode.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/viewscreen_assign_display_itemst.h" #include "df/viewscreen_buildinglistst.h" #include "df/viewscreen_dungeon_monsterstatusst.h" #include "df/viewscreen_dungeonmodest.h" @@ -1042,6 +1043,15 @@ df::item *Gui::getAnyItem(df::viewscreen *top) return NULL; } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_assign_display_itemst, top)) + { + if (screen->sel_column == df::viewscreen_assign_display_itemst::T_sel_column::Items) + return vector_get(screen->items[screen->item_type[screen->sel_type]], + screen->sel_item); + + return NULL; + } + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) return dfscreen->getSelectedItem(); diff --git a/library/xml b/library/xml index 301807985..1297be014 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 301807985eefb4db88416a0f5a7f7b94aadfb667 +Subproject commit 1297be0141c7116e677e19a9ddcad296ae31de7d From 3f45ba4e5dbb169b3a8e176bbe5d066c7bbec92a Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Dec 2017 23:36:43 -0500 Subject: [PATCH 071/170] Update changelogs --- NEWS.rst | 6 ++++++ docs/NEWS-dev.rst | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 07267a8ab..abecc0900 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -63,7 +63,13 @@ Misc Improvements - `gui/gm-editor`: added enum names to enum edit dialogs - `gui/gm-unit`: made skill search case-insensitive +- `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options +- `modtools/skill-change`: + + - now updates skill levels appropriately + - only prints output if ``-loud`` is passed + - `remotefortressreader`: includes item stack sizes and some performance improvements Removed diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 6bed2e344..1d687f127 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,40 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.03-beta1 +==================== + +Fixes +----- +- `autolabor`, `autohauler`, `labormanager`: added support for "put item on + display" jobs and building/destroying display furniture +- `gui/gm-editor`: fixed an error when editing primitives in Lua tables + +Structures +---------- +- Added 7 new globals from DF: ``version``, ``min_load_version``, + ``movie_version``, ``basic_seed``, ``title``, ``title_spaced``, + ``ui_building_resize_radius`` +- Fixed an issue preventing ``enabler`` from being allocated by DFHack +- Added ``job_type.PutItemOnDisplay`` +- Found ``renderer`` vtable on osx64 +- ``adventure_movement_optionst``, ``adventure_movement_hold_tilest``, + ``adventure_movement_climbst``: named coordinate fields +- ``mission``: added type +- ``unit``: added 3 new vmethods: ``getCreatureTile``, ``getCorpseTile``, ``getGlowTile`` +- ``viewscreen_assign_display_itemst``: fixed layout on x64 and identified many fields +- ``viewscreen_reportlistst``: fixed layout, added ``mission_id`` vector +- ``world.status``: named ``missions`` vector + +Other Changes +------------- +- `devel/dump-offsets`: now ignores ``index`` globals +- `gui/pathable`: added tile types to sidebar +- `modtools/skill-change`: + + - now updates skill levels appropriately + - only prints output if ``-loud`` is passed + DFHack 0.44.03-alpha1 ===================== From 04523f9e5d57ddcf510a464e4152b098e525286f Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Dec 2017 23:40:55 -0500 Subject: [PATCH 072/170] dfhack/df-structures#231: twbt_render_map offset for x64 --- docs/NEWS-dev.rst | 1 + library/xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 1d687f127..771684884 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -51,6 +51,7 @@ Structures - Added 7 new globals from DF: ``version``, ``min_load_version``, ``movie_version``, ``basic_seed``, ``title``, ``title_spaced``, ``ui_building_resize_radius`` +- Added ``twbt_render_map`` code offset on x64 - Fixed an issue preventing ``enabler`` from being allocated by DFHack - Added ``job_type.PutItemOnDisplay`` - Found ``renderer`` vtable on osx64 diff --git a/library/xml b/library/xml index 1297be014..7e23a328f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1297be0141c7116e677e19a9ddcad296ae31de7d +Subproject commit 7e23a328fd81e3d6db794c0c18b8b2e7bd235649 From 677833eeaa784b8bfc9ddd9fae6b04176e4c35f3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 29 Dec 2017 23:41:47 -0500 Subject: [PATCH 073/170] Bump to 0.44.03-beta1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5672eaab7..9a1177549 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,7 +141,7 @@ endif() # set up versioning. set(DF_VERSION "0.44.03") -SET(DFHACK_RELEASE "alpha1") +SET(DFHACK_RELEASE "beta1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From fa39220777e01b365b8cada43cdf775dcf855f3c Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 31 Dec 2017 14:31:58 +0530 Subject: [PATCH 074/170] add projectiles, complete with velocity. --- library/xml | 2 +- plugins/proto/RemoteFortressReader.proto | 7 ++ .../remotefortressreader.cpp | 69 ++++++++++++++++--- 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/library/xml b/library/xml index 24bd450fd..7e23a328f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 24bd450fdabe8be6483ad73f1355c0fd30571b05 +Subproject commit 7e23a328fd81e3d6db794c0c18b8b2e7bd235649 diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index cb7acca07..623ab7f53 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -268,6 +268,13 @@ message Item optional MatPair material = 6; optional ColorDefinition dye = 7; optional int32 stack_size = 8; + optional float subpos_x = 9; + optional float subpos_y = 10; + optional float subpos_z = 11; + optional bool projectile = 12; + optional float velocity_x = 13; + optional float velocity_y = 14; + optional float velocity_z = 15; } message MapBlock diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 118e0704e..9c7263880 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -62,6 +62,7 @@ #include "df/item.h" #include "df/item_constructed.h" #include "df/item_threadst.h" +#include "df/item_toolst.h" #include "df/itemimprovement.h" #include "df/itemimprovement_threadst.h" #include "df/itemdef.h" @@ -77,6 +78,7 @@ #include "df/plant.h" #include "df/plant_raw_flags.h" #include "df/projectile.h" +#include "df/proj_itemst.h" #include "df/proj_unitst.h" #include "df/region_map_entry.h" #include "df/report.h" @@ -91,6 +93,7 @@ #include "df/ui.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/vehicle.h" #include "df/viewscreen_choose_start_sitest.h" #include "df/world.h" #include "df/world_data.h" @@ -1214,6 +1217,39 @@ void CopyDesignation(df::map_block * DfBlock, RemoteFortressReader::MapBlock * N #endif } +void CopyProjectiles(RemoteFortressReader::MapBlock * NetBlock) +{ + for (auto proj = world->proj_list.next; proj != NULL; proj = proj->next) + { + STRICT_VIRTUAL_CAST_VAR(projectile, df::proj_itemst, proj->item); + if (projectile == NULL) + continue; + auto NetItem = NetBlock->add_items(); + CopyItem(NetItem, projectile->item); + NetItem->set_projectile(true); + if (projectile->flags.bits.parabolic) + { + NetItem->set_subpos_x(projectile->pos_x / 100000.0); + NetItem->set_subpos_y(projectile->pos_y / 100000.0); + NetItem->set_subpos_z(projectile->pos_z / 140000.0); + NetItem->set_velocity_x(projectile->speed_x / 100000.0); + NetItem->set_velocity_y(projectile->speed_y / 100000.0); + NetItem->set_velocity_z(projectile->speed_z / 140000.0); + } + else + { + DFCoord diff = projectile->target_pos - projectile->origin_pos; + float max_dist = max(max(abs(diff.x), abs(diff.y)), abs(diff.z)); + NetItem->set_subpos_x(projectile->origin_pos.x + (diff.x / max_dist * projectile->distance_flown) - projectile->cur_pos.x); + NetItem->set_subpos_y(projectile->origin_pos.y + (diff.y / max_dist * projectile->distance_flown) - projectile->cur_pos.y); + NetItem->set_subpos_z(projectile->origin_pos.z + (diff.z / max_dist * projectile->distance_flown) - projectile->cur_pos.z); + NetItem->set_velocity_x(diff.x / max_dist); + NetItem->set_velocity_y(diff.y / max_dist); + NetItem->set_velocity_z(diff.z / max_dist); + } + } +} + void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC) { @@ -1327,6 +1363,24 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) auto type = NetItem->mutable_type(); type->set_mat_type(DfItem->getType()); type->set_mat_index(DfItem->getSubtype()); + + bool isProjectile = false; + + if (!isProjectile && DfItem->getType() == item_type::TOOL) + { + VIRTUAL_CAST_VAR(tool, df::item_toolst, DfItem); + if (tool) + { + auto vehicle = binsearch_in_vector(world->vehicles.active, tool->vehicle_id); + if (vehicle) + { + NetItem->set_subpos_x(vehicle->offset_x / 100000.0); + NetItem->set_subpos_y(vehicle->offset_y / 100000.0); + NetItem->set_subpos_z(vehicle->offset_z / 140000.0); + } + } + } + if (DfItem->getType() == item_type::BOX) { type->set_mat_index(DfItem->isBag()); @@ -1407,7 +1461,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in int max_y = in->max_y(); int min_z = in->min_z(); int max_z = in->max_z(); - bool sentBuildings = false; //Always send all the buildings needed on the first block, and none on the rest. + bool firstBlock = true; //Always send all the buildings needed on the first block, and none on the rest. //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); for (int zz = max_z - 1; zz >= min_z; zz--) { @@ -1440,16 +1494,14 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in || block->occupancy[xxx][yyy].bits.building > 0) nonAir++; } - if (nonAir > 0 || !sentBuildings) + if (nonAir > 0 || firstBlock) { bool tileChanged = IsTiletypeChanged(pos); bool desChanged = IsDesignationChanged(pos); bool spatterChanged = IsspatterChanged(pos); - bool buildingChanged = !sentBuildings; - bool itemsChanged = areItemsChanged(&block->items); - //bool bldChanged = IsBuildingChanged(pos); + bool itemsChanged = true; //simpler just to send the items every frame. RemoteFortressReader::MapBlock *net_block; - if (tileChanged || desChanged || spatterChanged || buildingChanged || itemsChanged) + if (tileChanged || desChanged || spatterChanged || firstBlock || itemsChanged) net_block = out->add_map_blocks(); if (tileChanged) { @@ -1458,10 +1510,11 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in } if (desChanged) CopyDesignation(block, net_block, &MC, pos); - if (buildingChanged) + if (firstBlock) { CopyBuildings(DFCoord(min_x * 16, min_y * 16, min_z), DFCoord(max_x * 16, max_y * 16, max_z), net_block, &MC); - sentBuildings = true; + CopyProjectiles(net_block); + firstBlock = false; } if (spatterChanged) Copyspatters(block, net_block, &MC, pos); From bd8a6c31bac933b21b889ea18d80823670ed927a Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 6 Jan 2018 22:07:34 +0530 Subject: [PATCH 075/170] Send vehicles over remoteFortressReader, and don't send every block like a retard. --- .../remotefortressreader.cpp | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 9c7263880..4e4b5f14b 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1248,6 +1248,37 @@ void CopyProjectiles(RemoteFortressReader::MapBlock * NetBlock) NetItem->set_velocity_z(diff.z / max_dist); } } + for (int i = 0; i < world->vehicles.active.size(); i++) + { + bool isProj = false; + auto vehicle = world->vehicles.active[i]; + for (auto proj = world->proj_list.next; proj != NULL; proj = proj->next) + { + STRICT_VIRTUAL_CAST_VAR(projectile, df::proj_itemst, proj->item); + if (!projectile) + continue; + if (projectile->item->id == vehicle->item_id) + { + isProj = true; + break; + } + } + if (isProj) + continue; + + auto item = Items::findItemByID(vehicle->item_id); + if (!item) + continue; + auto NetItem = NetBlock->add_items(); + CopyItem(NetItem, item); + NetItem->set_subpos_x(vehicle->offset_x / 100000.0); + NetItem->set_subpos_y(vehicle->offset_y / 100000.0); + NetItem->set_subpos_z(vehicle->offset_z / 140000.0); + NetItem->set_velocity_x(vehicle->speed_x / 100000.0); + NetItem->set_velocity_y(vehicle->speed_y / 100000.0); + NetItem->set_velocity_z(vehicle->speed_z / 140000.0); + + } } void CopyBuildings(DFCoord min, DFCoord max, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC) @@ -1499,7 +1530,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in bool tileChanged = IsTiletypeChanged(pos); bool desChanged = IsDesignationChanged(pos); bool spatterChanged = IsspatterChanged(pos); - bool itemsChanged = true; //simpler just to send the items every frame. + bool itemsChanged = block->items.size() > 0; RemoteFortressReader::MapBlock *net_block; if (tileChanged || desChanged || spatterChanged || firstBlock || itemsChanged) net_block = out->add_map_blocks(); From d0a924a2073da307630c7aa60c8b364908beffb8 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 6 Jan 2018 23:48:06 +0530 Subject: [PATCH 076/170] Send shape ids through RFR --- plugins/proto/RemoteFortressReader.proto | 11 +++++++++ .../remotefortressreader.cpp | 23 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 623ab7f53..92c3cee42 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -275,6 +275,7 @@ message Item optional float velocity_x = 13; optional float velocity_y = 14; optional float velocity_z = 15; + optional int32 shape = 16; } message MapBlock @@ -875,3 +876,13 @@ message Status { repeated Report reports = 1; } + +message ShapeDescriptior +{ + optional string id = 1; +} + +message Language +{ + repeated ShapeDescriptior shapes = 1; +} \ No newline at end of file diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 4e4b5f14b..cafd4a4e5 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -37,6 +37,7 @@ #include "df/block_square_event_item_spatterst.h" #include "df/block_square_event_grassst.h" #endif +#include "df/art_image_element_shapest.h" #include "df/block_square_event_material_spatterst.h" #include "df/body_appearance_modifier.h" #include "df/body_part_layer_raw.h" @@ -61,6 +62,7 @@ #include "df/historical_figure.h" #include "df/item.h" #include "df/item_constructed.h" +#include "df/item_gemst.h" #include "df/item_threadst.h" #include "df/item_toolst.h" #include "df/itemimprovement.h" @@ -168,6 +170,7 @@ static command_result GetPauseState(color_ostream & stream, const EmptyMessage * static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out); void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); static command_result GetReports(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Status * out); +static command_result GetLanguage(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Language * out); void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); @@ -299,6 +302,7 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE); svc->addFunction("MiscMoveCommand", MiscMoveCommand, SF_ALLOW_REMOTE); + svc->addFunction("GetLanguage", GetLanguage, SF_ALLOW_REMOTE); return svc; } @@ -1420,6 +1424,11 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) if (actual_item) { NetItem->set_stack_size(actual_item->stack_size); + } + VIRTUAL_CAST_VAR(gem_item, df::item_gemst, DfItem); + if (gem_item) + { + } VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); if (constructed_item) @@ -2998,4 +3007,18 @@ static command_result GetReports(color_ostream & stream, const EmptyMessage * in lastSentReportID = local_rep->id; } return CR_OK; +} + +static command_result GetLanguage(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Language * out) +{ + if (!world) + return CR_FAILURE; + + for (int i = 0; i < world->raws.language.shapes.size(); i++) + { + auto shape = world->raws.language.shapes[i]; + auto netShape = out->add_shapes(); + netShape->set_id(shape->id); + } + return CR_OK; } \ No newline at end of file From d80d16ddc385826ec9c4a897ca73bbb813423aff Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 7 Jan 2018 00:50:32 +0530 Subject: [PATCH 077/170] Actually send gem shape. --- plugins/remotefortressreader/remotefortressreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index cafd4a4e5..9c548066a 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1428,7 +1428,7 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) VIRTUAL_CAST_VAR(gem_item, df::item_gemst, DfItem); if (gem_item) { - + NetItem->set_shape(gem_item->shape); } VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); if (constructed_item) From 29426111f7e6831168e73e12639aea37593ba153 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 7 Jan 2018 01:14:15 +0530 Subject: [PATCH 078/170] Send shapes for small gems too. --- plugins/remotefortressreader/remotefortressreader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 9c548066a..d5138639e 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -65,6 +65,7 @@ #include "df/item_gemst.h" #include "df/item_threadst.h" #include "df/item_toolst.h" +#include "df/item_smallgemst.h" #include "df/itemimprovement.h" #include "df/itemimprovement_threadst.h" #include "df/itemdef.h" @@ -1430,6 +1431,11 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { NetItem->set_shape(gem_item->shape); } + VIRTUAL_CAST_VAR(smallgem_item, df::item_smallgemst, DfItem); + if (smallgem_item) + { + NetItem->set_shape(smallgem_item->shape); + } VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); if (constructed_item) { From 724fb00b73e4e61db6c4a1a4e3591d67682e60ae Mon Sep 17 00:00:00 2001 From: Japa Mala Illo Date: Mon, 8 Jan 2018 09:58:37 +0530 Subject: [PATCH 079/170] Use an inteligenter method of setting the gem shapes. --- plugins/proto/RemoteFortressReader.proto | 1 - .../remotefortressreader.cpp | 207 +++++++++++++++++- 2 files changed, 203 insertions(+), 5 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 92c3cee42..08d804262 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -275,7 +275,6 @@ message Item optional float velocity_x = 13; optional float velocity_y = 14; optional float velocity_z = 15; - optional int32 shape = 16; } message MapBlock diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index d5138639e..da4121057 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -920,7 +920,84 @@ static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, mat_def->mutable_mat_pair()->set_mat_type((int)it); mat_def->mutable_mat_pair()->set_mat_index(-1); mat_def->set_id(ENUM_KEY_STR(item_type, it)); - if (it == item_type::BOX) + switch (it) + { + case df::enums::item_type::NONE: + break; + case df::enums::item_type::BAR: + break; + case df::enums::item_type::GEM: + case df::enums::item_type::SMALLGEM: + { + for (int i = 0; i < world->raws.language.shapes.size(); i++) + { + auto shape = world->raws.language.shapes[i]; + if (shape->gems_use.whole == 0) + continue; + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + shape->id); + } + break; + } + case df::enums::item_type::BLOCKS: + break; + case df::enums::item_type::ROUGH: + break; + case df::enums::item_type::BOULDER: + break; + case df::enums::item_type::WOOD: + break; + case df::enums::item_type::DOOR: + break; + case df::enums::item_type::FLOODGATE: + break; + case df::enums::item_type::BED: + break; + case df::enums::item_type::CHAIR: + break; + case df::enums::item_type::CHAIN: + break; + case df::enums::item_type::FLASK: + break; + case df::enums::item_type::GOBLET: + break; + case df::enums::item_type::INSTRUMENT: + break; + case df::enums::item_type::TOY: + break; + case df::enums::item_type::WINDOW: + break; + case df::enums::item_type::CAGE: + break; + case df::enums::item_type::BARREL: + break; + case df::enums::item_type::BUCKET: + break; + case df::enums::item_type::ANIMALTRAP: + break; + case df::enums::item_type::TABLE: + break; + case df::enums::item_type::COFFIN: + break; + case df::enums::item_type::STATUE: + break; + case df::enums::item_type::CORPSE: + break; + case df::enums::item_type::WEAPON: + break; + case df::enums::item_type::ARMOR: + break; + case df::enums::item_type::SHOES: + break; + case df::enums::item_type::SHIELD: + break; + case df::enums::item_type::HELM: + break; + case df::enums::item_type::GLOVES: + break; + case df::enums::item_type::BOX: { mat_def = out->add_material_list(); mat_def->mutable_mat_pair()->set_mat_type((int)it); @@ -930,6 +1007,128 @@ static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, mat_def->mutable_mat_pair()->set_mat_type((int)it); mat_def->mutable_mat_pair()->set_mat_index(1); mat_def->set_id("BOX_BAG"); + break; + } + case df::enums::item_type::BIN: + break; + case df::enums::item_type::ARMORSTAND: + break; + case df::enums::item_type::WEAPONRACK: + break; + case df::enums::item_type::CABINET: + break; + case df::enums::item_type::FIGURINE: + break; + case df::enums::item_type::AMULET: + break; + case df::enums::item_type::SCEPTER: + break; + case df::enums::item_type::AMMO: + break; + case df::enums::item_type::CROWN: + break; + case df::enums::item_type::RING: + break; + case df::enums::item_type::EARRING: + break; + case df::enums::item_type::BRACELET: + break; + case df::enums::item_type::ANVIL: + break; + case df::enums::item_type::CORPSEPIECE: + break; + case df::enums::item_type::REMAINS: + break; + case df::enums::item_type::MEAT: + break; + case df::enums::item_type::FISH: + break; + case df::enums::item_type::FISH_RAW: + break; + case df::enums::item_type::VERMIN: + break; + case df::enums::item_type::PET: + break; + case df::enums::item_type::SEEDS: + break; + case df::enums::item_type::PLANT: + break; + case df::enums::item_type::SKIN_TANNED: + break; + case df::enums::item_type::PLANT_GROWTH: + break; + case df::enums::item_type::THREAD: + break; + case df::enums::item_type::CLOTH: + break; + case df::enums::item_type::TOTEM: + break; + case df::enums::item_type::PANTS: + break; + case df::enums::item_type::BACKPACK: + break; + case df::enums::item_type::QUIVER: + break; + case df::enums::item_type::CATAPULTPARTS: + break; + case df::enums::item_type::BALLISTAPARTS: + break; + case df::enums::item_type::SIEGEAMMO: + break; + case df::enums::item_type::BALLISTAARROWHEAD: + break; + case df::enums::item_type::TRAPPARTS: + break; + case df::enums::item_type::TRAPCOMP: + break; + case df::enums::item_type::DRINK: + break; + case df::enums::item_type::POWDER_MISC: + break; + case df::enums::item_type::CHEESE: + break; + case df::enums::item_type::FOOD: + break; + case df::enums::item_type::LIQUID_MISC: + break; + case df::enums::item_type::COIN: + break; + case df::enums::item_type::GLOB: + break; + case df::enums::item_type::ROCK: + break; + case df::enums::item_type::PIPE_SECTION: + break; + case df::enums::item_type::HATCH_COVER: + break; + case df::enums::item_type::GRATE: + break; + case df::enums::item_type::QUERN: + break; + case df::enums::item_type::MILLSTONE: + break; + case df::enums::item_type::SPLINT: + break; + case df::enums::item_type::CRUTCH: + break; + case df::enums::item_type::TRACTION_BENCH: + break; + case df::enums::item_type::ORTHOPEDIC_CAST: + break; + case df::enums::item_type::TOOL: + break; + case df::enums::item_type::SLAB: + break; + case df::enums::item_type::EGG: + break; + case df::enums::item_type::BOOK: + break; + case df::enums::item_type::SHEET: + break; + case df::enums::item_type::BRANCH: + break; + default: + break; } int subtypes = Items::getSubtypeCount(it); if (subtypes >= 0) @@ -940,7 +1139,7 @@ static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, mat_def->mutable_mat_pair()->set_mat_type((int)it); mat_def->mutable_mat_pair()->set_mat_index(i); df::itemdef * item = Items::getSubtypeDef(it, i); - mat_def->set_id(item->id); + mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + item->id); } } } @@ -1429,12 +1628,12 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) VIRTUAL_CAST_VAR(gem_item, df::item_gemst, DfItem); if (gem_item) { - NetItem->set_shape(gem_item->shape); + type->set_mat_index(gem_item->shape); } VIRTUAL_CAST_VAR(smallgem_item, df::item_smallgemst, DfItem); if (smallgem_item) { - NetItem->set_shape(smallgem_item->shape); + type->set_mat_index(smallgem_item->shape); } VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); if (constructed_item) From 2782008b4229be6cc87902f6512cc85f3438ae4a Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 Jan 2018 19:52:35 -0500 Subject: [PATCH 080/170] Update tweak condition-material with new field names dfhack/df-structures#236 --- library/xml | 2 +- plugins/tweak/tweaks/condition-material.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/xml b/library/xml index 7e23a328f..15a89230c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7e23a328fd81e3d6db794c0c18b8b2e7bd235649 +Subproject commit 15a89230cace8f7cc1b90de63c7f2b44a9c77481 diff --git a/plugins/tweak/tweaks/condition-material.h b/plugins/tweak/tweaks/condition-material.h index 5e5afd7f4..c9aec73c9 100644 --- a/plugins/tweak/tweaks/condition-material.h +++ b/plugins/tweak/tweaks/condition-material.h @@ -8,8 +8,8 @@ struct condition_material_hook : df::viewscreen_workquota_conditionst { struct T_order_mat_data { std::vector list_entries; - std::vector list_unk1; - std::vector list_unk2; + std::vector mat_types; + std::vector mat_indices; std::vector list_unk3; std::vector list_visible; }; @@ -24,8 +24,8 @@ struct condition_material_hook : df::viewscreen_workquota_conditionst { } auto data = new T_order_mat_data; data->list_entries = scr->list_entries; - data->list_unk1 = scr->list_unk1; - data->list_unk2 = scr->list_unk2; + data->mat_types = scr->mat_types; + data->mat_indices = scr->mat_indices; data->list_unk3 = scr->list_unk3; data->list_visible = scr->list_visible; order_mat_data[scr] = data; @@ -37,8 +37,8 @@ struct condition_material_hook : df::viewscreen_workquota_conditionst { { T_order_mat_data *data = order_mat_data[scr]; scr->list_entries = data->list_entries; - scr->list_unk1 = data->list_unk1; - scr->list_unk2 = data->list_unk2; + scr->mat_types = data->mat_types; + scr->mat_indices = data->mat_indices; scr->list_unk3 = data->list_unk3; scr->list_visible = data->list_visible; delete data; @@ -55,8 +55,8 @@ struct condition_material_hook : df::viewscreen_workquota_conditionst { // keep the first item ("no material") around, because attempts to delete it // result in it still being displayed first, regardless of list_entries[0] list_entries.resize(1); - list_unk1.resize(1); - list_unk2.resize(1); + mat_types.resize(1); + mat_indices.resize(1); list_unk3.resize(1); list_visible.resize(1); // skip "no material" here @@ -71,8 +71,8 @@ struct condition_material_hook : df::viewscreen_workquota_conditionst { if (s->find(filter) != std::string::npos) { list_entries.push_back(data->list_entries[i]); - list_unk1.push_back(data->list_unk1[i]); - list_unk2.push_back(data->list_unk2[i]); + mat_types.push_back(data->mat_types[i]); + mat_indices.push_back(data->mat_indices[i]); list_unk3.push_back(data->list_unk3[i]); // this should be small enough to fit in an int16_t list_visible.push_back(int16_t(list_entries.size() - 1)); From ddad64224ad252310f790ae539931be17eb87c64 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Jan 2018 12:10:03 -0500 Subject: [PATCH 081/170] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 92ea8f43e..ca151dfae 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 92ea8f43ef7ace7e609a83e061d18ddbcf1f56e2 +Subproject commit ca151dfaea8837dfce4ae332661a70edddacfde9 From 16c4cde2141319b388418bb624640aae587ffd41 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 Jan 2018 12:10:17 -0500 Subject: [PATCH 082/170] Change version to 0.44.04 and update xml --- CMakeLists.txt | 6 +++--- library/xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a1177549..d84e8dfd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,9 +140,9 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.44.03") -SET(DFHACK_RELEASE "beta1") -SET(DFHACK_PRERELEASE TRUE) +set(DF_VERSION "0.44.04") +set(DFHACK_RELEASE "alpha1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/xml b/library/xml index 15a89230c..155c385a1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 15a89230cace8f7cc1b90de63c7f2b44a9c77481 +Subproject commit 155c385a159996928fda8dfa5e273819fa61783e From 4aa84568783644f6699cfc3d21f6d1e8f413664a Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 12 Jan 2018 00:28:15 -0500 Subject: [PATCH 083/170] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 155c385a1..72dd9b146 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 155c385a159996928fda8dfa5e273819fa61783e +Subproject commit 72dd9b14633e448f5e882e27a8d9af22ea9fdd5a diff --git a/scripts b/scripts index ca151dfae..e4c6851a9 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ca151dfaea8837dfce4ae332661a70edddacfde9 +Subproject commit e4c6851a9e0b763bdf12442828c3c58ff0aec65d From 14466d2dfc32d0453f4d2d70989319b044eead13 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 12 Jan 2018 00:29:35 -0500 Subject: [PATCH 084/170] Update NEWS-dev --- docs/NEWS-dev.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 771684884..33ff4237a 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,14 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.04-alpha1 +===================== + +Structures +---------- +- ``artifact_record``: fixed layout (changed in 0.44.04) +- ``incident``: fixed layout (changed in 0.44.01) - note that many fields have moved + DFHack 0.44.03-beta1 ==================== From 8d6e30ef0efbe8411fc05db34fb15ffb360397e1 Mon Sep 17 00:00:00 2001 From: Japa Mala Illo Date: Fri, 12 Jan 2018 11:50:40 +0530 Subject: [PATCH 085/170] Fix whitespace issues --- plugins/proto/AdventureControl.proto | 6 +- .../adventure_control.cpp | 68 +++++++++---------- .../remotefortressreader.cpp | 20 +++--- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/plugins/proto/AdventureControl.proto b/plugins/proto/AdventureControl.proto index a5785d7a3..7d3d128d6 100644 --- a/plugins/proto/AdventureControl.proto +++ b/plugins/proto/AdventureControl.proto @@ -58,7 +58,7 @@ enum AdvmodeMenu enum CarefulMovementType { - DEFAULT_MOVEMENT = 0; + DEFAULT_MOVEMENT = 0; RELEASE_ITEM_HOLD = 1; RELEASE_TILE_HOLD = 2; ATTACK_CREATURE = 3; @@ -95,8 +95,8 @@ message MovementOption message MenuContents { - optional AdvmodeMenu current_menu = 1; - repeated MovementOption movements = 2; + optional AdvmodeMenu current_menu = 1; + repeated MovementOption movements = 2; } message MiscMoveParams diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index 1e1f26452..acb4becac 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -90,7 +90,7 @@ command_result MoveCommand(DFHack::color_ostream &stream, const MoveCommandParam case 1: viewScreen->feed_key(interface_key::A_MOVE_SW_UP); break; - } + } break; } break; @@ -240,28 +240,28 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, out->set_current_menu((AdvmodeMenu)advUi->menu); -// /$$$$$$$$ /$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$$$ -//| $$_____/|_ $$_/| $$ / $$| $$$ /$$$| $$_____/ -//| $$ | $$ | $$/ $$/| $$$$ /$$$$| $$ -//| $$$$$ | $$ \ $$$$/ | $$ $$/$$ $$| $$$$$ -//| $$__/ | $$ >$$ $$ | $$ $$$| $$| $$__/ -//| $$ | $$ /$$/\ $$| $$\ $ | $$| $$ -//| $$ /$$$$$$| $$ \ $$| $$ \/ | $$| $$$$$$$$ -//|__/ |______/|__/ |__/|__/ |__/|________/ -// -// -// -// /$$$$$$$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ -//|__ $$__/| $$ |__/ |__/ | $$ |__/ | $$ | $$ | $$ -// | $$ | $$$$$$$ /$$ /$$$$$$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$ /$$$$$$$ | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$ -// | $$ | $$__ $$| $$ /$$_____/ | $$ /$$_____/ |____ $$ /$$_____/|_ $$_/ | $$ | $$ /$$__ $$| $$ /$$__ $$ | $$__ $$ |____ $$ /$$_____/| $$ /$$/ -// | $$ | $$ \ $$| $$| $$$$$$ | $$| $$$$$$ /$$$$$$$ | $$$$$$ | $$ | $$ | $$| $$ \ $$| $$| $$ | $$ | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ -// | $$ | $$ | $$| $$ \____ $$ | $$ \____ $$ /$$__ $$ \____ $$ | $$ /$$| $$ | $$| $$ | $$| $$| $$ | $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ -// | $$ | $$ | $$| $$ /$$$$$$$/ | $$ /$$$$$$$/ | $$$$$$$ /$$$$$$$/ | $$$$/| $$$$$$/| $$$$$$$/| $$| $$$$$$$ | $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ -// |__/ |__/ |__/|__/|_______/ |__/|_______/ \_______/ |_______/ \___/ \______/ | $$____/ |__/ \_______/ |__/ |__/ \_______/ \_______/|__/ \__/ -// | $$ -// | $$ -// |__/ + // /$$$$$$$$ /$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$$$ + //| $$_____/|_ $$_/| $$ / $$| $$$ /$$$| $$_____/ + //| $$ | $$ | $$/ $$/| $$$$ /$$$$| $$ + //| $$$$$ | $$ \ $$$$/ | $$ $$/$$ $$| $$$$$ + //| $$__/ | $$ >$$ $$ | $$ $$$| $$| $$__/ + //| $$ | $$ /$$/\ $$| $$\ $ | $$| $$ + //| $$ /$$$$$$| $$ \ $$| $$ \/ | $$| $$$$$$$$ + //|__/ |______/|__/ |__/|__/ |__/|________/ + // + // + // + // /$$$$$$$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ + //|__ $$__/| $$ |__/ |__/ | $$ |__/ | $$ | $$ | $$ + // | $$ | $$$$$$$ /$$ /$$$$$$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$ /$$$$$$$ | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$ + // | $$ | $$__ $$| $$ /$$_____/ | $$ /$$_____/ |____ $$ /$$_____/|_ $$_/ | $$ | $$ /$$__ $$| $$ /$$__ $$ | $$__ $$ |____ $$ /$$_____/| $$ /$$/ + // | $$ | $$ \ $$| $$| $$$$$$ | $$| $$$$$$ /$$$$$$$ | $$$$$$ | $$ | $$ | $$| $$ \ $$| $$| $$ | $$ | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ + // | $$ | $$ | $$| $$ \____ $$ | $$ \____ $$ /$$__ $$ \____ $$ | $$ /$$| $$ | $$| $$ | $$| $$| $$ | $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ + // | $$ | $$ | $$| $$ /$$$$$$$/ | $$ /$$$$$$$/ | $$$$$$$ /$$$$$$$/ | $$$$/| $$$$$$/| $$$$$$$/| $$| $$$$$$$ | $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ + // |__/ |__/ |__/|__/|_______/ |__/|_______/ \_______/ |_______/ \___/ \______/ | $$____/ |__/ \_______/ |__/ |__/ \_______/ \_______/|__/ \__/ + // | $$ + // | $$ + // |__/ if (advUi->menu == ui_advmode_menu::FallAction) { getCurViewscreen()->feed_key(interface_key::OPTION1); @@ -299,17 +299,17 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, command_result MovementSelectCommand(DFHack::color_ostream &stream, const dfproto::IntMessage *in) { - if (!(df::global::ui_advmode->menu == ui_advmode_menu::MoveCarefully)) - return CR_OK; - int choice = in->value(); - int page = choice / 5; - int select = choice % 5; - for (int i = 0; i < page; i++) - { - keyQueue.push(interface_key::SECONDSCROLL_PAGEDOWN); - } - keyQueue.push((interface_key::interface_key)(interface_key::OPTION1 + select)); - return CR_OK; + if (!(df::global::ui_advmode->menu == ui_advmode_menu::MoveCarefully)) + return CR_OK; + int choice = in->value(); + int page = choice / 5; + int select = choice % 5; + for (int i = 0; i < page; i++) + { + keyQueue.push(interface_key::SECONDSCROLL_PAGEDOWN); + } + keyQueue.push((interface_key::interface_key)(interface_key::OPTION1 + select)); + return CR_OK; } command_result MiscMoveCommand(DFHack::color_ostream &stream, const MiscMoveParams *in) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index da4121057..b13e56289 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -258,8 +258,8 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector addFunction("GetPauseState", GetPauseState, SF_ALLOW_REMOTE); svc->addFunction("GetVersionInfo", GetVersionInfo, SF_ALLOW_REMOTE); svc->addFunction("GetReports", GetReports, SF_ALLOW_REMOTE); - svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); + svc->addFunction("MoveCommand", MoveCommand, SF_ALLOW_REMOTE); svc->addFunction("JumpCommand", JumpCommand, SF_ALLOW_REMOTE); - svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); + svc->addFunction("MenuQuery", MenuQuery, SF_ALLOW_REMOTE); svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE); svc->addFunction("MiscMoveCommand", MiscMoveCommand, SF_ALLOW_REMOTE); svc->addFunction("GetLanguage", GetLanguage, SF_ALLOW_REMOTE); @@ -318,10 +318,10 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) DFhackCExport command_result plugin_onupdate(color_ostream &out) { - if (!enableUpdates) - return CR_OK; - KeyUpdate(); - return CR_OK; + if (!enableUpdates) + return CR_OK; + KeyUpdate(); + return CR_OK; } uint16_t fletcher16(uint8_t const *data, size_t bytes) @@ -1698,7 +1698,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in if (in->has_blocks_needed()) blocks_needed = in->blocks_needed(); else - blocks_needed = NUMBER_OF_POINTS*(in->max_z() - in->min_z()); + blocks_needed = NUMBER_OF_POINTS * (in->max_z() - in->min_z()); int blocks_sent = 0; int min_x = in->min_x(); int min_y = in->min_y(); @@ -2660,7 +2660,7 @@ static void CopyLocalMap(df::world_data * worldData, df::world_region_details* w int region_min_x = pos_x * 16; int region_min_y = pos_y * 16; - if ((site->global_min_x >(region_min_x + 16)) || + if ((site->global_min_x > (region_min_x + 16)) || (site->global_min_y > (region_min_y + 16)) || (site->global_max_x < (region_min_x)) || (site->global_max_y < (region_min_y))) From 9ba0b00580677f85246af21739190459f890f004 Mon Sep 17 00:00:00 2001 From: Japa Mala Illo Date: Fri, 12 Jan 2018 11:59:02 +0530 Subject: [PATCH 086/170] Remove the stupid big warning comment. --- .../adventure_control.cpp | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/plugins/remotefortressreader/adventure_control.cpp b/plugins/remotefortressreader/adventure_control.cpp index acb4becac..6fb592d62 100644 --- a/plugins/remotefortressreader/adventure_control.cpp +++ b/plugins/remotefortressreader/adventure_control.cpp @@ -240,28 +240,7 @@ command_result MenuQuery(DFHack::color_ostream &stream, const EmptyMessage *in, out->set_current_menu((AdvmodeMenu)advUi->menu); - // /$$$$$$$$ /$$$$$$ /$$ /$$ /$$ /$$ /$$$$$$$$ - //| $$_____/|_ $$_/| $$ / $$| $$$ /$$$| $$_____/ - //| $$ | $$ | $$/ $$/| $$$$ /$$$$| $$ - //| $$$$$ | $$ \ $$$$/ | $$ $$/$$ $$| $$$$$ - //| $$__/ | $$ >$$ $$ | $$ $$$| $$| $$__/ - //| $$ | $$ /$$/\ $$| $$\ $ | $$| $$ - //| $$ /$$$$$$| $$ \ $$| $$ \/ | $$| $$$$$$$$ - //|__/ |______/|__/ |__/|__/ |__/|________/ - // - // - // - // /$$$$$$$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ /$$ - //|__ $$__/| $$ |__/ |__/ | $$ |__/ | $$ | $$ | $$ - // | $$ | $$$$$$$ /$$ /$$$$$$$ /$$ /$$$$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$ /$$ /$$$$$$ /$$ /$$$$$$$ | $$$$$$$ /$$$$$$ /$$$$$$$| $$ /$$ - // | $$ | $$__ $$| $$ /$$_____/ | $$ /$$_____/ |____ $$ /$$_____/|_ $$_/ | $$ | $$ /$$__ $$| $$ /$$__ $$ | $$__ $$ |____ $$ /$$_____/| $$ /$$/ - // | $$ | $$ \ $$| $$| $$$$$$ | $$| $$$$$$ /$$$$$$$ | $$$$$$ | $$ | $$ | $$| $$ \ $$| $$| $$ | $$ | $$ \ $$ /$$$$$$$| $$ | $$$$$$/ - // | $$ | $$ | $$| $$ \____ $$ | $$ \____ $$ /$$__ $$ \____ $$ | $$ /$$| $$ | $$| $$ | $$| $$| $$ | $$ | $$ | $$ /$$__ $$| $$ | $$_ $$ - // | $$ | $$ | $$| $$ /$$$$$$$/ | $$ /$$$$$$$/ | $$$$$$$ /$$$$$$$/ | $$$$/| $$$$$$/| $$$$$$$/| $$| $$$$$$$ | $$ | $$| $$$$$$$| $$$$$$$| $$ \ $$ - // |__/ |__/ |__/|__/|_______/ |__/|_______/ \_______/ |_______/ \___/ \______/ | $$____/ |__/ \_______/ |__/ |__/ \_______/ \_______/|__/ \__/ - // | $$ - // | $$ - // |__/ + //Fixme: Needs a proper way to control it, but for now, this is the only way to allow Armok Vision to keep going without the user needing to switch to DF. if (advUi->menu == ui_advmode_menu::FallAction) { getCurViewscreen()->feed_key(interface_key::OPTION1); From e1bf878059b6248d926d0ab50f1918930ca3195d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 Jan 2018 16:50:53 -0500 Subject: [PATCH 087/170] Add some missing changelog entries --- NEWS.rst | 1 + docs/NEWS-dev.rst | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index abecc0900..ca9234d63 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -49,6 +49,7 @@ Fixes ----- - Fixed issues with the console output color affecting the prompt on Windows - `createitem`: stopped items from teleporting away in some forts +- `devel/inject-raws`: now recognizes spaces in reaction names - `gui/gm-unit`: can now edit mining skill - `gui/quickcmd`: stopped error from adding too many commands diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 33ff4237a..4dd04ce43 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -40,6 +40,11 @@ Development Changelog DFHack 0.44.04-alpha1 ===================== +Fixes +----- +- `devel/inject-raws`: now recognizes spaces in reaction names +- `exportlegends`: fixed an error that could occur when exporting empty lists + Structures ---------- - ``artifact_record``: fixed layout (changed in 0.44.04) @@ -125,6 +130,11 @@ Other Changes ------------- - The console now provides suggestions for built-in commands - `devel/export-dt-ini`: avoid hardcoding flags +- `exportlegends`: + + - reordered some tags to match DF's order + - added progress indicators for exporting long lists + - `gui/gm-editor`: added enum names to enum edit dialogs - `gui/gm-unit`: made skill search case-insensitive - `gui/rename`: added "clear" and "special characters" options From dbe950d92df9c8246d1765a78dead8fb38415179 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 13 Jan 2018 16:51:03 -0500 Subject: [PATCH 088/170] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 72dd9b146..f38c8d325 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 72dd9b14633e448f5e882e27a8d9af22ea9fdd5a +Subproject commit f38c8d325297d0dc354ca3b9881989980f74013d diff --git a/scripts b/scripts index e4c6851a9..ba92c1604 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e4c6851a9e0b763bdf12442828c3c58ff0aec65d +Subproject commit ba92c16046dae453af22c1ccf31a30c09787b357 From ce1644d6552e7d3cdf0abfa6dc7a1583ff60c393 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 14 Jan 2018 18:09:18 -0500 Subject: [PATCH 089/170] Bump to 0.44.05-alpha1 and update submodules --- CMakeLists.txt | 2 +- docs/NEWS-dev.rst | 7 +++++++ library/xml | 2 +- scripts | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d84e8dfd1..6e92fc967 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.44.04") +set(DF_VERSION "0.44.05") set(DFHACK_RELEASE "alpha1") set(DFHACK_PRERELEASE TRUE) diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 4dd04ce43..38fbe658d 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -37,6 +37,13 @@ Development Changelog .. contents:: :depth: 2 +DFHack 0.44.05-alpha1 +===================== + +Structures +---------- +- ``incident``: re-aligned again to match disassembly + DFHack 0.44.04-alpha1 ===================== diff --git a/library/xml b/library/xml index f38c8d325..3a9f401d1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f38c8d325297d0dc354ca3b9881989980f74013d +Subproject commit 3a9f401d196ee8ebc53edb9e15a13bfcb0879b4e diff --git a/scripts b/scripts index ba92c1604..2d4093e61 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ba92c16046dae453af22c1ccf31a30c09787b357 +Subproject commit 2d4093e61ea2a02742a6bfbfd80e49eb6dcdd549 From c3bf14a300d86455fc087d9dbe0031bffac79e93 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 14 Jan 2018 22:56:35 -0500 Subject: [PATCH 090/170] Correct bad os-type attributes in symbols.xml --- library/Core.cpp | 14 +++++++++++++- library/VersionInfoFactory.cpp | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 47bddbab8..5173a3ad9 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -640,7 +640,7 @@ static std::string sc_event_name (state_change_event id) { string getBuiltinCommand(std::string cmd) { std::string builtin = ""; - + // Check our list of builtin commands from the header if (built_in_commands.count(cmd)) builtin = cmd; @@ -1619,6 +1619,18 @@ bool Core::Init() } cerr << "Version: " << vinfo->getVersion() << endl; +#if defined(_WIN32) + const OSType expected = OS_WINDOWS; +#elif defined(_DARWIN) + const OSType expected = OS_APPLE; +#else + const OSType expected = OS_LINUX; +#endif + if (expected != vinfo->getOS()) { + cerr << "OS mismatch; resetting to " << int(expected) << endl; + vinfo->setOS(expected); + } + // Init global object pointers df::global::InitGlobals(); alias_mutex = new recursive_mutex(); diff --git a/library/VersionInfoFactory.cpp b/library/VersionInfoFactory.cpp index cdfdbf774..7033fd598 100644 --- a/library/VersionInfoFactory.cpp +++ b/library/VersionInfoFactory.cpp @@ -153,7 +153,7 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) else if (type == "md5-hash") { const char *cstr_value = pMemEntry->Attribute("value"); - fprintf(stderr, "%s: MD5: %s\n", cstr_name, cstr_value); + fprintf(stderr, "%s (%s): MD5: %s\n", cstr_name, cstr_os, cstr_value); if(!cstr_value) throw Error::SymbolsXmlUnderspecifiedEntry(cstr_name); mem->addMD5(cstr_value); @@ -161,7 +161,7 @@ void VersionInfoFactory::ParseVersion (TiXmlElement* entry, VersionInfo* mem) else if (type == "binary-timestamp") { const char *cstr_value = pMemEntry->Attribute("value"); - fprintf(stderr, "%s: PE: %s\n", cstr_name, cstr_value); + fprintf(stderr, "%s (%s): PE: %s\n", cstr_name, cstr_os, cstr_value); if(!cstr_value) throw Error::SymbolsXmlUnderspecifiedEntry(cstr_name); mem->addPE(strtol(cstr_value, 0, 16)); From 46bc26dfe2b4343adcd39034acb8447232d33973 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 14 Jan 2018 23:25:28 -0500 Subject: [PATCH 091/170] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 3a9f401d1..352e23310 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3a9f401d196ee8ebc53edb9e15a13bfcb0879b4e +Subproject commit 352e233105512a702875f48d82f922f0c9ca3905 From 167fcd757819211748fd130c1ac7871076e03202 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 15 Jan 2018 00:11:03 -0500 Subject: [PATCH 092/170] Add gui/liquids changes to changelog --- NEWS.rst | 1 + docs/NEWS-dev.rst | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index ca9234d63..a14bafa9f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -64,6 +64,7 @@ Misc Improvements - `gui/gm-editor`: added enum names to enum edit dialogs - `gui/gm-unit`: made skill search case-insensitive +- `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards - `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options - `modtools/skill-change`: diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index 38fbe658d..834282608 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -44,6 +44,10 @@ Structures ---------- - ``incident``: re-aligned again to match disassembly +Other Changes +------------- +- `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards + DFHack 0.44.04-alpha1 ===================== From e2ad956227de06cff240d8d4dadbda177203c6ef Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 16 Jan 2018 15:54:41 +0530 Subject: [PATCH 093/170] update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 72dd9b146..6b6dda838 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 72dd9b14633e448f5e882e27a8d9af22ea9fdd5a +Subproject commit 6b6dda838fc1b9c4e1c47fbdfbf19838749bad14 From ea6757377eadf3ebe6058746f2d92e5ee2ea05d4 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 16 Jan 2018 17:04:26 +0530 Subject: [PATCH 094/170] add item volume to RFR --- plugins/proto/RemoteFortressReader.proto | 1 + .../remotefortressreader.cpp | 228 ++---------------- 2 files changed, 26 insertions(+), 203 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 08d804262..786ee6bc9 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -275,6 +275,7 @@ message Item optional float velocity_x = 13; optional float velocity_y = 14; optional float velocity_z = 15; + optional int32 volume = 16; } message MapBlock diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index b13e56289..3e850d20b 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -922,213 +922,33 @@ static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, mat_def->set_id(ENUM_KEY_STR(item_type, it)); switch (it) { - case df::enums::item_type::NONE: - break; - case df::enums::item_type::BAR: - break; - case df::enums::item_type::GEM: - case df::enums::item_type::SMALLGEM: - { - for (int i = 0; i < world->raws.language.shapes.size(); i++) + case df::enums::item_type::GEM: + case df::enums::item_type::SMALLGEM: + { + for (int i = 0; i < world->raws.language.shapes.size(); i++) + { + auto shape = world->raws.language.shapes[i]; + if (shape->gems_use.whole == 0) + continue; + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + shape->id); + } + break; + } + case df::enums::item_type::BOX: { - auto shape = world->raws.language.shapes[i]; - if (shape->gems_use.whole == 0) - continue; mat_def = out->add_material_list(); mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + shape->id); + mat_def->mutable_mat_pair()->set_mat_index(0); + mat_def->set_id("BOX_CHEST"); + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(1); + mat_def->set_id("BOX_BAG"); + break; } - break; - } - case df::enums::item_type::BLOCKS: - break; - case df::enums::item_type::ROUGH: - break; - case df::enums::item_type::BOULDER: - break; - case df::enums::item_type::WOOD: - break; - case df::enums::item_type::DOOR: - break; - case df::enums::item_type::FLOODGATE: - break; - case df::enums::item_type::BED: - break; - case df::enums::item_type::CHAIR: - break; - case df::enums::item_type::CHAIN: - break; - case df::enums::item_type::FLASK: - break; - case df::enums::item_type::GOBLET: - break; - case df::enums::item_type::INSTRUMENT: - break; - case df::enums::item_type::TOY: - break; - case df::enums::item_type::WINDOW: - break; - case df::enums::item_type::CAGE: - break; - case df::enums::item_type::BARREL: - break; - case df::enums::item_type::BUCKET: - break; - case df::enums::item_type::ANIMALTRAP: - break; - case df::enums::item_type::TABLE: - break; - case df::enums::item_type::COFFIN: - break; - case df::enums::item_type::STATUE: - break; - case df::enums::item_type::CORPSE: - break; - case df::enums::item_type::WEAPON: - break; - case df::enums::item_type::ARMOR: - break; - case df::enums::item_type::SHOES: - break; - case df::enums::item_type::SHIELD: - break; - case df::enums::item_type::HELM: - break; - case df::enums::item_type::GLOVES: - break; - case df::enums::item_type::BOX: - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(0); - mat_def->set_id("BOX_CHEST"); - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(1); - mat_def->set_id("BOX_BAG"); - break; - } - case df::enums::item_type::BIN: - break; - case df::enums::item_type::ARMORSTAND: - break; - case df::enums::item_type::WEAPONRACK: - break; - case df::enums::item_type::CABINET: - break; - case df::enums::item_type::FIGURINE: - break; - case df::enums::item_type::AMULET: - break; - case df::enums::item_type::SCEPTER: - break; - case df::enums::item_type::AMMO: - break; - case df::enums::item_type::CROWN: - break; - case df::enums::item_type::RING: - break; - case df::enums::item_type::EARRING: - break; - case df::enums::item_type::BRACELET: - break; - case df::enums::item_type::ANVIL: - break; - case df::enums::item_type::CORPSEPIECE: - break; - case df::enums::item_type::REMAINS: - break; - case df::enums::item_type::MEAT: - break; - case df::enums::item_type::FISH: - break; - case df::enums::item_type::FISH_RAW: - break; - case df::enums::item_type::VERMIN: - break; - case df::enums::item_type::PET: - break; - case df::enums::item_type::SEEDS: - break; - case df::enums::item_type::PLANT: - break; - case df::enums::item_type::SKIN_TANNED: - break; - case df::enums::item_type::PLANT_GROWTH: - break; - case df::enums::item_type::THREAD: - break; - case df::enums::item_type::CLOTH: - break; - case df::enums::item_type::TOTEM: - break; - case df::enums::item_type::PANTS: - break; - case df::enums::item_type::BACKPACK: - break; - case df::enums::item_type::QUIVER: - break; - case df::enums::item_type::CATAPULTPARTS: - break; - case df::enums::item_type::BALLISTAPARTS: - break; - case df::enums::item_type::SIEGEAMMO: - break; - case df::enums::item_type::BALLISTAARROWHEAD: - break; - case df::enums::item_type::TRAPPARTS: - break; - case df::enums::item_type::TRAPCOMP: - break; - case df::enums::item_type::DRINK: - break; - case df::enums::item_type::POWDER_MISC: - break; - case df::enums::item_type::CHEESE: - break; - case df::enums::item_type::FOOD: - break; - case df::enums::item_type::LIQUID_MISC: - break; - case df::enums::item_type::COIN: - break; - case df::enums::item_type::GLOB: - break; - case df::enums::item_type::ROCK: - break; - case df::enums::item_type::PIPE_SECTION: - break; - case df::enums::item_type::HATCH_COVER: - break; - case df::enums::item_type::GRATE: - break; - case df::enums::item_type::QUERN: - break; - case df::enums::item_type::MILLSTONE: - break; - case df::enums::item_type::SPLINT: - break; - case df::enums::item_type::CRUTCH: - break; - case df::enums::item_type::TRACTION_BENCH: - break; - case df::enums::item_type::ORTHOPEDIC_CAST: - break; - case df::enums::item_type::TOOL: - break; - case df::enums::item_type::SLAB: - break; - case df::enums::item_type::EGG: - break; - case df::enums::item_type::BOOK: - break; - case df::enums::item_type::SHEET: - break; - case df::enums::item_type::BRANCH: - break; - default: - break; } int subtypes = Items::getSubtypeCount(it); if (subtypes >= 0) @@ -1665,6 +1485,8 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); } } + + NetItem->set_volume(DfItem->getVolume()); } void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) From a63347cf7a689b20260bedba33c87e2d068d3d93 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 17 Jan 2018 19:10:19 +0530 Subject: [PATCH 095/170] Move item reader to a separate file. --- plugins/proto/RemoteFortressReader.proto | 28 +- plugins/remotefortressreader/CMakeLists.txt | 2 + plugins/remotefortressreader/item_reader.cpp | 395 ++++++++++++++++++ plugins/remotefortressreader/item_reader.h | 25 ++ .../remotefortressreader.cpp | 167 +------- 5 files changed, 455 insertions(+), 162 deletions(-) create mode 100644 plugins/remotefortressreader/item_reader.cpp create mode 100644 plugins/remotefortressreader/item_reader.h diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 786ee6bc9..463e368fc 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -276,6 +276,7 @@ message Item optional float velocity_y = 14; optional float velocity_z = 15; optional int32 volume = 16; + repeated ItemImprovement improvements = 17; } message MapBlock @@ -885,4 +886,29 @@ message ShapeDescriptior message Language { repeated ShapeDescriptior shapes = 1; -} \ No newline at end of file +} + +enum ImprovementType +{ + ART_IMAGE = 0; + COVERED = 1; + RINGS_HANGING = 2; + BANDS = 3; + SPIKES = 4; + ITEMSPECIFIC = 5; + THREAD = 6; + CLOTH = 7; + SEWN_IMAGE = 8; + PAGES = 9; + ILLUSTRATION = 10; + INSTRUMENT_PIECE = 11; + WRITING = 12; +} + +message ItemImprovement +{ + optional MatPair mat_type = 1; + optional ImprovementType type = 2; + optional int32 shape = 3; + +} diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index 72b7c94cc..10cc21047 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -4,11 +4,13 @@ SET(PROJECT_SRCS remotefortressreader.cpp adventure_control.cpp building_reader.cpp + item_reader.cpp ) # A list of headers SET(PROJECT_HDRS adventure_control.h building_reader.h + item_reader.h df_version_int.h ) #proto files to include. diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp new file mode 100644 index 000000000..256d78fd9 --- /dev/null +++ b/plugins/remotefortressreader/item_reader.cpp @@ -0,0 +1,395 @@ +#include "item_reader.h" + +#include "df/descriptor_shape.h" +#include "df/item_type.h" +#include "df/item_constructed.h" +#include "df/item_gemst.h" +#include "df/item_threadst.h" +#include "df/item_toolst.h" +#include "df/item_smallgemst.h" +#include "df/itemimprovement.h" +#include "df/itemimprovement_threadst.h" +#include "df/itemdef.h" +#include "df/map_block.h" +#include "df/vehicle.h" +#include "df/world.h" + +#include "modules/Items.h" +#include "modules/MapCache.h" +#include "modules/Materials.h" +#include "MiscUtils.h" + + +using namespace DFHack; +using namespace df::enums; +using namespace RemoteFortressReader; +using namespace std; +using namespace df::global; + + +void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) +{ + NetItem->set_id(DfItem->id); + NetItem->set_flags1(DfItem->flags.whole); + NetItem->set_flags2(DfItem->flags2.whole); + auto pos = NetItem->mutable_pos(); + pos->set_x(DfItem->pos.x); + pos->set_y(DfItem->pos.y); + pos->set_z(DfItem->pos.z); + auto mat = NetItem->mutable_material(); + mat->set_mat_index(DfItem->getMaterialIndex()); + mat->set_mat_type(DfItem->getMaterial()); + auto type = NetItem->mutable_type(); + type->set_mat_type(DfItem->getType()); + type->set_mat_index(DfItem->getSubtype()); + + bool isProjectile = false; + + item_type::item_type itemType = DfItem->getType(); + + switch (itemType) + { + case df::enums::item_type::NONE: + break; + case df::enums::item_type::BAR: + break; + case df::enums::item_type::SMALLGEM: + { + VIRTUAL_CAST_VAR(smallgem_item, df::item_smallgemst, DfItem); + type->set_mat_index(smallgem_item->shape); + break; + } + case df::enums::item_type::BLOCKS: + break; + case df::enums::item_type::ROUGH: + break; + case df::enums::item_type::BOULDER: + break; + case df::enums::item_type::WOOD: + break; + case df::enums::item_type::DOOR: + break; + case df::enums::item_type::FLOODGATE: + break; + case df::enums::item_type::BED: + break; + case df::enums::item_type::CHAIR: + break; + case df::enums::item_type::CHAIN: + break; + case df::enums::item_type::FLASK: + break; + case df::enums::item_type::GOBLET: + break; + case df::enums::item_type::INSTRUMENT: + break; + case df::enums::item_type::TOY: + break; + case df::enums::item_type::WINDOW: + break; + case df::enums::item_type::CAGE: + break; + case df::enums::item_type::BARREL: + break; + case df::enums::item_type::BUCKET: + break; + case df::enums::item_type::ANIMALTRAP: + break; + case df::enums::item_type::TABLE: + break; + case df::enums::item_type::COFFIN: + break; + case df::enums::item_type::STATUE: + break; + case df::enums::item_type::CORPSE: + break; + case df::enums::item_type::WEAPON: + break; + case df::enums::item_type::ARMOR: + break; + case df::enums::item_type::SHOES: + break; + case df::enums::item_type::SHIELD: + break; + case df::enums::item_type::HELM: + break; + case df::enums::item_type::GLOVES: + break; + case df::enums::item_type::BOX: + type->set_mat_index(DfItem->isBag()); + break; + case df::enums::item_type::BIN: + break; + case df::enums::item_type::ARMORSTAND: + break; + case df::enums::item_type::WEAPONRACK: + break; + case df::enums::item_type::CABINET: + break; + case df::enums::item_type::FIGURINE: + break; + case df::enums::item_type::AMULET: + break; + case df::enums::item_type::SCEPTER: + break; + case df::enums::item_type::AMMO: + break; + case df::enums::item_type::CROWN: + break; + case df::enums::item_type::RING: + break; + case df::enums::item_type::EARRING: + break; + case df::enums::item_type::BRACELET: + break; + case df::enums::item_type::GEM: + { + VIRTUAL_CAST_VAR(gem_item, df::item_gemst, DfItem); + type->set_mat_index(gem_item->shape); + break; + } + case df::enums::item_type::ANVIL: + break; + case df::enums::item_type::CORPSEPIECE: + break; + case df::enums::item_type::REMAINS: + break; + case df::enums::item_type::MEAT: + break; + case df::enums::item_type::FISH: + break; + case df::enums::item_type::FISH_RAW: + break; + case df::enums::item_type::VERMIN: + break; + case df::enums::item_type::PET: + break; + case df::enums::item_type::SEEDS: + break; + case df::enums::item_type::PLANT: + break; + case df::enums::item_type::SKIN_TANNED: + break; + case df::enums::item_type::PLANT_GROWTH: + break; + case df::enums::item_type::THREAD: + { + VIRTUAL_CAST_VAR(thread, df::item_threadst, DfItem); + if (thread && thread->dye_mat_type >= 0) + { + DFHack::MaterialInfo info; + if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + break; + } + case df::enums::item_type::CLOTH: + break; + case df::enums::item_type::TOTEM: + break; + case df::enums::item_type::PANTS: + break; + case df::enums::item_type::BACKPACK: + break; + case df::enums::item_type::QUIVER: + break; + case df::enums::item_type::CATAPULTPARTS: + break; + case df::enums::item_type::BALLISTAPARTS: + break; + case df::enums::item_type::SIEGEAMMO: + break; + case df::enums::item_type::BALLISTAARROWHEAD: + break; + case df::enums::item_type::TRAPPARTS: + break; + case df::enums::item_type::TRAPCOMP: + break; + case df::enums::item_type::DRINK: + break; + case df::enums::item_type::POWDER_MISC: + break; + case df::enums::item_type::CHEESE: + break; + case df::enums::item_type::FOOD: + break; + case df::enums::item_type::LIQUID_MISC: + break; + case df::enums::item_type::COIN: + break; + case df::enums::item_type::GLOB: + break; + case df::enums::item_type::ROCK: + break; + case df::enums::item_type::PIPE_SECTION: + break; + case df::enums::item_type::HATCH_COVER: + break; + case df::enums::item_type::GRATE: + break; + case df::enums::item_type::QUERN: + break; + case df::enums::item_type::MILLSTONE: + break; + case df::enums::item_type::SPLINT: + break; + case df::enums::item_type::CRUTCH: + break; + case df::enums::item_type::TRACTION_BENCH: + break; + case df::enums::item_type::ORTHOPEDIC_CAST: + break; + case df::enums::item_type::TOOL: + if (!isProjectile) + { + VIRTUAL_CAST_VAR(tool, df::item_toolst, DfItem); + if (tool) + { + auto vehicle = binsearch_in_vector(world->vehicles.active, tool->vehicle_id); + if (vehicle) + { + NetItem->set_subpos_x(vehicle->offset_x / 100000.0); + NetItem->set_subpos_y(vehicle->offset_y / 100000.0); + NetItem->set_subpos_z(vehicle->offset_z / 140000.0); + } + } + } + break; + case df::enums::item_type::SLAB: + break; + case df::enums::item_type::EGG: + break; + case df::enums::item_type::BOOK: + break; + case df::enums::item_type::SHEET: + break; + case df::enums::item_type::BRANCH: + break; + default: + break; + } + + VIRTUAL_CAST_VAR(actual_item, df::item_actual, DfItem); + if (actual_item) + { + NetItem->set_stack_size(actual_item->stack_size); + } + + VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); + if (constructed_item) + { + for (int i = 0; i < constructed_item->improvements.size(); i++) + { + auto improvement = constructed_item->improvements[i]; + + if (!improvement) + continue; + + improvement_type::improvement_type impType = improvement->getType(); + + switch (impType) + { + case df::enums::improvement_type::ART_IMAGE: + break; + case df::enums::improvement_type::COVERED: + { + break; + } + case df::enums::improvement_type::RINGS_HANGING: + break; + case df::enums::improvement_type::BANDS: + break; + case df::enums::improvement_type::SPIKES: + break; + case df::enums::improvement_type::ITEMSPECIFIC: + break; + case df::enums::improvement_type::THREAD: + { + VIRTUAL_CAST_VAR(improvement_thread, df::itemimprovement_threadst, improvement); + if (improvement_thread->dye.mat_type >= 0) + { + DFHack::MaterialInfo info; + if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) + continue; + ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); + } + break; + } + case df::enums::improvement_type::CLOTH: + break; + case df::enums::improvement_type::SEWN_IMAGE: + break; + case df::enums::improvement_type::PAGES: + break; + case df::enums::improvement_type::ILLUSTRATION: + break; + case df::enums::improvement_type::INSTRUMENT_PIECE: + break; + case df::enums::improvement_type::WRITING: + break; + default: + break; + } + } + } + + NetItem->set_volume(DfItem->getVolume()); +} + +DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::MaterialList *out) +{ + if (!Core::getInstance().isWorldLoaded()) { + //out->set_available(false); + return CR_OK; + } + FOR_ENUM_ITEMS(item_type, it) + { + MaterialDefinition *mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(-1); + mat_def->set_id(ENUM_KEY_STR(item_type, it)); + switch (it) + { + case df::enums::item_type::GEM: + case df::enums::item_type::SMALLGEM: + { + for (int i = 0; i < world->raws.language.shapes.size(); i++) + { + auto shape = world->raws.language.shapes[i]; + if (shape->gems_use.whole == 0) + continue; + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + shape->id); + } + break; + } + case df::enums::item_type::BOX: + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(0); + mat_def->set_id("BOX_CHEST"); + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(1); + mat_def->set_id("BOX_BAG"); + break; + } + } + int subtypes = Items::getSubtypeCount(it); + if (subtypes >= 0) + { + for (int i = 0; i < subtypes; i++) + { + mat_def = out->add_material_list(); + mat_def->mutable_mat_pair()->set_mat_type((int)it); + mat_def->mutable_mat_pair()->set_mat_index(i); + df::itemdef * item = Items::getSubtypeDef(it, i); + mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + item->id); + } + } + } + return CR_OK; +} diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h new file mode 100644 index 000000000..45f8c1a95 --- /dev/null +++ b/plugins/remotefortressreader/item_reader.h @@ -0,0 +1,25 @@ +#ifndef ITEM_READER_H +#define ITEM_READER_H + +#include +#include "RemoteClient.h" +#include "RemoteFortressReader.pb.h" + +#include "DataDefs.h" + +namespace df +{ + struct item; + struct map_block; +} + +namespace MapExtras +{ + struct MapCache; +} + +DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::MaterialList *out); +void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); +void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out); + +#endif // !ITEM_READER_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 3e850d20b..450333088 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -60,15 +60,7 @@ #include "df/enabler.h" #include "df/graphic.h" #include "df/historical_figure.h" -#include "df/item.h" -#include "df/item_constructed.h" -#include "df/item_gemst.h" -#include "df/item_threadst.h" -#include "df/item_toolst.h" -#include "df/item_smallgemst.h" -#include "df/itemimprovement.h" -#include "df/itemimprovement_threadst.h" -#include "df/itemdef.h" + #include "df/job.h" #include "df/job_type.h" #include "df/job_item.h" @@ -96,8 +88,8 @@ #include "df/ui.h" #include "df/unit.h" #include "df/unit_inventory_item.h" -#include "df/vehicle.h" #include "df/viewscreen_choose_start_sitest.h" +#include "df/vehicle.h" #include "df/world.h" #include "df/world_data.h" #include "df/world_geo_biome.h" @@ -121,6 +113,7 @@ #include "adventure_control.h" #include "building_reader.h" +#include "item_reader.h" using namespace DFHack; using namespace df::enums; @@ -153,7 +146,6 @@ static command_result GetUnitListInside(color_ostream &stream, const BlockReques static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in, ViewInfo *out); static command_result GetMapInfo(color_ostream &stream, const EmptyMessage *in, MapInfo *out); static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in); -static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out); static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out); @@ -169,7 +161,6 @@ static command_result SendDigCommand(color_ostream &stream, const DigCommand *in static command_result SetPauseState(color_ostream & stream, const SingleBool * in); static command_result GetPauseState(color_ostream & stream, const EmptyMessage * in, SingleBool * out); static command_result GetVersionInfo(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::VersionInfo * out); -void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); static command_result GetReports(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Status * out); static command_result GetLanguage(color_ostream & stream, const EmptyMessage * in, RemoteFortressReader::Language * out); @@ -908,66 +899,6 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage return CR_OK; } -static command_result GetItemList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) -{ - if (!Core::getInstance().isWorldLoaded()) { - //out->set_available(false); - return CR_OK; - } - FOR_ENUM_ITEMS(item_type, it) - { - MaterialDefinition *mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(-1); - mat_def->set_id(ENUM_KEY_STR(item_type, it)); - switch (it) - { - case df::enums::item_type::GEM: - case df::enums::item_type::SMALLGEM: - { - for (int i = 0; i < world->raws.language.shapes.size(); i++) - { - auto shape = world->raws.language.shapes[i]; - if (shape->gems_use.whole == 0) - continue; - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(i); - mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + shape->id); - } - break; - } - case df::enums::item_type::BOX: - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(0); - mat_def->set_id("BOX_CHEST"); - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(1); - mat_def->set_id("BOX_BAG"); - break; - } - } - int subtypes = Items::getSubtypeCount(it); - if (subtypes >= 0) - { - for (int i = 0; i < subtypes; i++) - { - mat_def = out->add_material_list(); - mat_def->mutable_mat_pair()->set_mat_type((int)it); - mat_def->mutable_mat_pair()->set_mat_index(i); - df::itemdef * item = Items::getSubtypeDef(it, i); - mat_def->set_id(ENUM_KEY_STR(item_type, it) + "/" + item->id); - } - } - } - - - return CR_OK; -} - static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *in, MaterialList *out) { if (!Core::getInstance().isWorldLoaded()) { @@ -1403,92 +1334,6 @@ void Copyspatters(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetB } } -void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) -{ - NetItem->set_id(DfItem->id); - NetItem->set_flags1(DfItem->flags.whole); - NetItem->set_flags2(DfItem->flags2.whole); - auto pos = NetItem->mutable_pos(); - pos->set_x(DfItem->pos.x); - pos->set_y(DfItem->pos.y); - pos->set_z(DfItem->pos.z); - auto mat = NetItem->mutable_material(); - mat->set_mat_index(DfItem->getMaterialIndex()); - mat->set_mat_type(DfItem->getMaterial()); - auto type = NetItem->mutable_type(); - type->set_mat_type(DfItem->getType()); - type->set_mat_index(DfItem->getSubtype()); - - bool isProjectile = false; - - if (!isProjectile && DfItem->getType() == item_type::TOOL) - { - VIRTUAL_CAST_VAR(tool, df::item_toolst, DfItem); - if (tool) - { - auto vehicle = binsearch_in_vector(world->vehicles.active, tool->vehicle_id); - if (vehicle) - { - NetItem->set_subpos_x(vehicle->offset_x / 100000.0); - NetItem->set_subpos_y(vehicle->offset_y / 100000.0); - NetItem->set_subpos_z(vehicle->offset_z / 140000.0); - } - } - } - - if (DfItem->getType() == item_type::BOX) - { - type->set_mat_index(DfItem->isBag()); - } - VIRTUAL_CAST_VAR(actual_item, df::item_actual, DfItem); - if (actual_item) - { - NetItem->set_stack_size(actual_item->stack_size); - } - VIRTUAL_CAST_VAR(gem_item, df::item_gemst, DfItem); - if (gem_item) - { - type->set_mat_index(gem_item->shape); - } - VIRTUAL_CAST_VAR(smallgem_item, df::item_smallgemst, DfItem); - if (smallgem_item) - { - type->set_mat_index(smallgem_item->shape); - } - VIRTUAL_CAST_VAR(constructed_item, df::item_constructed, DfItem); - if (constructed_item) - { - for (int i = 0; i < constructed_item->improvements.size(); i++) - { - auto improvement = constructed_item->improvements[i]; - if (!improvement || improvement->getType() != improvement_type::THREAD) - continue; - - auto improvement_thread = virtual_cast(improvement); - if (!improvement_thread || improvement_thread->dye.mat_type < 0) - continue; - - DFHack::MaterialInfo info; - if (!info.decode(improvement_thread->dye.mat_type, improvement_thread->dye.mat_index)) - continue; - - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } - else if (DfItem->getType() == item_type::THREAD) - { - auto thread = virtual_cast(DfItem); - if (thread && thread->dye_mat_type >= 0) - { - DFHack::MaterialInfo info; - if (info.decode(thread->dye_mat_type, thread->dye_mat_index)) - ConvertDFColorDescriptor(info.material->powder_dye, NetItem->mutable_dye()); - } - } - - NetItem->set_volume(DfItem->getVolume()); -} - void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos) { NetBlock->set_map_x(DfBlock->map_pos.x); @@ -1498,13 +1343,13 @@ void CopyItems(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc { int id = DfBlock->items[i]; - auto item = df::item::find(id); if (item) CopyItem(NetBlock->add_items(), item); } } + static command_result GetBlockList(color_ostream &stream, const BlockRequest *in, BlockList *out) { int x, y, z; @@ -1684,7 +1529,7 @@ static command_result GetPlantList(color_ostream &stream, const BlockRequest *in out_plant->set_pos_y(plant->pos.y); out_plant->set_pos_z(plant->pos.z); } - } +} #endif return CR_OK; } @@ -2017,7 +1862,7 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, } else out->add_water_elevation(99); - } +} DFCoord pos = GetMapCenter(); out->set_center_x(pos.x); out->set_center_y(pos.y); From f2890620d1a0b9c3bd9616195f7e260d46ca5324 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 01:05:33 -0500 Subject: [PATCH 096/170] Remove tweak kitchen-keys - DF bug 614 was fixed --- dfhack.init-example | 1 - docs/Plugins.rst | 1 - plugins/tweak/tweak.cpp | 6 --- plugins/tweak/tweaks/kitchen-keys.h | 68 ----------------------------- 4 files changed, 76 deletions(-) delete mode 100644 plugins/tweak/tweaks/kitchen-keys.h diff --git a/dfhack.init-example b/dfhack.init-example index 3542956ce..75552006e 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -207,7 +207,6 @@ tweak civ-view-agreement tweak eggs-fertile tweak fps-min tweak hide-priority -tweak kitchen-keys tweak kitchen-prefs-empty tweak max-wheelbarrow tweak shift-8-scroll diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 0ed65c4a3..04f5df321 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -311,7 +311,6 @@ Subcommands that persist until disabled or DF quits: :import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison -:kitchen-keys: Fixes DF kitchen meal keybindings (:bug:`614`) :kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences :kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs (:bug:`9000`) :max-wheelbarrow: Allows assigning more than 3 wheelbarrows to a stockpile diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 417784efb..252f4c738 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -94,7 +94,6 @@ #include "tweaks/hide-priority.h" #include "tweaks/hotkey-clear.h" #include "tweaks/import-priority-category.h" -#include "tweaks/kitchen-keys.h" #include "tweaks/kitchen-prefs-color.h" #include "tweaks/kitchen-prefs-empty.h" #include "tweaks/max-wheelbarrow.h" @@ -218,8 +217,6 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector (world->selected_building); - if (!ws) - return false; - if (ws->type != workshop_type::Kitchen) - return false; - return true; - } - - DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) - { - if (kitchen_in_add()) - { - for (int i = 0; i < 4; i++) - { - if (input->count(kitchen_bindings[i])) - { - ui_sidebar_menus->workshop_job.cursor = i; - input->clear(); - input->insert(df::interface_key::SELECT); - } - } - } - INTERPOSE_NEXT(feed)(input); - } - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - if (kitchen_in_add()) - for (int i = 0; i < 3; i++) - draw_binding(i, kitchen_bindings[i]); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(kitchen_keys_hook, feed); -IMPLEMENT_VMETHOD_INTERPOSE(kitchen_keys_hook, render); From 909776571e1f2730db61a4312f036cd8baad2c1c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 01:06:03 -0500 Subject: [PATCH 097/170] dwarfmonitor: support getSelectedUnit --- plugins/dwarfmonitor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 2ea811f38..1ee1c8db8 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1543,6 +1543,11 @@ public: dwarf_column.setHighlight(0); } + df::unit *getSelectedUnit() override + { + return (selected_column == 1) ? dwarf_column.getFirstSelectedElem() : nullptr; + } + void feed(set *input) { bool key_processed = false; @@ -1574,7 +1579,7 @@ public: } else if (input->count(interface_key::CUSTOM_SHIFT_Z)) { - df::unit *selected_unit = (selected_column == 1) ? dwarf_column.getFirstSelectedElem() : nullptr; + df::unit *selected_unit = getSelectedUnit(); if (selected_unit) { input->clear(); From 4e2c6194ca33252a64dfb69c43d7cec28e654338 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 01:06:55 -0500 Subject: [PATCH 098/170] dwarfmonitor: support poetic/musical/dance forms --- plugins/dwarfmonitor.cpp | 75 +++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 1ee1c8db8..18c7ac9b2 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -18,31 +18,34 @@ #include "modules/Translation.h" #include "modules/World.h" #include "modules/Maps.h" -#include "df/activity_event.h" + #include "df/activity_entry.h" -#include "df/unit_preference.h" -#include "df/unit_soul.h" +#include "df/activity_event.h" +#include "df/creature_raw.h" +#include "df/dance_form.h" +#include "df/descriptor_color.h" +#include "df/descriptor_shape.h" #include "df/item_type.h" - -#include "df/itemdef_weaponst.h" -#include "df/itemdef_trapcompst.h" -#include "df/itemdef_toyst.h" -#include "df/itemdef_toolst.h" -#include "df/itemdef_instrumentst.h" -#include "df/itemdef_armorst.h" #include "df/itemdef_ammost.h" -#include "df/itemdef_siegeammost.h" +#include "df/itemdef_armorst.h" +#include "df/itemdef_foodst.h" #include "df/itemdef_glovesst.h" -#include "df/itemdef_shoesst.h" -#include "df/itemdef_shieldst.h" #include "df/itemdef_helmst.h" +#include "df/itemdef_instrumentst.h" #include "df/itemdef_pantsst.h" -#include "df/itemdef_foodst.h" +#include "df/itemdef_shieldst.h" +#include "df/itemdef_shoesst.h" +#include "df/itemdef_siegeammost.h" +#include "df/itemdef_toolst.h" +#include "df/itemdef_toyst.h" +#include "df/itemdef_trapcompst.h" +#include "df/itemdef_weaponst.h" +#include "df/musical_form.h" +#include "df/poetic_form.h" #include "df/trapcomp_flags.h" -#include "df/creature_raw.h" +#include "df/unit_preference.h" +#include "df/unit_soul.h" #include "df/world_raws.h" -#include "df/descriptor_shape.h" -#include "df/descriptor_color.h" using std::deque; @@ -137,6 +140,14 @@ static string getUnitName(df::unit * unit) return label; } +template +static string getFormName(int32_t id, const string &default_ = "?") { + T *form = T::find(id); + if (form) + return Translation::TranslateName(&form->name); + return default_; +} + static void send_key(const df::interface_key &key) { set< df::interface_key > keys; @@ -1290,6 +1301,19 @@ struct preference_map case (T_type::LikeColor): label += "Color :" + raws.language.colors[pref.color_id]->name; break; + + case (T_type::LikePoeticForm): + label += "Poetry :" + getFormName(pref.poetic_form_id); + break; + + case (T_type::LikeMusicalForm): + label += "Music :" + getFormName(pref.musical_form_id); + break; + + case (T_type::LikeDanceForm): + label += "Dance :" + getFormName(pref.dance_form_id); + break; + } } }; @@ -1444,6 +1468,18 @@ public: return false; break; + case (T_type::LikePoeticForm): + return lhs.poetic_form_id == rhs.poetic_form_id; + break; + + case (T_type::LikeMusicalForm): + return lhs.musical_form_id == rhs.musical_form_id; + break; + + case (T_type::LikeDanceForm): + return lhs.dance_form_id == rhs.dance_form_id; + break; + default: return false; } @@ -1483,6 +1519,11 @@ public: case (T_type::LikeColor): return COLOR_BLUE; + case (T_type::LikePoeticForm): + case (T_type::LikeMusicalForm): + case (T_type::LikeDanceForm): + return COLOR_LIGHTCYAN; + default: return false; } From 5f588b376aee2503879629c9763205c0570d6c21 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 01:07:20 -0500 Subject: [PATCH 099/170] dwarfmonitor: make handling of unrecognized preferences more obvious --- plugins/dwarfmonitor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 18c7ac9b2..ef77d7ae3 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1212,6 +1212,7 @@ struct preference_map break; default: + label = string("UNKNOWN ") + ENUM_ATTR_STR(item_type, caption, pref.item_type); break; } @@ -1314,6 +1315,9 @@ struct preference_map label += "Dance :" + getFormName(pref.dance_form_id); break; + default: + label += string("UNKNOWN ") + ENUM_KEY_STR(unit_preference::T_type, pref.type); + break; } } }; @@ -1525,7 +1529,7 @@ public: return COLOR_LIGHTCYAN; default: - return false; + return COLOR_LIGHTMAGENTA; } return true; From 9515a9e4f5fac41589849cbbe4ddf4a449ac509b Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 01:13:08 -0500 Subject: [PATCH 100/170] dwarfmonitor: use interface_key overload of OutputHotkeyString, grey out unit option --- plugins/dwarfmonitor.cpp | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index ef77d7ae3..79211fabd 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -491,6 +491,8 @@ public: void render() { + using namespace df::enums::interface_key; + if (Screen::isDismissed(this)) return; @@ -504,18 +506,18 @@ public: int32_t y = gps->dimy - 4; int32_t x = 2; - OutputHotkeyString(x, y, "Leave", "Esc"); + OutputHotkeyString(x, y, "Leave", LEAVESCREEN); x += 13; string window_label = "Window Months: " + int_to_string(window_days / min_window); - OutputHotkeyString(x, y, window_label.c_str(), "*"); + OutputHotkeyString(x, y, window_label.c_str(), SECONDSCROLL_PAGEDOWN); ++y; x = 2; - OutputHotkeyString(x, y, "Fort Stats", "Shift-D"); + OutputHotkeyString(x, y, "Fort Stats", CUSTOM_SHIFT_D); x += 3; - OutputHotkeyString(x, y, "Zoom Unit", "Shift-Z"); + OutputHotkeyString(x, y, "Zoom Unit", CUSTOM_SHIFT_Z); } std::string getFocusString() { return "dwarfmonitor_dwarfstats"; } @@ -1099,6 +1101,8 @@ public: void render() { + using namespace df::enums::interface_key; + if (Screen::isDismissed(this)) return; @@ -1113,18 +1117,18 @@ public: int32_t y = gps->dimy - 4; int32_t x = 2; - OutputHotkeyString(x, y, "Leave", "Esc"); + OutputHotkeyString(x, y, "Leave", LEAVESCREEN); x += 13; string window_label = "Window Months: " + int_to_string(window_days / min_window); - OutputHotkeyString(x, y, window_label.c_str(), "*"); + OutputHotkeyString(x, y, window_label.c_str(), SECONDSCROLL_PAGEDOWN); ++y; x = 2; - OutputHotkeyString(x, y, "Dwarf Stats", "Shift-D"); + OutputHotkeyString(x, y, "Dwarf Stats", CUSTOM_SHIFT_D); x += 3; - OutputHotkeyString(x, y, "Zoom Unit", "Shift-Z"); + OutputHotkeyString(x, y, "Zoom Unit", CUSTOM_SHIFT_Z); } std::string getFocusString() { return "dwarfmonitor_fortstats"; } @@ -1660,6 +1664,8 @@ public: void render() { + using namespace df::enums::interface_key; + if (Screen::isDismissed(this)) return; @@ -1673,10 +1679,11 @@ public: int32_t y = gps->dimy - 3; int32_t x = 2; - OutputHotkeyString(x, y, "Leave", "Esc"); + OutputHotkeyString(x, y, "Leave", LEAVESCREEN); x += 2; - OutputHotkeyString(x, y, "Zoom Unit", "Shift-Z"); + OutputHotkeyString(x, y, "Zoom Unit", CUSTOM_SHIFT_Z, false, 0, + getSelectedUnit() ? COLOR_WHITE : COLOR_DARKGREY); } std::string getFocusString() { return "dwarfmonitor_preferences"; } From 7b16cf16199e1f4d3cc3c2334af688e598ad554e Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 09:54:33 -0500 Subject: [PATCH 101/170] dwarfmonitor: actually display creature names --- plugins/dwarfmonitor.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 79211fabd..b715f6351 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1233,15 +1233,13 @@ struct preference_map { case (T_type::LikeCreature): { - label = "Creature :"; - Units::getRaceNamePluralById(pref.creature_id); + label = "Creature :" + Units::getRaceNamePluralById(pref.creature_id); break; } case (T_type::HateCreature): { - label = "Hates :"; - Units::getRaceNamePluralById(pref.creature_id); + label = "Hates :" + Units::getRaceNamePluralById(pref.creature_id); break; } From b035d9e53ad97fdf4a897a96a6c25e51d0995912 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 10:05:31 -0500 Subject: [PATCH 102/170] ListColumn: only change items' foreground color in selected columns --- plugins/listcolumn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/listcolumn.h b/plugins/listcolumn.h index 4e4815b69..f7747d96d 100644 --- a/plugins/listcolumn.h +++ b/plugins/listcolumn.h @@ -113,7 +113,7 @@ public: for (int i = display_start_offset; i < display_list.size() && i < last_index_able_to_display; i++) { ++y; - UIColor fg_color = (display_list[i]->selected) ? COLOR_SELECTED : display_list[i]->color; + UIColor fg_color = (is_selected_column && display_list[i]->selected) ? COLOR_SELECTED : display_list[i]->color; UIColor bg_color = (is_selected_column && i == highlighted_index) ? COLOR_HIGHLIGHTED : COLOR_BLACK; string item_label = display_list[i]->text; From 74aefddd75b3153c2ea215de82a29f2da9ba3208 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 10:17:40 -0500 Subject: [PATCH 103/170] dwarfmonitor: Use a reasonable default for unhandled item types --- plugins/dwarfmonitor.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index b715f6351..6f5481369 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1216,7 +1216,18 @@ struct preference_map break; default: - label = string("UNKNOWN ") + ENUM_ATTR_STR(item_type, caption, pref.item_type); + label = ENUM_ATTR_STR(item_type, caption, pref.item_type); + if (label.size()) + { + if (label[label.size() - 1] == 's') + label += "es"; + else + label += "s"; + } + else + { + label = "UNKNOWN"; + } break; } From 1ed6c70663d4ada28538d56138ecbcee58ee47fe Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 18 Jan 2018 10:17:54 -0500 Subject: [PATCH 104/170] dwarfmonitor: Add "view unit" option to prefs screen --- plugins/dwarfmonitor.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 6f5481369..7aed7188d 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -45,6 +45,7 @@ #include "df/trapcomp_flags.h" #include "df/unit_preference.h" #include "df/unit_soul.h" +#include "df/viewscreen_unitst.h" #include "df/world_raws.h" using std::deque; @@ -1345,14 +1346,14 @@ public: preferences_column.auto_select = true; preferences_column.setTitle("Preference"); preferences_column.bottom_margin = 3; - preferences_column.search_margin = 35; + preferences_column.search_margin = 50; dwarf_column.multiselect = false; dwarf_column.auto_select = true; dwarf_column.allow_null = true; dwarf_column.setTitle("Units with Preference"); dwarf_column.bottom_margin = 3; - dwarf_column.search_margin = 35; + dwarf_column.search_margin = 50; populatePreferencesColumn(); } @@ -1635,6 +1636,16 @@ public: Screen::dismiss(this); return; } + else if (input->count(interface_key::CUSTOM_SHIFT_V)) + { + df::unit *unit = getSelectedUnit(); + if (unit) + { + auto unitscr = df::allocate(); + unitscr->unit = unit; + Screen::show(unitscr); + } + } else if (input->count(interface_key::CUSTOM_SHIFT_Z)) { df::unit *selected_unit = getSelectedUnit(); @@ -1690,6 +1701,10 @@ public: int32_t x = 2; OutputHotkeyString(x, y, "Leave", LEAVESCREEN); + x += 2; + OutputHotkeyString(x, y, "View Unit", CUSTOM_SHIFT_V, false, 0, + getSelectedUnit() ? COLOR_WHITE : COLOR_DARKGREY); + x += 2; OutputHotkeyString(x, y, "Zoom Unit", CUSTOM_SHIFT_Z, false, 0, getSelectedUnit() ? COLOR_WHITE : COLOR_DARKGREY); From 58bef276de608cc92823e6d685971edcec035540 Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 19 Jan 2018 08:25:16 +0530 Subject: [PATCH 105/170] send item imrpovements --- plugins/proto/RemoteFortressReader.proto | 4 ++-- plugins/remotefortressreader/item_reader.cpp | 23 ++++++++++++++++++-- plugins/remotefortressreader/item_reader.h | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 463e368fc..ef32b9b81 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -907,8 +907,8 @@ enum ImprovementType message ItemImprovement { - optional MatPair mat_type = 1; + optional MatPair material = 1; optional ImprovementType type = 2; optional int32 shape = 3; - + optional int32 specific_type= 4; } diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 256d78fd9..ed9c5f204 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -8,6 +8,9 @@ #include "df/item_toolst.h" #include "df/item_smallgemst.h" #include "df/itemimprovement.h" +#include "df/itemimprovement_bandsst.h" +#include "df/itemimprovement_coveredst.h" +#include "df/itemimprovement_itemspecificst.h" #include "df/itemimprovement_threadst.h" #include "df/itemdef.h" #include "df/map_block.h" @@ -287,22 +290,38 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) improvement_type::improvement_type impType = improvement->getType(); + auto netImp = NetItem->add_improvements(); + + netImp->set_type((ImprovementType)impType); + + auto mat = netImp->mutable_material(); + mat->set_mat_type(improvement->mat_type); + mat->set_mat_index(improvement->mat_index); + switch (impType) { case df::enums::improvement_type::ART_IMAGE: break; case df::enums::improvement_type::COVERED: { + VIRTUAL_CAST_VAR(covered, df::itemimprovement_coveredst, improvement); + netImp->set_shape(covered->shape); break; } case df::enums::improvement_type::RINGS_HANGING: break; case df::enums::improvement_type::BANDS: + { + VIRTUAL_CAST_VAR(bands, df::itemimprovement_bandsst, improvement); + netImp->set_shape(bands->shape); break; - case df::enums::improvement_type::SPIKES: - break; + } case df::enums::improvement_type::ITEMSPECIFIC: + { + VIRTUAL_CAST_VAR(specific, df::itemimprovement_itemspecificst, improvement); + netImp->set_specific_type(specific->type); break; + } case df::enums::improvement_type::THREAD: { VIRTUAL_CAST_VAR(improvement_thread, df::itemimprovement_threadst, improvement); diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h index 45f8c1a95..2bd8e7c89 100644 --- a/plugins/remotefortressreader/item_reader.h +++ b/plugins/remotefortressreader/item_reader.h @@ -15,7 +15,7 @@ namespace df namespace MapExtras { - struct MapCache; + class MapCache; } DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::MaterialList *out); From 771b88c6c4db78e0658b81c82a17d3b2da0944da Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 21 Jan 2018 17:44:31 -0500 Subject: [PATCH 106/170] Update scripts, authors, dfhack.init-example for dfhack/scripts#43 --- dfhack.init-example | 3 +++ docs/Authors.rst | 1 + scripts | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dfhack.init-example b/dfhack.init-example index 75552006e..82210a2a6 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -55,6 +55,9 @@ keybinding add Alt-S@dwarfmode/Default gui/settings-manager # change quantity of manager orders keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity +# view combat reports for the selected unit/corpse/spatter +keybinding add Ctrl-Shift-R view-unit-reports + ############################## # Generic adv mode bindings # ############################## diff --git a/docs/Authors.rst b/docs/Authors.rst index 0f7e06811..8c1b5096e 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -28,6 +28,7 @@ Carter Bray Qartar Chris Dombroski cdombroski Clayton Hughes ClĂ©ment Vuchener cvuchener +Dan Amlund danamlund David Corbett dscorbett David Seguin dseguin Deon diff --git a/scripts b/scripts index 2d4093e61..e65369e58 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2d4093e61ea2a02742a6bfbfd80e49eb6dcdd549 +Subproject commit e65369e58f5bc2819641e4633424aa8922cf9b1b From 1ba5477b63067c5b86c46c0df05428776378557a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 21 Jan 2018 19:27:16 -0500 Subject: [PATCH 107/170] Add designation priority support to MapCache and dig plugin Fixes #481 --- library/include/modules/MapCache.h | 27 ++++++- library/include/modules/Maps.h | 4 +- library/modules/MapCache.cpp | 40 +++++++++- library/modules/Maps.cpp | 7 +- plugins/dig.cpp | 115 +++++++++++++++++++++-------- 5 files changed, 157 insertions(+), 36 deletions(-) diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index 0048f5bd9..36625719b 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -276,6 +276,9 @@ public: return true; } + int32_t priorityAt(df::coord2d p); + bool setPriorityAt(df::coord2d p, int32_t priority); + df::tile_occupancy OccupancyAt(df::coord2d p) { return index_tile(occupancy,p); @@ -544,13 +547,31 @@ class DFHACK_EXPORT MapCache Block * b= BlockAtTile(tilecoord); return b ? b->DesignationAt(tilecoord) : df::tile_designation(); } - bool setDesignationAt (DFCoord tilecoord, df::tile_designation des) + // priority is optional, only set if >= 0 + bool setDesignationAt (DFCoord tilecoord, df::tile_designation des, int32_t priority = -1) { - if(Block * b= BlockAtTile(tilecoord)) - return b->setDesignationAt(tilecoord, des); + if (Block *b = BlockAtTile(tilecoord)) + { + if (!b->setDesignationAt(tilecoord, des)) + return false; + if (priority >= 0 && b->setPriorityAt(tilecoord, priority)) + return false; + return true; + } return false; } + int32_t priorityAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->priorityAt(tilecoord) : -1; + } + bool setPriorityAt (DFCoord tilecoord, int32_t priority) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->setPriorityAt(tilecoord, priority) : false; + } + df::tile_occupancy occupancyAt (DFCoord tilecoord) { Block * b= BlockAtTile(tilecoord); diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index fb5fc9860..6b6e62f0a 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -46,6 +46,7 @@ distribution. namespace df { struct block_square_event; + struct block_square_event_designation_priorityst; struct block_square_event_frozen_liquidst; struct block_square_event_grassst; struct block_square_event_item_spatterst; @@ -321,7 +322,8 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, std::vector* grass = 0, std::vector* constructions = 0, std::vector* spoors = 0, - std::vector* items = 0 + std::vector* items = 0, + std::vector* priorities = 0 ); /// remove a block event from the block by address diff --git a/library/modules/MapCache.cpp b/library/modules/MapCache.cpp index fb4aef935..ffb9fc769 100644 --- a/library/modules/MapCache.cpp +++ b/library/modules/MapCache.cpp @@ -49,8 +49,9 @@ using namespace std; #include "df/block_burrow.h" #include "df/block_burrow_link.h" -#include "df/block_square_event_grassst.h" +#include "df/block_square_event_designation_priorityst.h" #include "df/block_square_event_frozen_liquidst.h" +#include "df/block_square_event_grassst.h" #include "df/building_type.h" #include "df/builtin_mats.h" #include "df/burrow.h" @@ -271,6 +272,43 @@ bool MapExtras::Block::setTiletypeAt(df::coord2d pos, df::tiletype tt, bool forc return true; } +static df::block_square_event_designation_priorityst *getPriorityEvent(df::map_block *block, bool write) +{ + vector events; + Maps::SortBlockEvents(block, 0, 0, 0, 0, 0, 0, 0, &events); + if (events.empty()) + { + if (!write) + return NULL; + + auto event = df::allocate(); + block->block_events.push_back((df::block_square_event*)event); + return event; + } + return events[0]; +} + +int32_t MapExtras::Block::priorityAt(df::coord2d pos) +{ + if (!block) + return false; + + if (auto event = getPriorityEvent(block, false)) + return event->priority[pos.x % 16][pos.y % 16]; + + return 0; +} + +bool MapExtras::Block::setPriorityAt(df::coord2d pos, int32_t priority) +{ + if (!block || priority < 0) + return false; + + auto event = getPriorityEvent(block, true); + event->priority[pos.x % 16][pos.y % 16] = priority; + return true; +} + bool MapExtras::Block::setVeinMaterialAt(df::coord2d pos, int16_t mat, df::inclusion_type type) { using namespace df::enums::tiletype_material; diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 2b2311a7c..20255dbe3 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -402,7 +402,8 @@ bool Maps::SortBlockEvents(df::map_block *block, vector *grasses, vector *constructions, vector *spoors, - vector *items) + vector *items, + vector *priorities) { if (veins) veins->clear(); @@ -456,6 +457,10 @@ bool Maps::SortBlockEvents(df::map_block *block, if (items) items->push_back((df::block_square_event_item_spatterst *)evt); break; + case block_square_event_type::designation_priority: + if (priorities) + priorities->push_back((df::block_square_event_designation_priorityst *)evt); + break; } } return true; diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 5404f2f2d..a56688a7b 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1,16 +1,23 @@ +#include +#include +#include +#include +#include +#include + #include "Core.h" #include "Console.h" #include "Export.h" #include "PluginManager.h" -#include "modules/Maps.h" +#include "uicommon.h" + #include "modules/Gui.h" #include "modules/MapCache.h" +#include "modules/Maps.h" #include "modules/Materials.h" -#include -#include -#include -#include -#include + +#include "df/ui_sidebar_menus.h" + using std::vector; using std::string; using std::stack; @@ -27,6 +34,7 @@ command_result digcircle (color_ostream &out, vector & parameters); command_result digtype (color_ostream &out, vector & parameters); DFHACK_PLUGIN("dig"); +REQUIRE_GLOBAL(ui_sidebar_menus); REQUIRE_GLOBAL(world); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) @@ -97,6 +105,7 @@ enum circle_what bool dig (MapExtras::MapCache & MCache, circle_what what, df::tile_dig_designation type, + int32_t priority, int32_t x, int32_t y, int32_t z, int x_max, int y_max ) @@ -175,20 +184,21 @@ bool dig (MapExtras::MapCache & MCache, break; } std::cerr << "allowing tt" << (int)tt << "\n"; - MCache.setDesignationAt(at,des); + MCache.setDesignationAt(at,des,priority); return true; }; bool lineX (MapExtras::MapCache & MCache, circle_what what, df::tile_dig_designation type, + int32_t priority, int32_t y1, int32_t y2, int32_t x, int32_t z, int x_max, int y_max ) { for(int32_t y = y1; y <= y2; y++) { - dig(MCache, what, type,x,y,z, x_max, y_max); + dig(MCache, what, type, priority, x,y,z, x_max, y_max); } return true; }; @@ -196,17 +206,51 @@ bool lineX (MapExtras::MapCache & MCache, bool lineY (MapExtras::MapCache & MCache, circle_what what, df::tile_dig_designation type, + int32_t priority, int32_t x1, int32_t x2, int32_t y, int32_t z, int x_max, int y_max ) { for(int32_t x = x1; x <= x2; x++) { - dig(MCache, what, type,x,y,z, x_max, y_max); + dig(MCache, what, type, priority, x,y,z, x_max, y_max); } return true; }; +int32_t parse_priority(color_ostream &out, vector ¶meters) +{ + int32_t default_priority = ui_sidebar_menus->designation.priority; + + for (auto it = parameters.begin(); it != parameters.end(); ++it) + { + const string &s = *it; + if (s.substr(0, 2) == "p=" || s.substr(0, 2) == "-p") + { + if (s.size() >= 3) + { + auto priority = int32_t(1000 * atof(s.c_str() + 2)); + parameters.erase(it); + return priority; + } + else if (it + 1 != parameters.end()) + { + auto priority = int32_t(1000 * atof((*(it + 1)).c_str())); + parameters.erase(it); + parameters.erase(it + 1); + return priority; + } + else + { + out.printerr("invalid priority specified; reverting to %i\n", default_priority); + break; + } + } + } + + return default_priority; +} + command_result digcircle (color_ostream &out, vector & parameters) { static bool filled = false; @@ -215,6 +259,8 @@ command_result digcircle (color_ostream &out, vector & parameters) static int diameter = 0; auto saved_d = diameter; bool force_help = false; + int32_t priority = parse_priority(out, parameters); + for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") @@ -326,12 +372,12 @@ command_result digcircle (color_ostream &out, vector & parameters) // paint center if(filled) { - lineY(MCache,what,type, cx - r, cx + r, cy, cz,x_max,y_max); + lineY(MCache, what, type, priority, cx - r, cx + r, cy, cz, x_max, y_max); } else { - dig(MCache, what, type,cx - r, cy, cz,x_max,y_max); - dig(MCache, what, type,cx + r, cy, cz,x_max,y_max); + dig(MCache, what, type, priority, cx - r, cy, cz, x_max, y_max); + dig(MCache, what, type, priority, cx + r, cy, cz, x_max, y_max); } adjust = false; iter = 2; @@ -363,24 +409,24 @@ command_result digcircle (color_ostream &out, vector & parameters) // paint if(filled || iter == diameter - 1) { - lineY(MCache,what,type, left, right, top , cz,x_max,y_max); - lineY(MCache,what,type, left, right, bottom , cz,x_max,y_max); + lineY(MCache, what, type, priority, left, right, top, cz, x_max, y_max); + lineY(MCache, what, type, priority, left, right, bottom, cz, x_max, y_max); } else { - dig(MCache, what, type,left, top, cz,x_max,y_max); - dig(MCache, what, type,left, bottom, cz,x_max,y_max); - dig(MCache, what, type,right, top, cz,x_max,y_max); - dig(MCache, what, type,right, bottom, cz,x_max,y_max); + dig(MCache, what, type, priority, left, top, cz, x_max, y_max); + dig(MCache, what, type, priority, left, bottom, cz, x_max, y_max); + dig(MCache, what, type, priority, right, top, cz, x_max, y_max); + dig(MCache, what, type, priority, right, bottom, cz, x_max, y_max); } if(!filled && diff > 1) { int lright = cx + lastwhole; int lleft = cx - lastwhole + adjust; - lineY(MCache,what,type, lleft + 1, left - 1, top + 1 , cz,x_max,y_max); - lineY(MCache,what,type, right + 1, lright - 1, top + 1 , cz,x_max,y_max); - lineY(MCache,what,type, lleft + 1, left - 1, bottom - 1 , cz,x_max,y_max); - lineY(MCache,what,type, right + 1, lright - 1, bottom - 1 , cz,x_max,y_max); + lineY(MCache, what, type, priority, lleft + 1, left - 1, top + 1 , cz, x_max, y_max); + lineY(MCache, what, type, priority, right + 1, lright - 1, top + 1 , cz, x_max, y_max); + lineY(MCache, what, type, priority, lleft + 1, left - 1, bottom - 1 , cz, x_max, y_max); + lineY(MCache, what, type, priority, right + 1, lright - 1, bottom - 1 , cz, x_max, y_max); } lastwhole = whole; } @@ -808,6 +854,8 @@ command_result digexp (color_ostream &out, vector & parameters) bool force_help = false; static explo_how how = EXPLO_NOTHING; static explo_what what = EXPLO_HIDDEN; + int32_t priority = parse_priority(out, parameters); + for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") @@ -963,7 +1011,7 @@ command_result digexp (color_ostream &out, vector & parameters) if(cross[y][x]) { des.bits.dig = tile_dig_designation::Default; - mx.setDesignationAt(pos,des); + mx.setDesignationAt(pos,des,priority); } } mx.WriteAll(); @@ -984,6 +1032,7 @@ command_result digvx (color_ostream &out, vector & parameters) // HOTKEY COMMAND: CORE ALREADY SUSPENDED vector lol; lol.push_back("x"); + lol.push_back(string("-p") + int_to_string(parse_priority(out, parameters))); return digv(out,lol); } @@ -992,6 +1041,8 @@ command_result digv (color_ostream &out, vector & parameters) // HOTKEY COMMAND: CORE ALREADY SUSPENDED uint32_t x_max,y_max,z_max; bool updown = false; + int32_t priority = parse_priority(out, parameters); + for(size_t i = 0; i < parameters.size();i++) { if(parameters.size() && parameters[0]=="x") @@ -1118,7 +1169,7 @@ command_result digv (color_ostream &out, vector & parameters) des_minus.bits.dig = tile_dig_designation::UpDownStair; else des_minus.bits.dig = tile_dig_designation::UpStair; - MCache->setDesignationAt(current-1,des_minus); + MCache->setDesignationAt(current-1,des_minus,priority); des.bits.dig = tile_dig_designation::DownStair; } @@ -1130,7 +1181,7 @@ command_result digv (color_ostream &out, vector & parameters) des_plus.bits.dig = tile_dig_designation::UpDownStair; else des_plus.bits.dig = tile_dig_designation::DownStair; - MCache->setDesignationAt(current+1,des_plus); + MCache->setDesignationAt(current+1,des_plus,priority); if(des.bits.dig == tile_dig_designation::DownStair) des.bits.dig = tile_dig_designation::UpDownStair; @@ -1140,7 +1191,7 @@ command_result digv (color_ostream &out, vector & parameters) } if(des.bits.dig == tile_dig_designation::No) des.bits.dig = tile_dig_designation::Default; - MCache->setDesignationAt(current,des); + MCache->setDesignationAt(current,des,priority); } } MCache->WriteAll(); @@ -1153,6 +1204,7 @@ command_result diglx (color_ostream &out, vector & parameters) // HOTKEY COMMAND: CORE ALREADY SUSPENDED vector lol; lol.push_back("x"); + lol.push_back(string("-p") + int_to_string(parse_priority(out, parameters))); return digl(out,lol); } @@ -1168,6 +1220,8 @@ command_result digl (color_ostream &out, vector & parameters) uint32_t x_max,y_max,z_max; bool updown = false; bool undo = false; + int32_t priority = parse_priority(out, parameters); + for(size_t i = 0; i < parameters.size();i++) { if(parameters[i]=="x") @@ -1326,7 +1380,7 @@ command_result digl (color_ostream &out, vector & parameters) // undo mode: clear designation if(undo) des_minus.bits.dig = tile_dig_designation::No; - MCache->setDesignationAt(current-1,des_minus); + MCache->setDesignationAt(current-1,des_minus,priority); des.bits.dig = tile_dig_designation::DownStair; } @@ -1341,7 +1395,7 @@ command_result digl (color_ostream &out, vector & parameters) // undo mode: clear designation if(undo) des_plus.bits.dig = tile_dig_designation::No; - MCache->setDesignationAt(current+1,des_plus); + MCache->setDesignationAt(current+1,des_plus,priority); if(des.bits.dig == tile_dig_designation::DownStair) des.bits.dig = tile_dig_designation::UpDownStair; @@ -1354,7 +1408,7 @@ command_result digl (color_ostream &out, vector & parameters) // undo mode: clear designation if(undo) des.bits.dig = tile_dig_designation::No; - MCache->setDesignationAt(current,des); + MCache->setDesignationAt(current,des,priority); } } MCache->WriteAll(); @@ -1371,6 +1425,7 @@ command_result digauto (color_ostream &out, vector & parameters) command_result digtype (color_ostream &out, vector & parameters) { //mostly copy-pasted from digv + int32_t priority = parse_priority(out, parameters); CoreSuspender suspend; if ( parameters.size() > 1 ) { @@ -1474,7 +1529,7 @@ command_result digtype (color_ostream &out, vector & parameters) df::tile_designation designation = mCache->designationAt(current); designation.bits.dig = baseDes.bits.dig; - mCache->setDesignationAt(current, designation); + mCache->setDesignationAt(current, designation,priority); } } } From f75b116ae28ed06fe945141899c6db79947660c7 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 24 Jan 2018 10:22:45 +0530 Subject: [PATCH 108/170] Added the rest of the relavent improvement headers. --- plugins/remotefortressreader/item_reader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index ed9c5f204..e0a6ff831 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -8,9 +8,13 @@ #include "df/item_toolst.h" #include "df/item_smallgemst.h" #include "df/itemimprovement.h" +#include "df/itemimprovement_art_imagest.h" #include "df/itemimprovement_bandsst.h" #include "df/itemimprovement_coveredst.h" +#include "df/itemimprovement_illustrationst.h" #include "df/itemimprovement_itemspecificst.h" +#include "df/itemimprovement_sewn_imagest.h" +#include "df/itemimprovement_specific_type.h" #include "df/itemimprovement_threadst.h" #include "df/itemdef.h" #include "df/map_block.h" From ee7ad348f0e413d4f3a47c3484985d7e679b0cef Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 24 Jan 2018 12:09:05 +0530 Subject: [PATCH 109/170] add item images --- plugins/proto/RemoteFortressReader.proto | 24 ++++++ plugins/remotefortressreader/item_reader.cpp | 81 ++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index ef32b9b81..02a4474a1 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -911,4 +911,28 @@ message ItemImprovement optional ImprovementType type = 2; optional int32 shape = 3; optional int32 specific_type= 4; + optional ArtImage image = 5; } + +enum ArtImageElementType +{ + IMAGE_CREATURE = 0; + IMAGE_PLANT = 1; + IMAGE_TREE = 2; + IMAGE_SHAPE = 3; + IMAGE_ITEM = 4; +} + +message ArtImageElement +{ + optional int32 count = 1; + optional ArtImageElementType type = 2; + optional MatPair creature_item = 3; + optional MatPair material = 5; + optional int32 id = 6; +} + +message ArtImage +{ + repeated ArtImageElement elements = 1; +} \ No newline at end of file diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index e0a6ff831..99bcbd760 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -1,5 +1,15 @@ #include "item_reader.h" +#include "df/art_image.h" +#include "df/art_image_chunk.h" +#include "df/art_image_element.h" +#include "df/art_image_element_creaturest.h" +#include "df/art_image_element_itemst.h" +#include "df/art_image_element_plantst.h" +#include "df/art_image_element_shapest.h" +#include "df/art_image_element_treest.h" +#include "df/art_image_element_type.h" +#include "df/art_image_ref.h" #include "df/descriptor_shape.h" #include "df/item_type.h" #include "df/item_constructed.h" @@ -34,6 +44,75 @@ using namespace std; using namespace df::global; +void CopyImage(const df::art_image * image, ArtImage * netImage) +{ + for (int i = 0; i < image->elements.size(); i++) + { + auto element = image->elements[i]; + auto netElement = netImage->add_elements(); + auto elementType = element->getType(); + netElement->set_type((ArtImageElementType)elementType); + + netElement->set_count(element->count); + + switch (elementType) + { + case df::enums::art_image_element_type::CREATURE: + { + VIRTUAL_CAST_VAR(creature, df::art_image_element_creaturest, element); + auto cret = netElement->mutable_creature_item(); + cret->set_mat_type(creature->race); + cret->set_mat_index(creature->caste); + break; + } + case df::enums::art_image_element_type::PLANT: + { + VIRTUAL_CAST_VAR(plant, df::art_image_element_plantst, element); + netElement->set_id(plant->plant_id); + break; + } + case df::enums::art_image_element_type::TREE: + { + VIRTUAL_CAST_VAR(tree, df::art_image_element_treest, element); + netElement->set_id(tree->plant_id); + break; + } + case df::enums::art_image_element_type::SHAPE: + { + VIRTUAL_CAST_VAR(shape, df::art_image_element_shapest, element); + netElement->set_id(shape->shape_id); + break; + } + case df::enums::art_image_element_type::ITEM: + { + VIRTUAL_CAST_VAR(item, df::art_image_element_itemst, element); + auto it = netElement->mutable_creature_item(); + it->set_mat_type(item->item_type); + it->set_mat_index(item->item_subtype); + netElement->set_id(item->item_id); + auto mat = netElement->mutable_material(); + mat->set_mat_type(item->mat_type); + mat->set_mat_index(item->mat_index); + break; + } + default: + break; + } + } +} + +void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) +{ + for (int i = 0; i < world->art_image_chunks.size(); i++) + { + auto chunk = world->art_image_chunks[i]; + if (chunk->id != imageRef.id) + continue; + auto image = chunk->images[imageRef.subid]; + CopyImage(image, netImage); + } +} + void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { NetItem->set_id(DfItem->id); @@ -305,6 +384,8 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) switch (impType) { case df::enums::improvement_type::ART_IMAGE: + VIRTUAL_CAST_VAR(artImage, df::itemimprovement_art_imagest, improvement); + CopyImage(artImage->image, netImp->mutable_image()); break; case df::enums::improvement_type::COVERED: { From 68324dfe0b3ad6c11a0b177d9e87bb49f91682a1 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 25 Jan 2018 07:53:19 +0530 Subject: [PATCH 110/170] Send statue images. --- plugins/proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader/item_reader.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 02a4474a1..0cdb41110 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -277,6 +277,7 @@ message Item optional float velocity_z = 15; optional int32 volume = 16; repeated ItemImprovement improvements = 17; + optional ArtImage image = 18; } message MapBlock diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 99bcbd760..36cbbb96e 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -14,9 +14,10 @@ #include "df/item_type.h" #include "df/item_constructed.h" #include "df/item_gemst.h" +#include "df/item_smallgemst.h" +#include "df/item_statuest.h" #include "df/item_threadst.h" #include "df/item_toolst.h" -#include "df/item_smallgemst.h" #include "df/itemimprovement.h" #include "df/itemimprovement_art_imagest.h" #include "df/itemimprovement_bandsst.h" @@ -186,7 +187,11 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) case df::enums::item_type::COFFIN: break; case df::enums::item_type::STATUE: + { + VIRTUAL_CAST_VAR(statue, df::item_statuest, DfItem); + CopyImage(statue->image, NetItem->mutable_image()); break; + } case df::enums::item_type::CORPSE: break; case df::enums::item_type::WEAPON: @@ -384,9 +389,11 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) switch (impType) { case df::enums::improvement_type::ART_IMAGE: + { VIRTUAL_CAST_VAR(artImage, df::itemimprovement_art_imagest, improvement); CopyImage(artImage->image, netImp->mutable_image()); break; + } case df::enums::improvement_type::COVERED: { VIRTUAL_CAST_VAR(covered, df::itemimprovement_coveredst, improvement); From f1b8fa305bedfc3b9909cc3f8b39d352a443f7e3 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 25 Jan 2018 11:55:46 +0530 Subject: [PATCH 111/170] try using the new function pointer. --- library/xml | 2 +- plugins/remotefortressreader/item_reader.cpp | 21 ++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/library/xml b/library/xml index f0c609211..618db6349 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f0c609211fbfd354b576cae75e9e64f8c6c80b06 +Subproject commit 618db6349ece5827d371a60b0fac1066b1d7989b diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 36cbbb96e..36d8f6ec9 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -104,13 +104,22 @@ void CopyImage(const df::art_image * image, ArtImage * netImage) void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) { - for (int i = 0; i < world->art_image_chunks.size(); i++) + if (df::global::getArtImage) { - auto chunk = world->art_image_chunks[i]; - if (chunk->id != imageRef.id) - continue; - auto image = chunk->images[imageRef.subid]; - CopyImage(image, netImage); + df::art_image * (*getImage)(df::art_image_ref *, int *) = (df::art_image * (*)(df::art_image_ref *, int *))df::global::getArtImage; + int subid = -1; + CopyImage(getImage(&imageRef, &subid), netImage); + } + else + { + for (int i = 0; i < world->art_image_chunks.size(); i++) + { + auto chunk = world->art_image_chunks[i]; + if (chunk->id != imageRef.id) + continue; + auto image = chunk->images[imageRef.subid]; + CopyImage(image, netImage); + } } } From ef451a2f2dff3ad659e506ee97636311d466f563 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 25 Jan 2018 20:24:12 +0530 Subject: [PATCH 112/170] Got the image reader function working. --- plugins/remotefortressreader/item_reader.cpp | 6 ++--- .../remotefortressreader.cpp | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 36d8f6ec9..93d6fe621 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -106,9 +106,9 @@ void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) { if (df::global::getArtImage) { - df::art_image * (*getImage)(df::art_image_ref *, int *) = (df::art_image * (*)(df::art_image_ref *, int *))df::global::getArtImage; + df::art_image * (__thiscall *getImage)(df::world*, df::art_image_ref *, int *) = (df::art_image * (__thiscall*)(df::world*, df::art_image_ref *, int *))df::global::getArtImage; int subid = -1; - CopyImage(getImage(&imageRef, &subid), netImage); + CopyImage(getImage(world, &imageRef, &subid), netImage); } else { @@ -456,7 +456,7 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) NetItem->set_volume(DfItem->getVolume()); } -DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::MaterialList *out) +DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::EmptyMessage *in, RemoteFortressReader::MaterialList *out) { if (!Core::getInstance().isWorldLoaded()) { //out->set_available(false); diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 450333088..d5f55eb95 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -179,6 +179,28 @@ const char* growth_locations[] = { }; #define GROWTH_LOCATIONS_SIZE 8 + +#include "df/art_image.h" +#include "df/art_image_chunk.h" +#include "df/art_image_ref.h" +command_result generate_image(color_ostream &out, vector & parameters) +{ + df::art_image_ref imageRef; + imageRef.civ_id = -1; + imageRef.id = -1; + imageRef.site_id = -1; + imageRef.subid = -1; + + if (df::global::getArtImage) + { + df::art_image * (__thiscall *getImage)(df::world*,df::art_image_ref *, int *) = (df::art_image * (__thiscall*)(df::world*, df::art_image_ref *, int *))df::global::getArtImage; + int subid = -1; + auto image = getImage(world,&imageRef, &subid); + out.print("Id: %d, subid: %d\n", image->id, image->subid); + } + return CR_OK; +} + command_result dump_bp_mods(color_ostream &out, vector & parameters) { remove("bp_appearance_mods.csv"); @@ -249,6 +271,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector Date: Thu, 25 Jan 2018 10:55:00 -0500 Subject: [PATCH 113/170] Add a dfhack.script_help() function to assist scripts --- docs/Lua API.rst | 6 +++++ library/lua/dfhack.lua | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 520ac243a..d79924cc1 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -3777,6 +3777,12 @@ Note that this function lets errors propagate to the caller. This is intended to only allow scripts that take appropriate action when used as a module to be loaded. +* ``dfhack.script_help([name, [extension]])`` + + Returns the contents of the embedded documentation of the specified script. + ``extension`` defaults to "lua", and ``name`` defaults to the name of the + script where this function was called. + Enabling and disabling scripts ============================== diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 340b6ce64..6acbe27e8 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -562,6 +562,61 @@ function dfhack.run_script_with_env(envVars, name, flags, ...) return script_code(...), env end +local function current_script_name() + local frame = 1 + while true do + local info = debug.getinfo(frame, 'f') + if not info then break end + if info.func == dfhack.run_script_with_env then + local i = 1 + while true do + local name, value = debug.getlocal(frame, i) + if not name then break end + if name == 'name' then + return value + end + i = i + 1 + end + break + end + frame = frame + 1 + end +end + +function dfhack.script_help(script_name, extension) + script_name = script_name or current_script_name() + extension = extension or 'lua' + local full_name = script_name .. '.' .. extension + local path = dfhack.internal.findScript(script_name .. '.' .. extension) + or error("Could not find script: " .. full_name) + local begin_seq, end_seq + if extension == 'rb' then + begin_seq = '=begin' + end_seq = '=end' + else + begin_seq = '[====[' + end_seq = ']====]' + end + local f = io.open(path) or error("Could not open " .. path) + local in_help = false + local help = '' + for line in f:lines() do + if line:endswith(begin_seq) then + in_help = true + elseif in_help then + if line:endswith(end_seq) then + break + end + if line ~= script_name and line ~= ('='):rep(#script_name) then + help = help .. line .. '\n' + end + end + end + f:close() + help = help:gsub('^\n+', ''):gsub('\n+$', '') + return help +end + local function _run_command(...) args = {...} if type(args[1]) == 'table' then From 5e0e674580df07fa6144545a096b2c56ec377d08 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 25 Jan 2018 10:56:08 -0500 Subject: [PATCH 114/170] Update submodules --- library/xml | 2 +- plugins/stonesense | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index 352e23310..f0c609211 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 352e233105512a702875f48d82f922f0c9ca3905 +Subproject commit f0c609211fbfd354b576cae75e9e64f8c6c80b06 diff --git a/plugins/stonesense b/plugins/stonesense index 4c55e1439..455b51aab 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 4c55e1439e4e9fa55f6b17147a346c9cde11f7b3 +Subproject commit 455b51aab7a93095a775285782635cfc17ac651a diff --git a/scripts b/scripts index e65369e58..cbdd03aae 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e65369e58f5bc2819641e4633424aa8922cf9b1b +Subproject commit cbdd03aae69ff6e96644e8169487eaa6b4019d52 From e3d95daf45f87eab53515975e779cf58aa80a595 Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 26 Jan 2018 08:19:41 +0530 Subject: [PATCH 115/170] Don't use globals --- library/xml | 2 +- plugins/remotefortressreader/item_reader.cpp | 6 ++++-- plugins/remotefortressreader/item_reader.h | 5 +++++ plugins/remotefortressreader/remotefortressreader.cpp | 9 +++++---- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/library/xml b/library/xml index 618db6349..9afe7c953 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 618db6349ece5827d371a60b0fac1066b1d7989b +Subproject commit 9afe7c9538f1bfa104c5eff54b0945eee32a76cc diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 93d6fe621..c57b90d7d 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -1,4 +1,6 @@ #include "item_reader.h" +#include "Core.h" +#include "VersionInfo.h" #include "df/art_image.h" #include "df/art_image_chunk.h" @@ -104,9 +106,9 @@ void CopyImage(const df::art_image * image, ArtImage * netImage) void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) { - if (df::global::getArtImage) + GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (getImage) { - df::art_image * (__thiscall *getImage)(df::world*, df::art_image_ref *, int *) = (df::art_image * (__thiscall*)(df::world*, df::art_image_ref *, int *))df::global::getArtImage; int subid = -1; CopyImage(getImage(world, &imageRef, &subid), netImage); } diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h index 2bd8e7c89..332280982 100644 --- a/plugins/remotefortressreader/item_reader.h +++ b/plugins/remotefortressreader/item_reader.h @@ -11,6 +11,9 @@ namespace df { struct item; struct map_block; + struct art_image; + struct art_image_ref; + struct world; } namespace MapExtras @@ -22,4 +25,6 @@ DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack:: void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out); +typedef df::art_image * (__thiscall *GET_IMAGE)(df::world*, df::art_image_ref *, int *); + #endif // !ITEM_READER_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index d5f55eb95..928b7a396 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -17,6 +17,7 @@ #include "SDL_events.h" #include "SDL_keyboard.h" #include "TileTypes.h" +#include "VersionInfo.h" #if DF_VERSION_INT > 34011 #include "DFHackVersion.h" #endif @@ -191,10 +192,10 @@ command_result generate_image(color_ostream &out, vector & parameters) imageRef.site_id = -1; imageRef.subid = -1; - if (df::global::getArtImage) - { - df::art_image * (__thiscall *getImage)(df::world*,df::art_image_ref *, int *) = (df::art_image * (__thiscall*)(df::world*, df::art_image_ref *, int *))df::global::getArtImage; - int subid = -1; + GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (getImage) + { + int subid = -1; auto image = getImage(world,&imageRef, &subid); out.print("Id: %d, subid: %d\n", image->id, image->subid); } From aff9c22875a7856542d0624183f332a6c0687a6c Mon Sep 17 00:00:00 2001 From: Japa Date: Fri, 26 Jan 2018 08:27:03 +0530 Subject: [PATCH 116/170] update submodules. --- plugins/stonesense | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/stonesense b/plugins/stonesense index 4c55e1439..455b51aab 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 4c55e1439e4e9fa55f6b17147a346c9cde11f7b3 +Subproject commit 455b51aab7a93095a775285782635cfc17ac651a diff --git a/scripts b/scripts index 6934b9d47..fd63a1658 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6934b9d47ccce5908395998133c14c91497f0935 +Subproject commit fd63a1658f3dd7d57d81014e333d0e16e358539d From c0c80b626de32d7e2e65b4c267a6e41801514b75 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 27 Jan 2018 12:12:19 +0530 Subject: [PATCH 117/170] update submodules --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 9afe7c953..f1566f504 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9afe7c9538f1bfa104c5eff54b0945eee32a76cc +Subproject commit f1566f504a089c95e65a9828f550050dcf1fef46 From 341c0dacf373c8f21b47d30522ee754aff4f69d8 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 27 Jan 2018 12:44:51 +0530 Subject: [PATCH 118/170] updated function definition for win64. --- plugins/remotefortressreader/item_reader.cpp | 2 +- plugins/remotefortressreader/item_reader.h | 7 ++++++- .../remotefortressreader.cpp | 16 ++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index c57b90d7d..2acda8aef 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -109,7 +109,7 @@ void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); if (getImage) { - int subid = -1; + int16_t subid = -1; CopyImage(getImage(world, &imageRef, &subid), netImage); } else diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h index 332280982..df25d5655 100644 --- a/plugins/remotefortressreader/item_reader.h +++ b/plugins/remotefortressreader/item_reader.h @@ -25,6 +25,11 @@ DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack:: void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out); -typedef df::art_image * (__thiscall *GET_IMAGE)(df::world*, df::art_image_ref *, int *); +#if(defined(WIN32) && !defined(_WIN64)) +typedef df::art_image * (__thiscall *GET_IMAGE)(df::world*, df::art_image_ref *, int16_t *); +#else +typedef df::art_image *(__fastcall *GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); +#endif + #endif // !ITEM_READER_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 928b7a396..22b836bb7 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -192,11 +192,11 @@ command_result generate_image(color_ostream &out, vector & parameters) imageRef.site_id = -1; imageRef.subid = -1; - GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); - if (getImage) - { - int subid = -1; - auto image = getImage(world,&imageRef, &subid); + GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (getImage) + { + int16_t subid = -1; + auto image = getImage(world, &imageRef, &subid); out.print("Id: %d, subid: %d\n", image->id, image->subid); } return CR_OK; @@ -272,7 +272,11 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector Date: Sat, 27 Jan 2018 19:26:30 +0530 Subject: [PATCH 119/170] fix compiling on gcc. --- plugins/remotefortressreader/item_reader.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h index df25d5655..59e097ca0 100644 --- a/plugins/remotefortressreader/item_reader.h +++ b/plugins/remotefortressreader/item_reader.h @@ -26,9 +26,9 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out); #if(defined(WIN32) && !defined(_WIN64)) -typedef df::art_image * (__thiscall *GET_IMAGE)(df::world*, df::art_image_ref *, int16_t *); +typedef df::art_image * (__thiscall *GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); #else -typedef df::art_image *(__fastcall *GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); +typedef df::art_image * (*GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); #endif From db60ff3911d6179a030ce9ef1196be4d3c3820fa Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 28 Jan 2018 07:55:42 +0530 Subject: [PATCH 120/170] update xmls --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index f1566f504..83d4183a4 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f1566f504a089c95e65a9828f550050dcf1fef46 +Subproject commit 83d4183a4c15fd3f37b53c7f911f4bfb75f21ee2 From b78b2feed26b1bf2b48b32ef7debc3dc4a11c0af Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 28 Jan 2018 10:12:50 +0530 Subject: [PATCH 121/170] Remove extra whitespace. --- library/xml | 2 +- plugins/remotefortressreader/remotefortressreader.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/xml b/library/xml index 83d4183a4..421c5ef8a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 83d4183a4c15fd3f37b53c7f911f4bfb75f21ee2 +Subproject commit 421c5ef8aedf0644d099ff1b779ac6fdf0624478 diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 22b836bb7..c64238a14 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -273,7 +273,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector set_pos_y(plant->pos.y); out_plant->set_pos_z(plant->pos.z); } -} + } #endif return CR_OK; } @@ -1890,7 +1890,7 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, } else out->add_water_elevation(99); -} + } DFCoord pos = GetMapCenter(); out->set_center_x(pos.x); out->set_center_y(pos.y); From 77c6ea1d33f4e5079c8abe862c6b310fcabd1886 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 28 Jan 2018 10:22:16 +0530 Subject: [PATCH 122/170] update xmls. --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 421c5ef8a..5bfce4cd2 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 421c5ef8aedf0644d099ff1b779ac6fdf0624478 +Subproject commit 5bfce4cd2175e084b8bb006516f9b0d339feb332 From 9a1f970d2d3d2be6e745218fa9a61a257aef1538 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 Jan 2018 02:14:54 -0500 Subject: [PATCH 123/170] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index f0c609211..ef5b1c8f0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f0c609211fbfd354b576cae75e9e64f8c6c80b06 +Subproject commit ef5b1c8f037a6240acdd3957fb7b6b9de529c5e2 diff --git a/scripts b/scripts index cbdd03aae..b330e696e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit cbdd03aae69ff6e96644e8169487eaa6b4019d52 +Subproject commit b330e696e6cb6a607d8cc77679bbe0fa5e51598c From 788a48144b3b88fb2cfb3c53f5ea9788c11c2bf2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 Jan 2018 02:16:57 -0500 Subject: [PATCH 124/170] dig: fix issues with priority parameters and digvx/diglx --- plugins/dig.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/dig.cpp b/plugins/dig.cpp index a56688a7b..148da5482 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -236,8 +236,7 @@ int32_t parse_priority(color_ostream &out, vector ¶meters) else if (it + 1 != parameters.end()) { auto priority = int32_t(1000 * atof((*(it + 1)).c_str())); - parameters.erase(it); - parameters.erase(it + 1); + parameters.erase(it, it + 2); return priority; } else @@ -251,6 +250,11 @@ int32_t parse_priority(color_ostream &out, vector ¶meters) return default_priority; } +string forward_priority(color_ostream &out, vector ¶meters) +{ + return string("-p") + int_to_string(parse_priority(out, parameters) / 1000); +} + command_result digcircle (color_ostream &out, vector & parameters) { static bool filled = false; @@ -339,6 +343,7 @@ command_result digcircle (color_ostream &out, vector & parameters) " chan = dig channel\n" "\n" " # = diameter in tiles (default = 0)\n" + " -p # = designation priority (default = 4)\n" "\n" "After you have set the options, the command called with no options\n" "repeats with the last selected parameters:\n" @@ -1032,7 +1037,7 @@ command_result digvx (color_ostream &out, vector & parameters) // HOTKEY COMMAND: CORE ALREADY SUSPENDED vector lol; lol.push_back("x"); - lol.push_back(string("-p") + int_to_string(parse_priority(out, parameters))); + lol.push_back(forward_priority(out, parameters)); return digv(out,lol); } @@ -1204,7 +1209,7 @@ command_result diglx (color_ostream &out, vector & parameters) // HOTKEY COMMAND: CORE ALREADY SUSPENDED vector lol; lol.push_back("x"); - lol.push_back(string("-p") + int_to_string(parse_priority(out, parameters))); + lol.push_back(forward_priority(out, parameters)); return digl(out,lol); } From 8d8632908efb07a7525a0aafaf81c9db3e351208 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 28 Jan 2018 13:45:21 +0530 Subject: [PATCH 125/170] update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 5bfce4cd2..ef5b1c8f0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 5bfce4cd2175e084b8bb006516f9b0d339feb332 +Subproject commit ef5b1c8f037a6240acdd3957fb7b6b9de529c5e2 diff --git a/scripts b/scripts index fd63a1658..b330e696e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit fd63a1658f3dd7d57d81014e333d0e16e358539d +Subproject commit b330e696e6cb6a607d8cc77679bbe0fa5e51598c From 2deeda11d23a1844fc65cd195028045e4591baae Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Sun, 28 Jan 2018 13:04:52 +0100 Subject: [PATCH 126/170] add many new cases for Gui::getSelectedUnit: report list, combat log list, military screen, unit health, unit custumize, assigning to cage, viewing cage, pitting, penning, burrows, look at corpse, look at corpse piece, look at named spatter --- library/modules/Gui.cpp | 121 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 4 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index d6eedcef7..380a76dee 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -49,16 +49,21 @@ using namespace DFHack; #include "df/announcement_flags.h" #include "df/assign_trade_status.h" +#include "df/building_cagest.h" #include "df/building_civzonest.h" #include "df/building_furnacest.h" #include "df/building_trapst.h" +#include "df/building_type.h" #include "df/building_workshopst.h" #include "df/d_init.h" #include "df/game_mode.h" #include "df/general_ref.h" #include "df/global_objects.h" #include "df/graphic.h" +#include "df/historical_figure.h" #include "df/interfacest.h" +#include "df/item_corpsepiecest.h" +#include "df/item_corpsest.h" #include "df/job.h" #include "df/layer_object_listst.h" #include "df/occupation.h" @@ -74,8 +79,10 @@ using namespace DFHack; #include "df/ui_unit_view_mode.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/viewscreen_announcelistst.h" #include "df/viewscreen_assign_display_itemst.h" #include "df/viewscreen_buildinglistst.h" +#include "df/viewscreen_customize_unitst.h" #include "df/viewscreen_dungeon_monsterstatusst.h" #include "df/viewscreen_dungeonmodest.h" #include "df/viewscreen_dwarfmodest.h" @@ -89,6 +96,7 @@ using namespace DFHack; #include "df/viewscreen_layer_noblelistst.h" #include "df/viewscreen_layer_overall_healthst.h" #include "df/viewscreen_layer_stockpilest.h" +#include "df/viewscreen_layer_unit_healthst.h" #include "df/viewscreen_layer_unit_relationshipst.h" #include "df/viewscreen_locationsst.h" #include "df/viewscreen_petst.h" @@ -97,6 +105,7 @@ using namespace DFHack; #include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_unitlistst.h" #include "df/viewscreen_unitst.h" +#include "df/viewscreen_reportlistst.h" #include "df/viewscreen_workquota_conditionst.h" #include "df/viewscreen_workshop_profilest.h" #include "df/world.h" @@ -818,6 +827,9 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) using df::global::ui_look_cursor; using df::global::ui_look_list; using df::global::ui_selected_unit; + using df::global::ui_building_in_assign; + using df::global::ui_building_assign_units; + using df::global::ui_building_item_cursor; if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitst, top)) { @@ -934,12 +946,63 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) return NULL; } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_reportlistst, top)) + return vector_get(screen->units, screen->cursor); + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_announcelistst, top)) + { + auto *report = vector_get(screen->reports, screen->sel_idx); + for (df::unit *unit : world->units.all) + { + if (unit == screen->unit) + continue; + for (int32_t report_id : unit->reports.log[screen->report_type]) + { + if (report_id == report->id) + return unit; + } + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_militaryst, top)) + { + if (screen->page == df::viewscreen_layer_militaryst::T_page::Positions) { + auto positions = getLayerList(screen, 1); + if (positions->enabled && positions->active) + return vector_get(screen->positions.assigned, positions->cursor); + + auto candidates = getLayerList(screen, 2); + if (candidates->enabled && candidates->active) + return vector_get(screen->positions.candidates, candidates->cursor); + } + if (screen->page == df::viewscreen_layer_militaryst::T_page::Equip) { + auto positions = getLayerList(screen, 1); + if (positions->enabled && positions->active) + return vector_get(screen->equip.units, positions->cursor); + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_unit_healthst, top)) + return screen->unit; + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_customize_unitst, top)) + return screen->unit; + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) return dfscreen->getSelectedUnit(); if (!Gui::dwarfmode_hotkey(top)) return NULL; + // general assigning units in building, i.e. (q)uery cage -> (a)ssign + if (ui_building_in_assign && *ui_building_in_assign + && ui_building_assign_units && ui_building_item_cursor + && ui->main.mode != Zones) // dont show for (i) zone + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + + if (ui->follow_unit != -1) + return df::unit::find(ui->follow_unit); + switch (ui->main.mode) { case ViewUnits: { @@ -948,16 +1011,66 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) return vector_get(world->units.active, *ui_selected_unit); } + case ZonesPitInfo: // (i) zone -> (P)it + case ZonesPenInfo: // (i) zone -> pe(N) + { + if (!ui_building_assign_units || !ui_building_item_cursor) + return NULL; + + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + } + case Burrows: + { + if (ui->burrows.in_add_units_mode) + return vector_get(ui->burrows.list_units, ui->burrows.unit_cursor_pos); + + return NULL; + } + case QueryBuilding: + { + df::building *building = getAnyBuilding(top); + if (building->getType() == df::building_type::Cage) + { + auto *cage = static_cast(building); + if (*ui_building_item_cursor < cage->assigned_units.size()) + return df::unit::find(cage->assigned_units[*ui_building_item_cursor]); + } + return NULL; + } case LookAround: { if (!ui_look_list || !ui_look_cursor) return NULL; auto item = vector_get(ui_look_list->items, *ui_look_cursor); - if (item && item->type == df::ui_look_list::T_items::Unit) - return item->unit; - else - return NULL; + if (item) { + if (item->type == df::ui_look_list::T_items::Unit) + return item->unit; + else if (item->type == df::ui_look_list::T_items::Item) + { + if (item->item->getType() == df::item_type::CORPSE) + { + // loo(k) at corpse + auto *corpse = static_cast(item->item); + return df::unit::find(corpse->unit_id); + } + else if (item->item->getType() == df::item_type::CORPSEPIECE) + { + // loo(k) at corpse piece + auto *corpsepiece = static_cast(item->item); + return df::unit::find(corpsepiece->unit_id); + } + } + else if (item->type == df::ui_look_list::T_items::Spatter) + { + // loo(k) at blood/ichor/.. spatter with a name + MaterialInfo mat; + if (mat.decode(item->spatter_mat_type, item->spatter_mat_index)) + return df::unit::find(mat.figure->unit_id); + } + } + + return NULL; } default: return NULL; From e63a871363971d90852e5aaad216e27244a96934 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 31 Jan 2018 10:11:43 +0530 Subject: [PATCH 127/170] use the vmethod for getting improvement images. --- library/xml | 2 +- plugins/remotefortressreader/item_reader.cpp | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/library/xml b/library/xml index ef5b1c8f0..2b7ef6fde 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ef5b1c8f037a6240acdd3957fb7b6b9de529c5e2 +Subproject commit 2b7ef6fdeb87cc63eb56d57d5b6b220176840404 diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 2acda8aef..933abc501 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -106,13 +106,6 @@ void CopyImage(const df::art_image * image, ArtImage * netImage) void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) { - GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); - if (getImage) - { - int16_t subid = -1; - CopyImage(getImage(world, &imageRef, &subid), netImage); - } - else { for (int i = 0; i < world->art_image_chunks.size(); i++) { @@ -402,7 +395,7 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) case df::enums::improvement_type::ART_IMAGE: { VIRTUAL_CAST_VAR(artImage, df::itemimprovement_art_imagest, improvement); - CopyImage(artImage->image, netImp->mutable_image()); + CopyImage(artImage->getImage(DfItem), netImp->mutable_image()); break; } case df::enums::improvement_type::COVERED: From 325e0b0e33b0a6b9ca830c9d43777d0f5564d26f Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 31 Jan 2018 09:57:11 -0500 Subject: [PATCH 128/170] binpatch.lua: check for empty patches --- library/lua/binpatch.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/lua/binpatch.lua b/library/lua/binpatch.lua index d8e95b29f..0cae97e5b 100644 --- a/library/lua/binpatch.lua +++ b/library/lua/binpatch.lua @@ -17,6 +17,7 @@ local function load_patch(name) local old_bytes = {} local new_bytes = {} + local has_bytes = false for line in file:lines() do if string.match(line, '^%x+:') then @@ -34,10 +35,14 @@ local function load_patch(name) old_bytes[offset] = oldv new_bytes[offset] = newv + has_bytes = true end end file:close() + if not has_bytes then + return nil, 'no patch bytes found' + end return { name = name, old_bytes = old_bytes, new_bytes = new_bytes } end From 537e94d75a818b7ac704c297be41d364fee81b74 Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Sun, 28 Jan 2018 13:37:27 +0100 Subject: [PATCH 129/170] fix segfault when splatter did not have historical figure --- library/modules/Gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 380a76dee..e0dd46a32 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1065,7 +1065,7 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) { // loo(k) at blood/ichor/.. spatter with a name MaterialInfo mat; - if (mat.decode(item->spatter_mat_type, item->spatter_mat_index)) + if (mat.decode(item->spatter_mat_type, item->spatter_mat_index) && mat.figure) return df::unit::find(mat.figure->unit_id); } } From 38491b4be871a75692f557116d7143dc2d49712a Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Wed, 31 Jan 2018 20:01:49 +0100 Subject: [PATCH 130/170] add checks to avoid potential segfaults. use more dfhack idiomatic code --- library/modules/Gui.cpp | 79 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index e0dd46a32..e3cebd45e 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -951,16 +951,27 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_announcelistst, top)) { - auto *report = vector_get(screen->reports, screen->sel_idx); - for (df::unit *unit : world->units.all) - { - if (unit == screen->unit) - continue; - for (int32_t report_id : unit->reports.log[screen->report_type]) + if (screen->unit) { + // in (r)eports -> enter + auto *report = vector_get(screen->reports, screen->sel_idx); + if (report) { - if (report_id == report->id) - return unit; + for (df::unit *unit : world->units.all) + { + if (unit && screen->report_type >= 0 && screen->report_type < 3 + && unit != screen->unit) // find 'other' unit related to this report + { + for (int32_t report_id : unit->reports.log[screen->report_type]) + { + if (report_id == report->id) + return unit; + } + } + } } + } else { + // in (a)nnouncements + return NULL; // cannot determine unit from reports } } @@ -968,16 +979,16 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) { if (screen->page == df::viewscreen_layer_militaryst::T_page::Positions) { auto positions = getLayerList(screen, 1); - if (positions->enabled && positions->active) + if (positions && positions->enabled && positions->active) return vector_get(screen->positions.assigned, positions->cursor); auto candidates = getLayerList(screen, 2); - if (candidates->enabled && candidates->active) + if (candidates && candidates->enabled && candidates->active) return vector_get(screen->positions.candidates, candidates->cursor); } if (screen->page == df::viewscreen_layer_militaryst::T_page::Equip) { auto positions = getLayerList(screen, 1); - if (positions->enabled && positions->active) + if (positions && positions->enabled && positions->active) return vector_get(screen->equip.units, positions->cursor); } } @@ -994,10 +1005,13 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (!Gui::dwarfmode_hotkey(top)) return NULL; + if (!ui) + return NULL; + // general assigning units in building, i.e. (q)uery cage -> (a)ssign if (ui_building_in_assign && *ui_building_in_assign - && ui_building_assign_units && ui_building_item_cursor - && ui->main.mode != Zones) // dont show for (i) zone + && ui_building_assign_units && ui_building_item_cursor + && ui->main.mode != Zones) // dont show for (i) zone return vector_get(*ui_building_assign_units, *ui_building_item_cursor); if (ui->follow_unit != -1) @@ -1006,7 +1020,7 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) switch (ui->main.mode) { case ViewUnits: { - if (!ui_selected_unit) + if (!ui_selected_unit || !ui_selected_unit) return NULL; return vector_get(world->units.active, *ui_selected_unit); @@ -1014,10 +1028,10 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) case ZonesPitInfo: // (i) zone -> (P)it case ZonesPenInfo: // (i) zone -> pe(N) { - if (!ui_building_assign_units || !ui_building_item_cursor) - return NULL; + if (ui_building_assign_units || ui_building_item_cursor) + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); - return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + return NULL; } case Burrows: { @@ -1028,12 +1042,13 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) } case QueryBuilding: { - df::building *building = getAnyBuilding(top); - if (building->getType() == df::building_type::Cage) + if (df::building *building = getAnyBuilding(top)) { - auto *cage = static_cast(building); - if (*ui_building_item_cursor < cage->assigned_units.size()) - return df::unit::find(cage->assigned_units[*ui_building_item_cursor]); + if (VIRTUAL_CAST_VAR(cage, df::building_cagest, building)) + { + if (ui_building_item_cursor) + return df::unit::find(vector_get(cage->assigned_units, *ui_building_item_cursor)); + } } return NULL; } @@ -1042,24 +1057,16 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (!ui_look_list || !ui_look_cursor) return NULL; - auto item = vector_get(ui_look_list->items, *ui_look_cursor); - if (item) { + if (auto item = vector_get(ui_look_list->items, *ui_look_cursor)) + { if (item->type == df::ui_look_list::T_items::Unit) return item->unit; else if (item->type == df::ui_look_list::T_items::Item) { - if (item->item->getType() == df::item_type::CORPSE) - { - // loo(k) at corpse - auto *corpse = static_cast(item->item); - return df::unit::find(corpse->unit_id); - } - else if (item->item->getType() == df::item_type::CORPSEPIECE) - { - // loo(k) at corpse piece - auto *corpsepiece = static_cast(item->item); - return df::unit::find(corpsepiece->unit_id); - } + if (VIRTUAL_CAST_VAR(corpse, df::item_corpsest, item->item)) + return df::unit::find(corpse->unit_id); // loo(k) at corpse + else if (VIRTUAL_CAST_VAR(corpsepiece, df::item_corpsepiecest, item->item)) + return df::unit::find(corpsepiece->unit_id); // loo(k) at corpse piece } else if (item->type == df::ui_look_list::T_items::Spatter) { From 8665600574d959bcb3c4c7a738b8909cfbf47194 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 3 Feb 2018 10:38:17 +0530 Subject: [PATCH 131/170] Send tiles for shape descriptors, and art image ids. --- plugins/proto/RemoteFortressReader.proto | 2 ++ plugins/remotefortressreader/item_reader.cpp | 3 +++ plugins/remotefortressreader/remotefortressreader.cpp | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 0cdb41110..73f75792f 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -882,6 +882,7 @@ message Status message ShapeDescriptior { optional string id = 1; + optional int32 tile = 2; } message Language @@ -936,4 +937,5 @@ message ArtImageElement message ArtImage { repeated ArtImageElement elements = 1; + optional MatPair id = 2; } \ No newline at end of file diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 933abc501..2eef1ad67 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -49,6 +49,9 @@ using namespace df::global; void CopyImage(const df::art_image * image, ArtImage * netImage) { + auto id = netImage->mutable_id(); + id->set_mat_type(image->id); + id->set_mat_index(image->subid); for (int i = 0; i < image->elements.size(); i++) { auto element = image->elements[i]; diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index c64238a14..427fc4334 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -53,8 +53,6 @@ #include "df/creature_raw.h" #include "df/creature_raw.h" #include "df/descriptor_color.h" -#include "df/descriptor_color.h" -#include "df/descriptor_pattern.h" #include "df/descriptor_pattern.h" #include "df/descriptor_shape.h" #include "df/dfhack_material_category.h" @@ -2919,6 +2917,7 @@ static command_result GetLanguage(color_ostream & stream, const EmptyMessage * i auto shape = world->raws.language.shapes[i]; auto netShape = out->add_shapes(); netShape->set_id(shape->id); + netShape->set_tile(shape->tile); } return CR_OK; } \ No newline at end of file From 0f43c07334d66406d27f0082b2cfcc90d99a1ad2 Mon Sep 17 00:00:00 2001 From: Japa Date: Sat, 3 Feb 2018 11:10:26 +0530 Subject: [PATCH 132/170] update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 2b7ef6fde..b0203a1d9 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 2b7ef6fdeb87cc63eb56d57d5b6b220176840404 +Subproject commit b0203a1d982212b1a82ea159d07a2dc6df31c191 From 636448f431a1298dfb00822a12812de929bc0c7e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 03:28:32 -0500 Subject: [PATCH 133/170] Update changelog --- NEWS.rst | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index a14bafa9f..917af3fe7 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -44,26 +44,50 @@ New Scripts - `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global - `gui/cp437-table`: An in-game CP437 table +- `view-unit-reports`: opens the reports screen with combat reports for the selected unit Fixes ----- - Fixed issues with the console output color affecting the prompt on Windows - `createitem`: stopped items from teleporting away in some forts - `devel/inject-raws`: now recognizes spaces in reaction names +- `dig`: added support for designation priorities - fixes issues with + designations from ``digv`` and related commands having extremely high priority +- `dwarfmonitor`: + + - fixed display of creatures and poetic/music/dance forms on ``prefs`` screen + - added "view unit" option + - now exposes the selected unit to other tools + - `gui/gm-unit`: can now edit mining skill - `gui/quickcmd`: stopped error from adding too many commands +- `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear Misc Improvements ----------------- - The console now provides suggestions for built-in commands +- `binpatch`: now reports errors for empty patch files - `devel/export-dt-ini`: avoid hardcoding flags - `exportlegends`: - reordered some tags to match DF's order - added progress indicators for exporting long lists +- `force`: now provides useful help +- `full-heal`: + + - can now select corpses to resurrect + - now resets body part temperatures upon resurrection to prevent creatures + from freezing/melting again + - now resets units' vanish countdown to reverse effects of `exterminate` + - `gui/gm-editor`: added enum names to enum edit dialogs -- `gui/gm-unit`: made skill search case-insensitive +- `gui/gm-unit`: + + - made skill search case-insensitive + - added a profession editor + - misc. layout improvements + - `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards - `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options @@ -76,7 +100,22 @@ Misc Improvements Removed ------- -- `warn-stuck-trees`: the corresponding DF bug was fixed in 0.44.01 +- `warn-stuck-trees`: :bug:`9252` fixed in DF 0.44.01 +- `tweak`: ``kitchen-keys``: :bug:`614` fixed in DF 0.44.04 + +Internals +--------- +- ``Gui::getAnyUnit()`` supports many more screens/menus +- New globals available: + + - ``version`` + - ``min_load_version`` + - ``movie_version`` + - ``basic_seed`` + - ``title`` + - ``title_spaced`` + - ``ui_building_resize_radius`` + - ``soul_next_id`` Lua --- From 6181b2bce343204f7594f5c559d9b7ee09525abe Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Sat, 3 Feb 2018 16:29:30 +0100 Subject: [PATCH 134/170] Add tweak that replaces dwarf mode FPS counter with one that does not count when paused --- dfhack.init-example | 3 + plugins/tweak/tweak.cpp | 7 ++ plugins/tweak/tweaks/pausing-fps-counter.h | 137 +++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 plugins/tweak/tweaks/pausing-fps-counter.h diff --git a/dfhack.init-example b/dfhack.init-example index 82210a2a6..fb846a47f 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -202,6 +202,9 @@ tweak hotkey-clear # Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving tweak embark-profile-name +# dwarf mode FPS counter that does not jump to FPS_CAP when paused +tweak pausing-fps-counter + # Misc. UI tweaks tweak block-labors # Prevents labors that can't be used from being toggled tweak burrow-name-cancel diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 252f4c738..6b5b1f687 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -98,6 +98,7 @@ #include "tweaks/kitchen-prefs-empty.h" #include "tweaks/max-wheelbarrow.h" #include "tweaks/military-assign.h" +#include "tweaks/pausing-fps-counter.h" #include "tweaks/nestbox-color.h" #include "tweaks/shift-8-scroll.h" #include "tweaks/stable-cursor.h" @@ -232,6 +233,9 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector display_frames == 1); + } + return init_have_fps_yes; + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + + if (!df::global::pause_state || !df::global::enabler || !df::global::world + || !df::global::gps || !df::global::pause_state) + return; + + // if init.txt does not have [FPS:YES] then dont show this FPS counter + if (!dwarfmode_pausing_fps_counter_hook::init_have_fps_yes()) + return; + + static bool prev_paused = true; + static uint32_t prev_clock = 0; + static int32_t prev_frames = 0; + static uint32_t elapsed_clock = 0; + static uint32_t elapsed_frames = 0; + static double history[history_length]; + + if (prev_clock == 0) + { + // init + for (int i = 0; i < history_length; i++) + history[i] = 0.0; + } + + // disable default FPS counter because it is rendered on top of this FPS counter. + if (df::global::gps->display_frames == 1) + df::global::gps->display_frames = 0; + + if (*df::global::pause_state) + prev_paused = true; + else + { + uint32_t clock = df::global::enabler->clock; + int32_t frames = df::global::world->frame_counter; + + if (!prev_paused && prev_clock != 0 + && clock >= prev_clock && frames >= prev_frames) + { + // if we were previously paused, then dont add clock/frames, + // but wait for the next time render is called. + elapsed_clock += clock - prev_clock; + elapsed_frames += frames - prev_frames; + } + + prev_paused = false; + prev_clock = clock; + prev_frames = frames; + + // add FPS to history every second or after at least one frame. + if (elapsed_clock >= 1000 && elapsed_frames >= 1) + { + double fps = elapsed_frames / (elapsed_clock / 1000.0); + for (int i = history_length - 1; i >= 1; i--) + history[i] = history[i - 1]; + history[0] = fps; + + elapsed_clock = 0; + elapsed_frames = 0; + } + } + + // average fps over a few seconds to stabilize the counter. + double fps_sum = 0.0; + int fps_count = 0; + for (int i = 0; i < history_length; i++) + { + if (history[i] > 0.0) + { + fps_sum += history[i]; + fps_count++; + } + } + + double fps = fps_count == 0 ? 1.0 : fps_sum / fps_count; + double gfps = df::global::enabler->calculated_gfps; + + std::stringstream fps_counter; + fps_counter << "FPS:" + << setw(4) << fixed << setprecision(fps >= 1.0 ? 0 : 2) << fps + << " (" << gfps << ")"; + + // show this FPS counter same as the default counter. + int x = 10; + int y = 0; + OutputString(COLOR_WHITE, x, y, fps_counter.str(), + false, 0, COLOR_CYAN, false); + } +}; + +struct title_pausing_fps_counter_hook : df::viewscreen_titlest { + typedef df::viewscreen_titlest interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + + // if init.txt have FPS:YES then enable default FPS counter when exiting dwarf mode. + // So it is enabled if starting adventure mode without exiting dwarf fortress. + if (dwarfmode_pausing_fps_counter_hook::init_have_fps_yes() + && df::global::gps && df::global::gps->display_frames == 0) + df::global::gps->display_frames = 1; + } +}; + + +IMPLEMENT_VMETHOD_INTERPOSE(dwarfmode_pausing_fps_counter_hook, render); + +IMPLEMENT_VMETHOD_INTERPOSE(title_pausing_fps_counter_hook, render); From 426839aac290ef0a8a78648ee5ba48519c1e8f87 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 17:58:59 -0500 Subject: [PATCH 135/170] Update scripts, xml, NEWS for dfhack/scripts#37 --- NEWS.rst | 10 ++++++++++ library/xml | 2 +- scripts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 917af3fe7..f704508bd 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -41,9 +41,16 @@ DFHack future New Scripts ----------- +- `break-dance`: Breaks up a stuck dance activity +- `cannibalism`: Allows consumption of sapient corpses - `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global +- `fillneeds`: Use with a unit selected to make them focused and unstressed +- `firestarter`: Lights things on fire: items, locations, entire inventories even! +- `flashstep`: Teleports adventurer to cursor +- `ghostly`: Turns an adventurer into a ghost or back - `gui/cp437-table`: An in-game CP437 table +- `questport`: Sends your adventurer to the location of your quest log cursor - `view-unit-reports`: opens the reports screen with combat reports for the selected unit Fixes @@ -61,6 +68,7 @@ Fixes - `gui/gm-unit`: can now edit mining skill - `gui/quickcmd`: stopped error from adding too many commands +- `names`: fixed many errors - `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear Misc Improvements @@ -91,11 +99,13 @@ Misc Improvements - `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards - `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options +- `launch`: can now ride creatures - `modtools/skill-change`: - now updates skill levels appropriately - only prints output if ``-loud`` is passed +- `names`: can now edit names of units - `remotefortressreader`: includes item stack sizes and some performance improvements Removed diff --git a/library/xml b/library/xml index ef5b1c8f0..718788141 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ef5b1c8f037a6240acdd3957fb7b6b9de529c5e2 +Subproject commit 7187881412f8ee7518527641e0df52a3ed4a52e3 diff --git a/scripts b/scripts index b330e696e..8d079a591 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b330e696e6cb6a607d8cc77679bbe0fa5e51598c +Subproject commit 8d079a59122d9ba72ce9c0f7687402a343d09bc7 From e88ba60ba5884261a85073b0413c24a2141e892d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 18:08:15 -0500 Subject: [PATCH 136/170] Document "dig" priority arguments --- docs/Plugins.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 04f5df321..c896b5fd0 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1930,6 +1930,13 @@ Basic commands: :dfhack-keybind:`digv` +.. note:: + + All commands implemented by the `dig` plugin (listed by ``ls dig``) support + specifying the designation priority with ``-p#``, ``-p #``, or ``p=#``, + where ``#`` is a number from 1 to 7. If a priority is not specified, the + priority selected in-game is used as the default. + .. _digexp: digexp From bdba95f90c1e99e98dee6bcd37031ca2631a53d7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 18:10:16 -0500 Subject: [PATCH 137/170] memview: check for tags from sizecheck --- plugins/devel/memview.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index b93319a07..d84a3b578 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -53,7 +53,14 @@ size_t convert(const std::string& p,bool ishex=false) conv>>ret; return ret; } -bool isAddr(uintptr_t *trg,vector & ranges) +bool isAddr(void *trg, vector &ranges) +{ + for (auto &r : ranges) + if (r.isInRange(trg)) + return true; + return false; +} +bool isAddrAt(uintptr_t *trg, vector &ranges) { if(trg[0]%4==0) for(size_t i=0;i & parameters) is_enabled = true; memdata.state=STATE_ON; } - if(parameters.size()>1) + if (vector_get(parameters, 1, string("a")).substr(0, 1) == "a") + memdata.len = detect_size(memdata.addr); + else if (parameters.size()>1) memdata.len=convert(parameters[1]); else memdata.len=20*16; From d71e252b5038f584f38d92c453b6e8ff71cac311 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 22:17:28 -0500 Subject: [PATCH 138/170] Bump to r1 --- CMakeLists.txt | 4 ++-- NEWS.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e92fc967..c7eb1f234 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,8 +141,8 @@ endif() # set up versioning. set(DF_VERSION "0.44.05") -set(DFHACK_RELEASE "alpha1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/NEWS.rst b/NEWS.rst index f704508bd..ce8635675 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,8 +36,8 @@ Changelog .. contents:: :depth: 2 -DFHack future -============= +DFHack 0.44.05-r1 +================= New Scripts ----------- From 39b488a103838c5ad43c69cb0f18160f27f61ed3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 23:01:15 -0500 Subject: [PATCH 139/170] Download/install DF --- .travis.yml | 18 +++++++++++------- travis/download-df.sh | 28 ++++++++++++++++++++++++++++ travis/get-df-version.sh | 4 ++++ 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100755 travis/download-df.sh create mode 100755 travis/get-df-version.sh diff --git a/.travis.yml b/.travis.yml index ad17693a9..ab18066f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: cpp cache: pip: true directories: + - $HOME/DF-travis - $HOME/lua53 addons: apt: @@ -22,8 +23,11 @@ matrix: - gcc-4.8-multilib - g++-4.8-multilib before_install: +- export DF_VERSION=$(sh travis/get-df-version.sh) +- export DF_FOLDER="$HOME/DF-travis/$DF_VERSION" - pip install --user "sphinx==1.4" "requests[security]" - sh travis/build-lua.sh +- sh travis/download-df.sh script: - export PATH="$PATH:$HOME/lua53/bin" - git tag tmp-travis-build @@ -37,12 +41,12 @@ script: - python travis/script-syntax.py --ext=rb --cmd="ruby -c" - mkdir build-travis - cd build-travis -- cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DBUILD_DOCS:BOOL=ON -- make -j3 +- cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" +- make -j3 install notifications: email: false - irc: - channels: - - "chat.freenode.net#dfhack" - on_success: change - on_failure: always + # irc: + # channels: + # - "chat.freenode.net#dfhack" + # on_success: change + # on_failure: always diff --git a/travis/download-df.sh b/travis/download-df.sh new file mode 100755 index 000000000..56a2a539d --- /dev/null +++ b/travis/download-df.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +tardest="df.tar.bz2" + +cd "$(dirname "$0")" +echo "DF_VERSION: $DF_VERSION" +echo "DF_FOLDER: $DF_FOLDER" +mkdir -p "$DF_FOLDER" +cd "$DF_FOLDER" + +if [ -f receipt ]; then + echo "Already downloaded $DF_VERSION" + exit 0 +fi + +rm -rif "$tardest" df_linux + +minor=$(echo "$DF_VERSION" | cut -d. -f2) +patch=$(echo "$DF_VERSION" | cut -d. -f3) +url="http://www.bay12games.com/dwarves/df_${minor}_${patch}_linux.tar.bz2" + +echo Downloading +wget "$url" -O "$tardest" +echo Extracting +tar xf "$tardest" --strip-components=1 +echo Done + +touch receipt diff --git a/travis/get-df-version.sh b/travis/get-df-version.sh new file mode 100755 index 000000000..13d317d2e --- /dev/null +++ b/travis/get-df-version.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cd "$(dirname "$0")" +cd .. +grep DF_VERSION CMakeLists.txt | perl -ne 'print "$&\n" if /[\d\.]+/' From b54a35ce5dc36c2b375b99555072b2b7322a450f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 23:26:43 -0500 Subject: [PATCH 140/170] Build 64-bit DFHack, install SDL --- .travis.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ab18066f3..8499aa761 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,9 +8,12 @@ cache: addons: apt: packages: &default_packages + - libsdl-image1.2-dev + - libsdl-ttf2.0-dev + - libsdl1.2-dev - libxml-libxml-perl - libxml-libxslt-perl - - zlib1g-dev:i386 + - zlib1g-dev matrix: include: - env: GCC_VERSION=4.8 @@ -20,8 +23,8 @@ matrix: - ubuntu-toolchain-r-test packages: - *default_packages - - gcc-4.8-multilib - - g++-4.8-multilib + - gcc-4.8 + - g++-4.8 before_install: - export DF_VERSION=$(sh travis/get-df-version.sh) - export DF_FOLDER="$HOME/DF-travis/$DF_VERSION" @@ -41,8 +44,9 @@ script: - python travis/script-syntax.py --ext=rb --cmd="ruby -c" - mkdir build-travis - cd build-travis -- cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" +- cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DDFHACK_BUILD_ARCH=64 -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - make -j3 install +- "$DF_FOLDER/dfhack +devel/check-release +die" notifications: email: false # irc: From 38140fb450c374ee0ff111e965773f37379bd993 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 4 Feb 2018 10:12:15 +0530 Subject: [PATCH 141/170] Copy engravings in RFR, and update the art image function. --- library/xml | 2 +- plugins/proto/RemoteFortressReader.proto | 21 ++++- plugins/remotefortressreader/item_reader.cpp | 36 ++++--- plugins/remotefortressreader/item_reader.h | 9 +- .../remotefortressreader.cpp | 93 ++++++++++++++++--- 5 files changed, 123 insertions(+), 38 deletions(-) diff --git a/library/xml b/library/xml index b0203a1d9..6652fd55e 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b0203a1d982212b1a82ea159d07a2dc6df31c191 +Subproject commit 6652fd55e5e489c8a5d12467d1ea85c83192ba17 diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 73f75792f..96dc37a8d 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -434,6 +434,7 @@ message BlockList repeated MapBlock map_blocks = 1; optional int32 map_x = 2; optional int32 map_y = 3; + repeated Engraving engravings = 4; } message PlantDef @@ -938,4 +939,22 @@ message ArtImage { repeated ArtImageElement elements = 1; optional MatPair id = 2; -} \ No newline at end of file +} + +message Engraving +{ + optional Coord pos = 1; + optional int32 quality = 2; + optional int32 tile = 3; + optional ArtImage image = 4; + optional bool floor = 5; + optional bool west = 6; + optional bool east = 7; + optional bool north = 8; + optional bool south = 9; + optional bool hidden = 10; + optional bool northwest = 11; + optional bool northeast = 12; + optional bool southwest = 13; + optional bool southeast = 14; + } \ No newline at end of file diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 2eef1ad67..e92420373 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -107,20 +107,6 @@ void CopyImage(const df::art_image * image, ArtImage * netImage) } } -void CopyImage(df::art_image_ref imageRef, ArtImage * netImage) -{ - { - for (int i = 0; i < world->art_image_chunks.size(); i++) - { - auto chunk = world->art_image_chunks[i]; - if (chunk->id != imageRef.id) - continue; - auto image = chunk->images[imageRef.subid]; - CopyImage(image, netImage); - } - } -} - void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) { NetItem->set_id(DfItem->id); @@ -196,7 +182,27 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) case df::enums::item_type::STATUE: { VIRTUAL_CAST_VAR(statue, df::item_statuest, DfItem); - CopyImage(statue->image, NetItem->mutable_image()); + + df::art_image_chunk * chunk = NULL; + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (GetArtImageChunk) + { + chunk = GetArtImageChunk(&(world->art_image_chunks), statue->image.id); + } + else + { + for (int i = 0; i < world->art_image_chunks.size(); i++) + { + if (world->art_image_chunks[i]->id == statue->image.id) + chunk = world->art_image_chunks[i]; + } + } + if (chunk) + { + CopyImage(chunk->images[statue->image.subid], NetItem->mutable_image()); + } + + break; } case df::enums::item_type::CORPSE: diff --git a/plugins/remotefortressreader/item_reader.h b/plugins/remotefortressreader/item_reader.h index 59e097ca0..045c1be51 100644 --- a/plugins/remotefortressreader/item_reader.h +++ b/plugins/remotefortressreader/item_reader.h @@ -12,7 +12,7 @@ namespace df struct item; struct map_block; struct art_image; - struct art_image_ref; + struct art_image_chunk; struct world; } @@ -25,11 +25,8 @@ DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack:: void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem); void ConvertDFColorDescriptor(int16_t index, RemoteFortressReader::ColorDefinition * out); -#if(defined(WIN32) && !defined(_WIN64)) -typedef df::art_image * (__thiscall *GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); -#else -typedef df::art_image * (*GET_IMAGE)(df::world *, df::art_image_ref *, int16_t *); -#endif +typedef df::art_image_chunk * (*GET_ART_IMAGE_CHUNK)(std::vector *, int); +void CopyImage(const df::art_image * image, RemoteFortressReader::ArtImage * netImage); #endif // !ITEM_READER_H diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 427fc4334..a724e434f 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -57,6 +57,7 @@ #include "df/descriptor_shape.h" #include "df/dfhack_material_category.h" #include "df/enabler.h" +#include "df/engraving.h" #include "df/graphic.h" #include "df/historical_figure.h" @@ -182,20 +183,18 @@ const char* growth_locations[] = { #include "df/art_image.h" #include "df/art_image_chunk.h" #include "df/art_image_ref.h" -command_result generate_image(color_ostream &out, vector & parameters) +command_result loadArtImageChunk(color_ostream &out, vector & parameters) { - df::art_image_ref imageRef; - imageRef.civ_id = -1; - imageRef.id = -1; - imageRef.site_id = -1; - imageRef.subid = -1; + if (parameters.size() != 1) + return CR_WRONG_USAGE; - GET_IMAGE getImage = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); - if (getImage) + + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (GetArtImageChunk) { - int16_t subid = -1; - auto image = getImage(world, &imageRef, &subid); - out.print("Id: %d, subid: %d\n", image->id, image->subid); + int index = atoi(parameters[0].c_str()); + auto chunk = GetArtImageChunk(&(world->art_image_chunks), index); + out.print("Loaded chunk id: &d", chunk->id); } return CR_OK; } @@ -271,10 +270,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector * items) return result; } +map engravingHashes; + +bool isEngravingNew(int index) +{ + if (engravingHashes[index]) + return false; + engravingHashes[index] = true; + return true; +} + +void engravingIsNotNew(int index) +{ + engravingHashes[index] = false; +} + static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage *in) { hashes.clear(); @@ -806,6 +820,7 @@ static command_result ResetMapHashes(color_ostream &stream, const EmptyMessage * buildingHashes.clear(); spatterHashes.clear(); itemHashes.clear(); + engravingHashes.clear(); return CR_OK; } @@ -1485,6 +1500,54 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in } } } + + for (int i = 0; i < world->engravings.size(); i++) + { + auto engraving = world->engravings[i]; + if (engraving->pos.x < (min_x * 16) || engraving->pos.x >(max_x * 16)) + continue; + if (engraving->pos.y < (min_y * 16) || engraving->pos.x >(max_y * 16)) + continue; + if (engraving->pos.z < (min_z * 16) || engraving->pos.x >(max_z * 16)) + continue; + if (!isEngravingNew(i)) + continue; + + df::art_image_chunk * chunk = NULL; + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + if (GetArtImageChunk) + { + chunk = GetArtImageChunk(&(world->art_image_chunks), engraving->art_id); + } + else + { + for (int i = 0; i < world->art_image_chunks.size(); i++) + { + if (world->art_image_chunks[i]->id == engraving->art_id) + chunk = world->art_image_chunks[i]; + } + } + if (!chunk) + { + engravingIsNotNew(i); + continue; + } + auto netEngraving = out->add_engravings(); + ConvertDFCoord(engraving->pos, netEngraving->mutable_pos()); + netEngraving->set_quality(engraving->quality); + netEngraving->set_tile(engraving->tile); + CopyImage(chunk->images[engraving->art_subid], netEngraving->mutable_image()); + netEngraving->set_floor(engraving->flags.bits.floor); + netEngraving->set_west(engraving->flags.bits.west); + netEngraving->set_east(engraving->flags.bits.east); + netEngraving->set_north(engraving->flags.bits.north); + netEngraving->set_south(engraving->flags.bits.south); + netEngraving->set_hidden(engraving->flags.bits.hidden); + netEngraving->set_northwest(engraving->flags.bits.northwest); + netEngraving->set_northeast(engraving->flags.bits.northeast); + netEngraving->set_southwest(engraving->flags.bits.southwest); + netEngraving->set_southeast(engraving->flags.bits.southeast); + } MC.trash(); return CR_OK; } From c621a29fe340a4b5578925877091f550343ed8ff Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 4 Feb 2018 10:21:28 +0530 Subject: [PATCH 142/170] Fix global name. --- plugins/remotefortressreader/item_reader.cpp | 2 +- plugins/remotefortressreader/remotefortressreader.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index e92420373..3a9fed571 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -184,7 +184,7 @@ void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) VIRTUAL_CAST_VAR(statue, df::item_statuest, DfItem); df::art_image_chunk * chunk = NULL; - GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("get_art_image_chunk")); if (GetArtImageChunk) { chunk = GetArtImageChunk(&(world->art_image_chunks), statue->image.id); diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index a724e434f..412d7894f 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -189,7 +189,7 @@ command_result loadArtImageChunk(color_ostream &out, vector & parameter return CR_WRONG_USAGE; - GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("get_art_image_chunk")); if (GetArtImageChunk) { int index = atoi(parameters[0].c_str()); @@ -1514,7 +1514,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in continue; df::art_image_chunk * chunk = NULL; - GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("rfr_get_art_image")); + GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("get_art_image_chunk")); if (GetArtImageChunk) { chunk = GetArtImageChunk(&(world->art_image_chunks), engraving->art_id); From ed406e0e3d3a3a630bd227a602143f34d7759e72 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 4 Feb 2018 10:24:51 +0530 Subject: [PATCH 143/170] fix naming and return statement. --- plugins/remotefortressreader/remotefortressreader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 412d7894f..32bd73dad 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -194,7 +194,7 @@ command_result loadArtImageChunk(color_ostream &out, vector & parameter { int index = atoi(parameters[0].c_str()); auto chunk = GetArtImageChunk(&(world->art_image_chunks), index); - out.print("Loaded chunk id: &d", chunk->id); + out.print("Loaded chunk id: %d\n", chunk->id); } return CR_OK; } @@ -260,7 +260,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector Date: Sat, 3 Feb 2018 23:56:44 -0500 Subject: [PATCH 144/170] Set PRINT_MODE:TEXT --- travis/download-df.sh | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/travis/download-df.sh b/travis/download-df.sh index 56a2a539d..4430f7630 100755 --- a/travis/download-df.sh +++ b/travis/download-df.sh @@ -2,15 +2,23 @@ tardest="df.tar.bz2" +which md5sum && alias md5=md5sum +selfmd5=$(openssl md5 < "$0") +echo $selfmd5 + cd "$(dirname "$0")" echo "DF_VERSION: $DF_VERSION" echo "DF_FOLDER: $DF_FOLDER" mkdir -p "$DF_FOLDER" cd "$DF_FOLDER" -if [ -f receipt ]; then - echo "Already downloaded $DF_VERSION" - exit 0 +if [[ -f receipt ]]; then + if [[ "$selfmd5" != "$(cat receipt)" ]]; then + echo "download-df.sh changed; removing DF" + else + echo "Already downloaded $DF_VERSION" + exit 0 + fi fi rm -rif "$tardest" df_linux @@ -23,6 +31,9 @@ echo Downloading wget "$url" -O "$tardest" echo Extracting tar xf "$tardest" --strip-components=1 +echo Changing settings +echo '' >> "$DF_FOLDER/data/init/init.txt" +echo '[PRINT_MODE:TEXT]' >> "$DF_FOLDER/data/init/init.txt" echo Done -touch receipt +echo "$selfmd5" > receipt From 638f0ab35aecf18c02c0a3ef5430b8bb3bb0cc09 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 23:59:01 -0500 Subject: [PATCH 145/170] Add "headless" mode, use in travis --- .travis.yml | 1 + library/Core.cpp | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8499aa761..d2516b967 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ before_install: - pip install --user "sphinx==1.4" "requests[security]" - sh travis/build-lua.sh - sh travis/download-df.sh +- echo "export DFHACK_HEADLESS=1" >> "$HOME/.dfhackrc" script: - export PATH="$PATH:$HOME/lua53/bin" - git tag tmp-travis-build diff --git a/library/Core.cpp b/library/Core.cpp index 5173a3ad9..58b3f85f5 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -81,6 +81,10 @@ using namespace DFHack; #include "SDL_events.h" +#ifdef LINUX_BUILD +#include +#endif + using namespace tthread; using namespace df::enums; using df::global::init; @@ -1638,7 +1642,24 @@ bool Core::Init() cerr << "Initializing Console.\n"; // init the console. bool is_text_mode = (init && init->display.flag.is_set(init_display_flags::TEXT)); - if (is_text_mode || getenv("DFHACK_DISABLE_CONSOLE")) + bool is_headless = bool(getenv("DFHACK_HEADLESS")); + if (is_headless) + { +#ifdef LINUX_BUILD + auto endwin = (int(*)(void))dlsym(RTLD_DEFAULT, "endwin"); + if (endwin) + { + endwin(); + } + else + { + cerr << "endwin(): bind failed" << endl; + } +#else + cerr << "Headless mode not supported on Windows" << endl; +#endif + } + if ((is_text_mode && !is_headless) || getenv("DFHACK_DISABLE_CONSOLE")) { con.init(true); cerr << "Console is not available. Use dfhack-run to send commands.\n"; @@ -1718,7 +1739,7 @@ bool Core::Init() HotkeyMutex = new mutex(); HotkeyCond = new condition_variable(); - if (!is_text_mode) + if (!is_text_mode || is_headless) { cerr << "Starting IO thread.\n"; // create IO thread From 956d0ce3634289a3ef4e44030c3382a0161859c6 Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 4 Feb 2018 10:30:49 +0530 Subject: [PATCH 146/170] update submodules. --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 6652fd55e..392922a04 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6652fd55e5e489c8a5d12467d1ea85c83192ba17 +Subproject commit 392922a045f7965a0d75d16062452f37a7bcf7be diff --git a/scripts b/scripts index b330e696e..8d079a591 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b330e696e6cb6a607d8cc77679bbe0fa5e51598c +Subproject commit 8d079a59122d9ba72ce9c0f7687402a343d09bc7 From a5cca757154813c5d3acb7050aed148538c2859b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 00:17:46 -0500 Subject: [PATCH 147/170] headless: Disable sound, wgetch --- library/Hooks-linux.cpp | 4 ++++ travis/download-df.sh | 1 + 2 files changed, 5 insertions(+) diff --git a/library/Hooks-linux.cpp b/library/Hooks-linux.cpp index b0bf5a781..8291bf899 100644 --- a/library/Hooks-linux.cpp +++ b/library/Hooks-linux.cpp @@ -88,6 +88,10 @@ DFhackCExport int SDL_PollEvent(SDL::Event* event) struct WINDOW; DFhackCExport int wgetch(WINDOW *win) { + if (getenv("DFHACK_HEADLESS")) + { + return 0; + } static int (*_wgetch)(WINDOW * win) = (int (*)( WINDOW * )) dlsym(RTLD_NEXT, "wgetch"); if(!_wgetch) { diff --git a/travis/download-df.sh b/travis/download-df.sh index 4430f7630..db5009069 100755 --- a/travis/download-df.sh +++ b/travis/download-df.sh @@ -34,6 +34,7 @@ tar xf "$tardest" --strip-components=1 echo Changing settings echo '' >> "$DF_FOLDER/data/init/init.txt" echo '[PRINT_MODE:TEXT]' >> "$DF_FOLDER/data/init/init.txt" +echo '[SOUND:NO]' >> "$DF_FOLDER/data/init/init.txt" echo Done echo "$selfmd5" > receipt From f8a9557562574d1b0dffc080df40e8f7dcf372bd Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 00:36:19 -0500 Subject: [PATCH 148/170] Exit with pop-screen --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d2516b967..187e9bce2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,7 @@ script: - cd build-travis - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DDFHACK_BUILD_ARCH=64 -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - make -j3 install -- "$DF_FOLDER/dfhack +devel/check-release +die" +- "$DF_FOLDER/dfhack +devel/check-release +devel/pop-screen" notifications: email: false # irc: From 4aa0990dc764ad5ab328a8d6da867e772486352a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 01:48:09 -0500 Subject: [PATCH 149/170] Fix issue with DF not quitting --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 187e9bce2..a706d8f79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,7 +47,8 @@ script: - cd build-travis - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DDFHACK_BUILD_ARCH=64 -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - make -j3 install -- "$DF_FOLDER/dfhack +devel/check-release +devel/pop-screen" +- mv "$DF_FOLDER"/dfhack.init-example "$DF_FOLDER"/dfhack.init +- "$DF_FOLDER/dfhack" "+devel/check-release" "+lua" "scr.breakdown_level=1" notifications: email: false # irc: From 2de28d43576707820d2e2a3e4a76c4e4f2d6b561 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 02:13:20 -0500 Subject: [PATCH 150/170] Fix bash compat issues --- travis/download-df.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/travis/download-df.sh b/travis/download-df.sh index db5009069..20dc3dbd4 100755 --- a/travis/download-df.sh +++ b/travis/download-df.sh @@ -12,8 +12,8 @@ echo "DF_FOLDER: $DF_FOLDER" mkdir -p "$DF_FOLDER" cd "$DF_FOLDER" -if [[ -f receipt ]]; then - if [[ "$selfmd5" != "$(cat receipt)" ]]; then +if [ -f receipt ]; then + if [ "$selfmd5" != "$(cat receipt)" ]; then echo "download-df.sh changed; removing DF" else echo "Already downloaded $DF_VERSION" From 23efb1cbf11e8debbebeb4cbad5f355538ff46c1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 02:13:23 -0500 Subject: [PATCH 151/170] Run startup commands in dfhack_travis.init --- .travis.yml | 3 ++- travis/dfhack_travis.init | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 travis/dfhack_travis.init diff --git a/.travis.yml b/.travis.yml index a706d8f79..04bfcae9b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,8 @@ script: - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DDFHACK_BUILD_ARCH=64 -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - make -j3 install - mv "$DF_FOLDER"/dfhack.init-example "$DF_FOLDER"/dfhack.init -- "$DF_FOLDER/dfhack" "+devel/check-release" "+lua" "scr.breakdown_level=1" +- cp ../travis/dfhack_travis.init "$DF_FOLDER"/ +- "$DF_FOLDER/dfhack" notifications: email: false # irc: diff --git a/travis/dfhack_travis.init b/travis/dfhack_travis.init new file mode 100644 index 000000000..5b28cefef --- /dev/null +++ b/travis/dfhack_travis.init @@ -0,0 +1,2 @@ +devel/check-release +:lua scr.breakdown_level=df.interface_breakdown_types.QUIT From 78061085c6636e2f586d7aa92b77e2742e19918a Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 4 Feb 2018 16:02:02 +0530 Subject: [PATCH 152/170] Add art image properties to RFR --- library/xml | 2 +- plugins/proto/RemoteFortressReader.proto | 69 +++++++++++++++++++- plugins/remotefortressreader/item_reader.cpp | 32 +++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 392922a04..40da7231a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 392922a045f7965a0d75d16062452f37a7bcf7be +Subproject commit 40da7231a0114fe3420d475961b08826f64fbf79 diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 96dc37a8d..35f5b0abe 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -935,10 +935,25 @@ message ArtImageElement optional int32 id = 6; } +enum ArtImagePropertyType +{ + TRANSITIVE_VERB = 0; + INTRANSITIVE_VERB = 1; +} + +message ArtImageProperty +{ + optional int32 subject = 1; + optional int32 object = 2; + optional ArtImageVerb verb = 3; + optional ArtImagePropertyType type = 4; +} + message ArtImage { repeated ArtImageElement elements = 1; optional MatPair id = 2; + repeated ArtImageProperty properties = 3; } message Engraving @@ -957,4 +972,56 @@ message Engraving optional bool northeast = 12; optional bool southwest = 13; optional bool southeast = 14; - } \ No newline at end of file +} + +enum ArtImageVerb +{ + VERB_WITHERING = 0; + VERB_SURROUNDEDBY = 1; + VERB_MASSACRING = 2; + VERB_FIGHTING = 3; + VERB_LABORING = 4; + VERB_GREETING = 5; + VERB_REFUSING = 6; + VERB_SPEAKING = 7; + VERB_EMBRACING = 8; + VERB_STRIKINGDOWN = 9; + VERB_MENACINGPOSE = 10; + VERB_TRAVELING = 11; + VERB_RAISING = 12; + VERB_HIDING = 13; + VERB_LOOKINGCONFUSED = 14; + VERB_LOOKINGTERRIFIED = 15; + VERB_DEVOURING = 16; + VERB_ADMIRING = 17; + VERB_BURNING = 18; + VERB_WEEPING = 19; + VERB_LOOKINGDEJECTED = 20; + VERB_CRINGING = 21; + VERB_SCREAMING = 22; + VERB_SUBMISSIVEGESTURE = 23; + VERB_FETALPOSITION = 24; + VERB_SMEAREDINTOSPIRAL = 25; + VERB_FALLING = 26; + VERB_DEAD = 27; + VERB_LAUGHING = 28; + VERB_LOOKINGOFFENDED = 29; + VERB_BEINGSHOT = 30; + VERB_PLAINTIVEGESTURE = 31; + VERB_MELTING = 32; + VERB_SHOOTING = 33; + VERB_TORTURING = 34; + VERB_COMMITTINGDEPRAVEDACT = 35; + VERB_PRAYING = 36; + VERB_CONTEMPLATING = 37; + VERB_COOKING = 38; + VERB_ENGRAVING = 39; + VERB_PROSTRATING = 40; + VERB_SUFFERING = 41; + VERB_BEINGIMPALED = 42; + VERB_BEINGCONTORTED = 43; + VERB_BEINGFLAYED = 44; + VERB_HANGINGFROM = 45; + VERB_BEINGMUTILATED = 46; + VERB_TRIUMPHANTPOSE = 47; +} diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp index 3a9fed571..f96397409 100644 --- a/plugins/remotefortressreader/item_reader.cpp +++ b/plugins/remotefortressreader/item_reader.cpp @@ -11,6 +11,9 @@ #include "df/art_image_element_shapest.h" #include "df/art_image_element_treest.h" #include "df/art_image_element_type.h" +#include "df/art_image_property.h" +#include "df/art_image_property_intransitive_verbst.h" +#include "df/art_image_property_transitive_verbst.h" #include "df/art_image_ref.h" #include "df/descriptor_shape.h" #include "df/item_type.h" @@ -105,6 +108,35 @@ void CopyImage(const df::art_image * image, ArtImage * netImage) break; } } + for (int i = 0; i < image->properties.size(); i++) + { + auto dfProperty = image->properties[i]; + auto netProperty = netImage->add_properties(); + auto propertyType = dfProperty->getType(); + + netProperty->set_type((ArtImagePropertyType)propertyType); + + switch (propertyType) + { + case df::enums::art_image_property_type::transitive_verb: + { + VIRTUAL_CAST_VAR(transitive, df::art_image_property_transitive_verbst, dfProperty); + netProperty->set_subject(transitive->subject); + netProperty->set_object(transitive->object); + netProperty->set_verb((ArtImageVerb)transitive->verb); + break; + } + case df::enums::art_image_property_type::intransitive_verb: + { + VIRTUAL_CAST_VAR(intransitive, df::art_image_property_intransitive_verbst, dfProperty); + netProperty->set_subject(intransitive->subject); + netProperty->set_verb((ArtImageVerb)intransitive->verb); + break; + } + default: + break; + } + } } void CopyItem(RemoteFortressReader::Item * NetItem, df::item * DfItem) From 2af5f7ab870901edc5237e62f01e1be15a1d074f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 16:00:53 -0500 Subject: [PATCH 153/170] Add test runner --- .travis.yml | 5 +++-- test/main.lua | 10 ++++++++++ travis/dfhack_travis.init | 4 ++-- travis/run-tests.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 test/main.lua create mode 100644 travis/run-tests.py diff --git a/.travis.yml b/.travis.yml index 04bfcae9b..147cd13fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,8 +48,9 @@ script: - cmake .. -DCMAKE_C_COMPILER=gcc-$GCC_VERSION -DCMAKE_CXX_COMPILER=g++-$GCC_VERSION -DDFHACK_BUILD_ARCH=64 -DBUILD_DOCS:BOOL=ON -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - make -j3 install - mv "$DF_FOLDER"/dfhack.init-example "$DF_FOLDER"/dfhack.init -- cp ../travis/dfhack_travis.init "$DF_FOLDER"/ -- "$DF_FOLDER/dfhack" +- cd .. +- cp travis/dfhack_travis.init "$DF_FOLDER"/ +- python travis/run-tests.py "$DF_FOLDER" notifications: email: false # irc: diff --git a/test/main.lua b/test/main.lua new file mode 100644 index 000000000..0085a9711 --- /dev/null +++ b/test/main.lua @@ -0,0 +1,10 @@ +function set_test_stage(stage) + local f = io.open('test_stage.txt', 'w') + f:write(stage) + f:close() +end + +print('running tests') + +set_test_stage('done') +dfhack.run_command('die') diff --git a/travis/dfhack_travis.init b/travis/dfhack_travis.init index 5b28cefef..d9bc3e5ba 100644 --- a/travis/dfhack_travis.init +++ b/travis/dfhack_travis.init @@ -1,2 +1,2 @@ -devel/check-release -:lua scr.breakdown_level=df.interface_breakdown_types.QUIT +:lua dfhack.internal.addScriptPath(os.getenv('TRAVIS_BUILD_DIR')) +test/main diff --git a/travis/run-tests.py b/travis/run-tests.py new file mode 100644 index 000000000..a8265088c --- /dev/null +++ b/travis/run-tests.py @@ -0,0 +1,30 @@ +import os, subprocess, sys + +MAX_TRIES = 5 + +dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' +test_stage = 'test_stage.txt' + +def get_test_stage(): + if os.path.isfile(test_stage): + return open(test_stage).read().strip() + return '0' + +os.chdir(sys.argv[1]) +if os.path.exists(test_stage): + os.remove(test_stage) + +tries = 0 +while True: + tries += 1 + stage = get_test_stage() + print('Run #%i: stage=%s' % (tries, get_test_stage())) + if stage == 'done': + print('Done!') + os.remove(test_stage) + sys.exit(0) + if tries > MAX_TRIES: + print('Too many tries - aborting') + sys.exit(1) + + os.system(dfhack) From b2a19dedeb589cc9db11479a6034a929e4bd109b Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 22:56:24 -0500 Subject: [PATCH 154/170] load-art-image-chunk: safety check --- plugins/remotefortressreader/remotefortressreader.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 32bd73dad..5b84bf745 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -188,6 +188,11 @@ command_result loadArtImageChunk(color_ostream &out, vector & parameter if (parameters.size() != 1) return CR_WRONG_USAGE; + if (!Core::getInstance().isWorldLoaded()) + { + out.printerr("No world loaded\n"); + return CR_FAILURE; + } GET_ART_IMAGE_CHUNK GetArtImageChunk = reinterpret_cast(Core::getInstance().vinfo->getAddress("get_art_image_chunk")); if (GetArtImageChunk) @@ -2983,4 +2988,4 @@ static command_result GetLanguage(color_ostream & stream, const EmptyMessage * i netShape->set_tile(shape->tile); } return CR_OK; -} \ No newline at end of file +} From c92227f007114148f0b48059908b86645a6c36d7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 4 Feb 2018 23:02:12 -0500 Subject: [PATCH 155/170] Update news (RFR, #1214) --- NEWS.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index ce8635675..478c79e01 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -106,7 +106,11 @@ Misc Improvements - only prints output if ``-loud`` is passed - `names`: can now edit names of units -- `remotefortressreader`: includes item stack sizes and some performance improvements +- `remotefortressreader`: + + - support for moving adventurers + - suport for item stack sizes, vehicles, gem shapes, item volume, art images, item improvements + - some performance improvements Removed ------- From c1e2633e17b7ef4a2f90c3dd3a7cccf646ec93ad Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 5 Feb 2018 19:18:35 -0500 Subject: [PATCH 156/170] Refactor DFHack exception classes Move implementations out of MiscUtils.cpp to Error.cpp and make what() return a more useful description --- library/CMakeLists.txt | 1 + library/Error.cpp | 44 +++++++++++++++++ library/LuaTypes.cpp | 29 ++--------- library/MiscUtils.cpp | 12 ----- library/include/Error.h | 97 +++++++++++++------------------------ library/include/MiscUtils.h | 18 +++++++ 6 files changed, 102 insertions(+), 99 deletions(-) create mode 100644 library/Error.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 40c122de9..807a2845e 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -57,6 +57,7 @@ SET(MAIN_SOURCES Core.cpp ColorText.cpp DataDefs.cpp +Error.cpp VTableInterpose.cpp LuaWrapper.cpp LuaTypes.cpp diff --git a/library/Error.cpp b/library/Error.cpp new file mode 100644 index 000000000..773362af3 --- /dev/null +++ b/library/Error.cpp @@ -0,0 +1,44 @@ +#include "Error.h" +#include "MiscUtils.h" + +using namespace DFHack::Error; + +inline const char *safe_str(const char *s) +{ + return s ? s : "(NULL)"; +} + +NullPointer::NullPointer(const char *varname) + :All(stl_concat("NULL pointer: ", safe_str(varname))), + varname(varname) +{} + +InvalidArgument::InvalidArgument(const char *expr) + :All(stl_concat("Invalid argument; expected: ", safe_str(expr))), + expr(expr) +{} + +VTableMissing::VTableMissing(const char *name) + :All(stl_concat("Missing vtable address: ", safe_str(name))), + name(name) +{} + +SymbolsXmlParse::SymbolsXmlParse(const char* desc, int id, int row, int col) + :AllSymbols(stl_concat("error ", id, ": ", desc, ", at row ", row, " col ", col)), + desc(safe_str(desc)), id(id), row(row), col(col) +{} + +SymbolsXmlBadAttribute::SymbolsXmlBadAttribute(const char *attr) + :AllSymbols(stl_concat("attribute is either missing or invalid: ", safe_str(attr))), + attr(safe_str(attr)) +{} + +SymbolsXmlNoRoot::SymbolsXmlNoRoot() + :AllSymbols("no root element") +{} + +SymbolsXmlUnderspecifiedEntry::SymbolsXmlUnderspecifiedEntry(const char *where) + :AllSymbols(stl_concat("Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: ", + safe_str(where))), + where(safe_str(where)) +{} diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index f30a1878e..f744f3eba 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1076,20 +1076,8 @@ int LuaWrapper::method_wrapper_core(lua_State *state, function_identity_base *id try { id->invoke(state, 1); } - catch (Error::NullPointer &e) { - const char *vn = e.varname(); - std::string tmp = stl_sprintf("NULL pointer: %s", vn ? vn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); - } - catch (Error::InvalidArgument &e) { - const char *vn = e.expr(); - std::string tmp = stl_sprintf("Invalid argument; expected: %s", vn ? vn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); - } - catch (Error::VTableMissing &e) { - const char *cn = e.name(); - std::string tmp = stl_sprintf("Missing vtable address: %s", cn ? cn : "?"); - field_error(state, UPVAL_METHOD_NAME, tmp.c_str(), "invoke"); + catch (Error::All &e) { + field_error(state, UPVAL_METHOD_NAME, e.what(), "invoke"); } catch (std::exception &e) { std::string tmp = stl_sprintf("C++ exception: %s", e.what()); @@ -1107,17 +1095,8 @@ int Lua::CallWithCatch(lua_State *state, int (*fn)(lua_State*), const char *cont try { return fn(state); } - catch (Error::NullPointer &e) { - const char *vn = e.varname(); - return luaL_error(state, "%s: NULL pointer: %s", context, vn ? vn : "?"); - } - catch (Error::InvalidArgument &e) { - const char *vn = e.expr(); - return luaL_error(state, "%s: Invalid argument; expected: %s", context, vn ? vn : "?"); - } - catch (Error::VTableMissing &e) { - const char *cn = e.name(); - return luaL_error(state, "%s: Missing vtable address: %s", context, cn ? cn : "?"); + catch (Error::All &e) { + return luaL_error(state, "%s: %s", context, e.what()); } catch (std::exception &e) { return luaL_error(state, "%s: C++ exception: %s", context, e.what()); diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index bff7f07e1..afc3dca70 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -41,18 +41,6 @@ distribution. #include #include -const char *DFHack::Error::NullPointer::what() const throw() { - return "DFHack::Error::NullPointer"; -} - -const char *DFHack::Error::InvalidArgument::what() const throw() { - return "DFHack::Error::InvalidArgument"; -} - -const char *DFHack::Error::VTableMissing::what() const throw() { - return "DFHack::Error::VTableMissing"; -} - std::string stl_sprintf(const char *fmt, ...) { va_list lst; va_start(lst, fmt); diff --git a/library/include/Error.h b/library/include/Error.h index 2d0baadfc..d3d208b1f 100644 --- a/library/include/Error.h +++ b/library/include/Error.h @@ -41,118 +41,91 @@ namespace DFHack #ifdef _MSC_VER #pragma push /** - * C4275 is - The warning officially is non dll-interface class 'std::exception' used as base for + * C4275 - The warning officially is non dll-interface class 'std::exception' used as base for * dll-interface class * - * Basically, its saying that you might have an ABI problem if you mismatch compilers. We don't + * Basically, it's saying that you might have an ABI problem if you mismatch compilers. We don't * care since we build all of DFhack at once against whatever Toady is using */ #pragma warning(disable: 4275) #endif - class DFHACK_EXPORT All : public std::exception{}; + class DFHACK_EXPORT All : public std::exception + { + public: + const std::string full; + All(const std::string &full) + :full(full) + {} + virtual const char *what() const noexcept + { + return full.c_str(); + } + virtual ~All() noexcept {} + }; #ifdef _MSC_VER #pragma pop #endif class DFHACK_EXPORT NullPointer : public All { - const char *varname_; public: - NullPointer(const char *varname_ = NULL) : varname_(varname_) {} - const char *varname() const { return varname_; } - virtual const char *what() const throw(); + const char *const varname; + NullPointer(const char *varname = NULL); }; #define CHECK_NULL_POINTER(var) \ { if (var == NULL) throw DFHack::Error::NullPointer(#var); } class DFHACK_EXPORT InvalidArgument : public All { - const char *expr_; public: - InvalidArgument(const char *expr_ = NULL) : expr_(expr_) {} - const char *expr() const { return expr_; } - virtual const char *what() const throw(); + const char *const expr; + InvalidArgument(const char *expr = NULL); }; #define CHECK_INVALID_ARGUMENT(expr) \ { if (!(expr)) throw DFHack::Error::InvalidArgument(#expr); } class DFHACK_EXPORT VTableMissing : public All { - const char *name_; public: - VTableMissing(const char *name_ = NULL) : name_(name_) {} - const char *name() const { return name_; } - virtual const char *what() const throw(); + const char *const name; + VTableMissing(const char *name = NULL); }; - class DFHACK_EXPORT AllSymbols : public All{}; + class DFHACK_EXPORT AllSymbols : public All + { + public: + AllSymbols(const std::string &full) + :All(full) + {} + }; // Syntax errors and whatnot, the xml can't be read class DFHACK_EXPORT SymbolsXmlParse : public AllSymbols { public: - SymbolsXmlParse(const char* _desc, int _id, int _row, int _col) - :desc(_desc), id(_id), row(_row), col(_col) - { - std::stringstream s; - s << "error " << id << ": " << desc << ", at row " << row << " col " << col; - full = s.str(); - } - std::string full; + SymbolsXmlParse(const char* desc, int id, int row, int col); const std::string desc; const int id; const int row; const int col; - virtual ~SymbolsXmlParse() throw(){}; - virtual const char* what() const throw() - { - return full.c_str(); - } }; - class DFHACK_EXPORT SymbolsXmlBadAttribute : public All + class DFHACK_EXPORT SymbolsXmlBadAttribute : public AllSymbols { public: - SymbolsXmlBadAttribute(const char* _attr) : attr(_attr) - { - std::stringstream s; - s << "attribute is either missing or invalid: " << attr; - full = s.str(); - } - std::string full; + SymbolsXmlBadAttribute(const char* attr); std::string attr; - virtual ~SymbolsXmlBadAttribute() throw(){}; - virtual const char* what() const throw() - { - return full.c_str(); - } }; - class DFHACK_EXPORT SymbolsXmlNoRoot : public All + class DFHACK_EXPORT SymbolsXmlNoRoot : public AllSymbols { public: - SymbolsXmlNoRoot() {} - virtual ~SymbolsXmlNoRoot() throw(){}; - virtual const char* what() const throw() - { - return "Symbol file is missing root element."; - } + SymbolsXmlNoRoot(); }; - class DFHACK_EXPORT SymbolsXmlUnderspecifiedEntry : public All + class DFHACK_EXPORT SymbolsXmlUnderspecifiedEntry : public AllSymbols { public: - SymbolsXmlUnderspecifiedEntry(const char * _where) : where(_where) - { - std::stringstream s; - s << "Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: " << where; - full = s.str(); - } - virtual ~SymbolsXmlUnderspecifiedEntry() throw(){}; + SymbolsXmlUnderspecifiedEntry(const char *where); std::string where; - std::string full; - virtual const char* what() const throw() - { - return full.c_str(); - } }; } } diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 917b67489..ff0c842c5 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -349,6 +349,24 @@ DFHACK_EXPORT uint64_t GetTimeMs64(); DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...); DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args); +// https://stackoverflow.com/questions/27375089/what-is-the-easiest-way-to-print-a-variadic-parameter-pack-using-stdostream +template +inline std::string stl_concat(Args... args) +{ + std::ostringstream os; + (void)(int[]){0, (void(os << std::forward(args)), 0)...}; + return os.str(); +} + +template +inline std::string stl_concat(const std::string &sep, Args... args) +{ + std::ostringstream os; + (void)(int[]){0, (void(os << sep << std::forward(args)), 0)...}; + return os.str(); +} + + // Conversion between CP437 and UTF-8 DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in); From a37ac2c349737f68d1772ba37993a0efa884b3c0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 5 Feb 2018 19:22:07 -0500 Subject: [PATCH 157/170] Re-enable IRC notifications --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 147cd13fe..ede4b132b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -53,8 +53,8 @@ script: - python travis/run-tests.py "$DF_FOLDER" notifications: email: false - # irc: - # channels: - # - "chat.freenode.net#dfhack" - # on_success: change - # on_failure: always + irc: + channels: + - "chat.freenode.net#dfhack" + on_success: change + on_failure: always From 7426f0850457102575d0e029f76f2c5849562e76 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Wed, 7 Feb 2018 10:40:52 -0600 Subject: [PATCH 158/170] Fix Error.cpp compile for Windows --- library/Error.cpp | 15 +++++++-------- library/include/MiscUtils.h | 18 ------------------ 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/library/Error.cpp b/library/Error.cpp index 773362af3..ba1482918 100644 --- a/library/Error.cpp +++ b/library/Error.cpp @@ -3,33 +3,33 @@ using namespace DFHack::Error; -inline const char *safe_str(const char *s) +inline std::string safe_str(const char *s) { return s ? s : "(NULL)"; } NullPointer::NullPointer(const char *varname) - :All(stl_concat("NULL pointer: ", safe_str(varname))), + :All("NULL pointer: " + safe_str(varname)), varname(varname) {} InvalidArgument::InvalidArgument(const char *expr) - :All(stl_concat("Invalid argument; expected: ", safe_str(expr))), + :All("Invalid argument; expected: " + safe_str(expr)), expr(expr) {} VTableMissing::VTableMissing(const char *name) - :All(stl_concat("Missing vtable address: ", safe_str(name))), + :All("Missing vtable address: " + safe_str(name)), name(name) {} SymbolsXmlParse::SymbolsXmlParse(const char* desc, int id, int row, int col) - :AllSymbols(stl_concat("error ", id, ": ", desc, ", at row ", row, " col ", col)), + :AllSymbols(stl_sprintf("error %d: %s, at row %d col %d", id, desc, row, col)), desc(safe_str(desc)), id(id), row(row), col(col) {} SymbolsXmlBadAttribute::SymbolsXmlBadAttribute(const char *attr) - :AllSymbols(stl_concat("attribute is either missing or invalid: ", safe_str(attr))), + :AllSymbols("attribute is either missing or invalid: " + safe_str(attr)), attr(safe_str(attr)) {} @@ -38,7 +38,6 @@ SymbolsXmlNoRoot::SymbolsXmlNoRoot() {} SymbolsXmlUnderspecifiedEntry::SymbolsXmlUnderspecifiedEntry(const char *where) - :AllSymbols(stl_concat("Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: ", - safe_str(where))), + :AllSymbols("Underspecified symbol file entry, each entry needs to set both the name attribute and have a value. parent: " + safe_str(where)), where(safe_str(where)) {} diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index ff0c842c5..917b67489 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -349,24 +349,6 @@ DFHACK_EXPORT uint64_t GetTimeMs64(); DFHACK_EXPORT std::string stl_sprintf(const char *fmt, ...); DFHACK_EXPORT std::string stl_vsprintf(const char *fmt, va_list args); -// https://stackoverflow.com/questions/27375089/what-is-the-easiest-way-to-print-a-variadic-parameter-pack-using-stdostream -template -inline std::string stl_concat(Args... args) -{ - std::ostringstream os; - (void)(int[]){0, (void(os << std::forward(args)), 0)...}; - return os.str(); -} - -template -inline std::string stl_concat(const std::string &sep, Args... args) -{ - std::ostringstream os; - (void)(int[]){0, (void(os << sep << std::forward(args)), 0)...}; - return os.str(); -} - - // Conversion between CP437 and UTF-8 DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in); From 7ab8d74ac9e7cc6b7dbcf942cdc58ed7cc72458c Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Wed, 7 Feb 2018 14:32:27 -0600 Subject: [PATCH 159/170] Add mising Error.cpp reference to dfhack-client --- library/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 807a2845e..4d4a4e9f1 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -320,7 +320,7 @@ ADD_DEPENDENCIES(dfhack-version git-describe) ADD_LIBRARY(dfhack SHARED ${PROJECT_SOURCES}) ADD_DEPENDENCIES(dfhack generate_headers generate_proto_core) -ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ${PROJECT_PROTO_SRCS}) +ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp Error.cpp ${PROJECT_PROTO_SRCS}) ADD_DEPENDENCIES(dfhack-client dfhack) ADD_EXECUTABLE(dfhack-run dfhack-run.cpp) From 19b65c2d1eb603e0344c1c7133f96f63cdeb03a3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 7 Feb 2018 20:14:36 -0500 Subject: [PATCH 160/170] Remove Error.h include (#1224) --- library/MiscUtils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index afc3dca70..e350cb9ec 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -25,7 +25,6 @@ distribution. #include "Internal.h" #include "Export.h" #include "MiscUtils.h" -#include "Error.h" #ifndef LINUX_BUILD #include From 55f5439ddf0e1688e49c51966e18e4ef4132ffdf Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 9 Feb 2018 02:07:08 -0500 Subject: [PATCH 161/170] dwarfmonitor: remove unused hook, use CoreSuspendClaimer --- plugins/dwarfmonitor.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 7aed7188d..bf7c02efc 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -1870,15 +1870,11 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest { typedef df::viewscreen_dwarfmodest interpose_base; - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - INTERPOSE_NEXT(feed)(input); - } - DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)(); + CoreSuspendClaimer suspend; if (Maps::IsValid()) { dm_lua::call("render_all"); @@ -1886,7 +1882,6 @@ struct dwarf_monitor_hook : public df::viewscreen_dwarfmodest } }; -IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(dwarf_monitor_hook, render); static bool set_monitoring_mode(const string &mode, const bool &state) @@ -1933,8 +1928,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) load_config(); if (is_enabled != enable) { - if (!INTERPOSE_HOOK(dwarf_monitor_hook, feed).apply(enable) || - !INTERPOSE_HOOK(dwarf_monitor_hook, render).apply(enable)) + if (!INTERPOSE_HOOK(dwarf_monitor_hook, render).apply(enable)) return CR_FAILURE; reset(); From 342f193409f387e64ee00fba09c2220b1c98ac9d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Feb 2018 02:07:30 -0500 Subject: [PATCH 162/170] autochop: store skip settings in one field, fix double colon and initial load language_name fields default to -1, so the new settings could have been enabled on all worlds by default. --- plugins/autochop.cpp | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 3b75068f6..6ba7709cc 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -49,9 +49,26 @@ static bool autochop_enabled = false; static int min_logs, max_logs; static const int LOG_CAP_MAX = 99999; static bool wait_for_threshold; -static bool skip_fruit_trees; -static bool skip_food_trees; -static bool skip_cook_trees; +struct Skip { + bool fruit_trees; + bool food_trees; + bool cook_trees; + operator int() { + return (fruit_trees ? 1 : 0) | + (food_trees ? 2 : 0) | + (cook_trees ? 4 : 0); + } + Skip &operator= (int in) { + // set all fields to false if they haven't been set in this save yet + if (in < 0) + in = 0; + fruit_trees = (in & 1); + food_trees = (in & 2); + cook_trees = (in & 4); + return *this; + } +}; +static Skip skip; static PersistentDataItem config_autochop; @@ -183,9 +200,7 @@ static void save_config() config_autochop.ival(1) = min_logs; config_autochop.ival(2) = max_logs; config_autochop.ival(3) = wait_for_threshold; - config_autochop.ival(5) = skip_fruit_trees; - config_autochop.ival(6) = skip_food_trees; - config_autochop.ival(7) = skip_cook_trees; + config_autochop.ival(4) = skip; } static void initialize() @@ -195,9 +210,7 @@ static void initialize() min_logs = 80; max_logs = 100; wait_for_threshold = false; - skip_fruit_trees = false; - skip_food_trees = false; - skip_cook_trees = false; + skip = 0; config_autochop = World::GetPersistentData("autochop/config"); if (config_autochop.isValid()) @@ -207,9 +220,7 @@ static void initialize() min_logs = config_autochop.ival(1); max_logs = config_autochop.ival(2); wait_for_threshold = config_autochop.ival(3); - skip_fruit_trees = config_autochop.ival(4); - skip_food_trees = config_autochop.ival(5); - skip_cook_trees = config_autochop.ival(6); + skip = config_autochop.ival(4); } else { @@ -240,19 +251,19 @@ static bool skip_plant(const df::plant * plant) const df::plant_raw *plant_raw = df::plant_raw::find(plant->material); // Skip fruit trees if set. - if (skip_fruit_trees && plant_raw->material_defs.type_drink != -1) + if (skip.fruit_trees && plant_raw->material_defs.type_drink != -1) return true; - if (skip_food_trees || skip_cook_trees) + if (skip.food_trees || skip.cook_trees) { df::material * mat; for (int idx = 0; idx < plant_raw->material.size(); idx++) { mat = plant_raw->material[idx]; - if (skip_food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) + if (skip.food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) return true; - if (skip_cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) + if (skip.cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) return true; } } @@ -603,15 +614,15 @@ public: } else if (input->count(interface_key::CUSTOM_F)) { - skip_fruit_trees = !skip_fruit_trees; + skip.fruit_trees = !skip.fruit_trees; } else if (input->count(interface_key::CUSTOM_E)) { - skip_food_trees = !skip_food_trees; + skip.food_trees = !skip.food_trees; } else if (input->count(interface_key::CUSTOM_C)) { - skip_cook_trees = !skip_cook_trees; + skip.cook_trees = !skip.cook_trees; } else if (enabler->tracking_on && enabler->mouse_lbut) { @@ -696,9 +707,9 @@ public: OutputString(COLOR_WHITE, x, y, "", true, left_margin); } OutputHotkeyString(x, y, "No limit", CUSTOM_SHIFT_N, true, left_margin); - OutputToggleString(x, y, "Skip Fruit Trees: ", CUSTOM_F, skip_fruit_trees, true, left_margin); - OutputToggleString(x, y, "Skip Edible Product Trees: ", CUSTOM_E, skip_food_trees, true, left_margin); - OutputToggleString(x, y, "Skip Cookable Product Trees: ", CUSTOM_C, skip_cook_trees, true, left_margin); + OutputToggleString(x, y, "Skip Fruit Trees", CUSTOM_F, skip.fruit_trees, true, left_margin); + OutputToggleString(x, y, "Skip Edible Product Trees", CUSTOM_E, skip.food_trees, true, left_margin); + OutputToggleString(x, y, "Skip Cookable Product Trees", CUSTOM_C, skip.cook_trees, true, left_margin); } ++y; From 9a0befa4cbb463f75c682d937134bfa8749a54b7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Feb 2018 03:03:07 -0500 Subject: [PATCH 163/170] Show number of trees skipped --- plugins/autochop.cpp | 61 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 6ba7709cc..a2a863540 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -230,8 +230,11 @@ static void initialize() } } -static bool skip_plant(const df::plant * plant) +static bool skip_plant(const df::plant * plant, bool *restricted) { + if (restricted) + *restricted = false; + // Skip all non-trees immediately. if (plant->flags.bits.is_shrub) return true; @@ -248,11 +251,19 @@ static bool skip_plant(const df::plant * plant) if (cur->designation[x][y].bits.hidden) return true; + df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); + if (material != tiletype_material::TREE) + return true; + const df::plant_raw *plant_raw = df::plant_raw::find(plant->material); // Skip fruit trees if set. if (skip.fruit_trees && plant_raw->material_defs.type_drink != -1) + { + if (restricted) + *restricted = true; return true; + } if (skip.food_trees || skip.cook_trees) { @@ -261,29 +272,44 @@ static bool skip_plant(const df::plant * plant) { mat = plant_raw->material[idx]; if (skip.food_trees && mat->flags.is_set(material_flags::EDIBLE_RAW)) + { + if (restricted) + *restricted = true; return true; + } if (skip.cook_trees && mat->flags.is_set(material_flags::EDIBLE_COOKED)) + { + if (restricted) + *restricted = true; return true; + } } } - df::tiletype_material material = tileMaterial(cur->tiletype[x][y]); - if (material != tiletype_material::TREE) - return true; - return false; } -static int do_chop_designation(bool chop, bool count_only) +static int do_chop_designation(bool chop, bool count_only, int *skipped = nullptr) { int count = 0; + if (skipped) + { + *skipped = 0; + } for (size_t i = 0; i < world->plants.all.size(); i++) { const df::plant *plant = world->plants.all[i]; - if (skip_plant(plant)) + bool restricted = false; + if (skip_plant(plant, &restricted)) + { + if (restricted && skipped) + { + ++*skipped; + } continue; + } if (!count_only && !watchedBurrows.isValidPos(plant->pos)) continue; @@ -425,7 +451,11 @@ static void do_autochop() class ViewscreenAutochop : public dfhack_viewscreen { public: - ViewscreenAutochop() + ViewscreenAutochop(): + selected_column(0), + current_log_count(0), + marked_tree_count(0), + skipped_tree_count(0) { edit_mode = EDIT_NONE; burrows_column.multiselect = true; @@ -459,7 +489,7 @@ public: burrows_column.filterDisplay(); current_log_count = get_log_count(); - marked_tree_count = do_chop_designation(false, true); + marked_tree_count = do_chop_designation(false, true, &skipped_tree_count); } void change_min_logs(int delta) @@ -559,13 +589,21 @@ public: { int count = do_chop_designation(true, false); message = "Trees marked for chop: " + int_to_string(count); - marked_tree_count = do_chop_designation(false, true); + marked_tree_count = do_chop_designation(false, true, &skipped_tree_count); + if (skipped_tree_count) + { + message += ", skipped: " + int_to_string(skipped_tree_count); + } } else if (input->count(interface_key::CUSTOM_U)) { int count = do_chop_designation(false, false); message = "Trees unmarked: " + int_to_string(count); - marked_tree_count = do_chop_designation(false, true); + marked_tree_count = do_chop_designation(false, true, &skipped_tree_count); + if (skipped_tree_count) + { + message += ", skipped: " + int_to_string(skipped_tree_count); + } } else if (input->count(interface_key::CUSTOM_N)) { @@ -734,6 +772,7 @@ private: int selected_column; int current_log_count; int marked_tree_count; + int skipped_tree_count; MapExtras::MapCache mcache; string message; enum { EDIT_NONE, EDIT_MIN, EDIT_MAX } edit_mode; From 9fe9e64f09ae89fd837528b9983af6ca9743d905 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Feb 2018 03:04:40 -0500 Subject: [PATCH 164/170] Add dtimm to Authors.rst (#1180) --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 8c1b5096e..aecfc519a 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -31,6 +31,7 @@ ClĂ©ment Vuchener cvuchener Dan Amlund danamlund David Corbett dscorbett David Seguin dseguin +David Timm dtimm Deon DoctorVanGogh DoctorVanGogh Donald Ruegsegger hashaash From ca29cb8e6f8b33f10b151c66c49a0c02c59bae46 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 10 Feb 2018 17:51:02 -0500 Subject: [PATCH 165/170] embark-assistant: update field names, now compiles --- plugins/embark-assistant/survey.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/embark-assistant/survey.cpp b/plugins/embark-assistant/survey.cpp index ace97e5b1..6583d2479 100644 --- a/plugins/embark-assistant/survey.cpp +++ b/plugins/embark-assistant/survey.cpp @@ -198,7 +198,7 @@ namespace embark_assist { x = world_data->rivers[i]->path.x[k]; y = world_data->rivers[i]->path.y[k]; - if (world_data->rivers[i]->unk_8c[k] < 5000) { + if (world_data->rivers[i]->flow[k] < 5000) { if (world_data->region_map[x][y].flags.is_set(df::region_map_entry_flags::is_brook)) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Brook; } @@ -206,10 +206,10 @@ namespace embark_assist { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Stream; } } - else if (world_data->rivers[i]->unk_8c[k] < 10000) { + else if (world_data->rivers[i]->flow[k] < 10000) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Minor; } - else if (world_data->rivers[i]->unk_8c[k] < 20000) { + else if (world_data->rivers[i]->flow[k] < 20000) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Medium; } else { @@ -227,7 +227,7 @@ namespace embark_assist { if (x >= 0 && y >= 0 && x < world->worldgen.worldgen_parms.dim_x && y < world->worldgen.worldgen_parms.dim_y) { if (survey_results->at(x).at(y).river_size == embark_assist::defs::river_sizes::None) { if (world_data->rivers[i]->path.x.size() && - world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 5000) { + world_data->rivers[i]->flow[world_data->rivers[i]->path.x.size() - 1] < 5000) { if (world_data->region_map[x][y].flags.is_set(df::region_map_entry_flags::is_brook)) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Brook; } @@ -235,10 +235,10 @@ namespace embark_assist { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Stream; } } - else if (world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 10000) { + else if (world_data->rivers[i]->flow[world_data->rivers[i]->path.x.size() - 1] < 10000) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Minor; } - else if (world_data->rivers[i]->unk_8c[world_data->rivers[i]->path.x.size() - 1] < 20000) { + else if (world_data->rivers[i]->flow[world_data->rivers[i]->path.x.size() - 1] < 20000) { survey_results->at(x).at(y).river_size = embark_assist::defs::river_sizes::Medium; } else { @@ -268,11 +268,11 @@ namespace embark_assist { reanimating = true; } else if (interaction->targets[k]->getType() == 2) {// Returns wrong type.. Should be df::interaction_target_type::MATERIAL - df::interaction_target_materialst* material = static_cast(interaction->targets[k]); - if (DFHack::MaterialInfo(material->anon_1, material->anon_2).isInorganic()) { - for (uint16_t l = 0; l < world->raws.inorganics[material->anon_2]->material.syndrome.size(); l++) { - for (uint16_t m = 0; m < world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce.size(); m++) { - if (world->raws.inorganics[material->anon_2]->material.syndrome[l]->ce[m]->getType() == df::creature_interaction_effect_type::FLASH_TILE) { + df::interaction_target_materialst* material = virtual_cast(interaction->targets[k]); + if (material && DFHack::MaterialInfo(material->mat_type, material->mat_index).isInorganic()) { + for (uint16_t l = 0; l < world->raws.inorganics[material->mat_index]->material.syndrome.size(); l++) { + for (uint16_t m = 0; m < world->raws.inorganics[material->mat_index]->material.syndrome[l]->ce.size(); m++) { + if (world->raws.inorganics[material->mat_index]->material.syndrome[l]->ce[m]->getType() == df::creature_interaction_effect_type::FLASH_TILE) { // Using this as a proxy. There seems to be a group of 4 effects for thralls: // display symbol, flash symbol, phys att change and one more. thralling = true; From b2fb6964731e711c2681c871aec8feb9b490284e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Feb 2018 02:38:50 -0500 Subject: [PATCH 166/170] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 8d079a591..28a1ccc98 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8d079a59122d9ba72ce9c0f7687402a343d09bc7 +Subproject commit 28a1ccc9883d85106fa3b0ed59ddd57fcfc3f5c7 From c136bcbabacd5ac025810a9df6271f360830b6f4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Feb 2018 02:47:41 -0500 Subject: [PATCH 167/170] Update NEWS --- NEWS.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index 478c79e01..ee685f8f9 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,6 +36,33 @@ Changelog .. contents:: :depth: 2 +DFHack 0.44.05-r2 +================= + +New Plugins +----------- +- `embark-assistant`: adds more information and features to embark screen + +New Scripts +----------- +- `adv-fix-sleepers`: fixes units in adventure mode who refuse to wake up (:bug:`6798`) +- `hermit`: blocks caravans, migrants, diplomats (for hermit challenge) + +New Features +------------ +- With ``PRINT_MODE:TEXT``, setting the ``DFHACK_HEADLESS`` environment variable + will hide DF's display and allow the console to be used normally. (Note that + this is intended for testing and is not very useful for actual gameplay.) + +Fixes +----- +- `devel/inject-raws`: fixed gloves and shoes (old typo causing errors) +- `view-item-info`: fixed an error with some shields + +Misc Improvements +----------------- +- `autochop`: can now exclude trees with fruit, + DFHack 0.44.05-r1 ================= From 269d575267d09ca85cb8d4b96e116b7674548dc4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Feb 2018 03:07:25 -0500 Subject: [PATCH 168/170] Document environment variables --- docs/Core.rst | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/docs/Core.rst b/docs/Core.rst index 15adcc533..b15305fa9 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -430,6 +430,45 @@ Other init files directory, will be run when any world or that save is loaded. +Environment variables +===================== + +DFHack's behavior can be adjusted with some environment variables. For example, +on UNIX-like systems:: + + DFHACK_SOME_VAR=1 ./dfhack + +- ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run`` + and `remotefortressreader` among others) instead of the default ``5000``. As + with the default, if this port cannot be used, the server is not started. + +- ``DFHACK_DISABLE_CONSOLE``: if set, the DFHack console is not set up. This is + the default behavior if ``PRINT_MODE:TEXT`` is set in ``data/init/init.txt``. + Intended for situations where DFHack cannot run in a terminal window. + +- ``DFHACK_HEADLESS``: if set, and ``PRINT_MODE:TEXT`` is set, DF's display will + be hidden, and the console will be started unless ``DFHACK_DISABLE_CONSOLE`` + is also set. Intended for non-interactive gameplay only. + +- ``DFHACK_NO_GLOBALS``, ``DFHACK_NO_VTABLES``: ignores all global or vtable + addresses in ``symbols.xml``, respectively. Intended for development use - + e.g. to make sure tools do not crash when these addresses are missing. + +- ``DFHACK_NO_DEV_PLUGINS``: if set, any plugins from the plugins/devel folder + that are built and installed will not be loaded on startup. + +- ``DFHACK_LOG_MEM_RANGES`` (macOS only): if set, logs memory ranges to + ``stderr.log``. Note that `devel/lsmem` can also do this. + +Other (non-DFHack-specific) variables that affect DFHack: + +- ``TERM``: if this is set to ``dumb`` or ``cons25`` on \*nix, the console will + not support any escape sequences (arrow keys, etc.). + +- ``LANG``, ``LC_CTYPE``: if either of these contain "UTF8" or "UTF-8" (not case + sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this + should be the case in most UTF-8-capable \*nix terminal emulators already. + Miscellaneous Notes =================== This section is for odd but important notes that don't fit anywhere else. From 6260062d0582a4089fd2d8e1274de6aa0db21c22 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 11 Feb 2018 03:08:02 -0500 Subject: [PATCH 169/170] Add basic embark-assistant docs (closes #1226) --- docs/Plugins.rst | 12 ++++++++++++ plugins/embark-assistant/embark-assistant.cpp | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c896b5fd0..da1231184 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -526,6 +526,18 @@ nopause Disables pausing (both manual and automatic) with the exception of pause forced by `reveal` ``hell``. This is nice for digging under rivers. +.. _embark-assistant: + +embark-assistant +================ + +This plugin provides embark site selection help. It has to be run with the +``embark-assistant`` command while the pre-embark screen is displayed and shows +extended (and correct(?)) resource information for the embark rectangle as well +as normally undisplayed sites in the current embark region. It also has a site +selection tool with more options than DF's vanilla search tool. For detailed +help invoke the in game info screen. Requires 42 lines to display properly. + .. _embark-tools: embark-tools diff --git a/plugins/embark-assistant/embark-assistant.cpp b/plugins/embark-assistant/embark-assistant.cpp index 283b696a0..7e0ea21cc 100644 --- a/plugins/embark-assistant/embark-assistant.cpp +++ b/plugins/embark-assistant/embark-assistant.cpp @@ -138,7 +138,7 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector & &embark_assist::main::state->survey_results); embark_assist::main::state->match_results.resize(world->worldgen.worldgen_parms.dim_x); - + for (uint16_t i = 0; i < world->worldgen.worldgen_parms.dim_x; i++) { embark_assist::main::state->match_results[i].resize(world->worldgen.worldgen_parms.dim_y); } From 23d02a642ddef76ed37838862be549d735871a66 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 12 Feb 2018 01:45:53 -0500 Subject: [PATCH 170/170] Make tweak pausing-fps-counter non-default for now Ref #1219 --- dfhack.init-example | 3 --- 1 file changed, 3 deletions(-) diff --git a/dfhack.init-example b/dfhack.init-example index fb846a47f..82210a2a6 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -202,9 +202,6 @@ tweak hotkey-clear # Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving tweak embark-profile-name -# dwarf mode FPS counter that does not jump to FPS_CAP when paused -tweak pausing-fps-counter - # Misc. UI tweaks tweak block-labors # Prevents labors that can't be used from being toggled tweak burrow-name-cancel