diff --git a/docs/Compile.rst b/docs/Compile.rst
index fd8079861..f30775a03 100644
--- a/docs/Compile.rst
+++ b/docs/Compile.rst
@@ -152,6 +152,12 @@ Before you can build anything, you'll also need ``cmake``. It is advisable to
also get ``ccmake`` on distributions that split the cmake package into multiple
parts.
+You will need pthread; most systems should have this already. Note that older
+CMake versions may have trouble detecting pthread, so if you run into
+pthread-related errors and pthread is installed, you may need to upgrade CMake,
+either by downloading it from `cmake.org `_ or
+through your package manager, if possible.
+
You also need zlib, libsdl (1.2, not sdl2, like DF), perl, and the XML::LibXML
and XML::LibXSLT perl packages (for the code generation parts). You should be
able to find them in your distro repositories.
diff --git a/docs/changelog.txt b/docs/changelog.txt
index 17c766f75..ef2fc825d 100644
--- a/docs/changelog.txt
+++ b/docs/changelog.txt
@@ -37,6 +37,15 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
================================================================================
# Future
+## Misc Improvements
+- `RemoteFortressReader`:
+ - added basic framework for controlling and reading the menus in DF, currently only supports the building menu.
+ - added support for reading item raws.
+ - added a check for wheather or not the game is currently saving or loading, for utilities to check if it's safe to read from DF.
+ - guestimate unit facing direction, and position within tiles.
+ - get unit age.
+ - get unit wounds.
+
## Internals
- Fixed some OpenGL build issues with `stonesense`
diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h
index 0c41bf7f6..f33abf4e0 100644
--- a/library/include/modules/Maps.h
+++ b/library/include/modules/Maps.h
@@ -36,6 +36,7 @@ distribution.
#include "BitArray.h"
#include "modules/Materials.h"
+#include "df/biome_type.h"
#include "df/block_flags.h"
#include "df/feature_type.h"
#include "df/flow_type.h"
@@ -333,6 +334,12 @@ extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, d
DFHACK_EXPORT bool canWalkBetween(df::coord pos1, df::coord pos2);
DFHACK_EXPORT bool canStepBetween(df::coord pos1, df::coord pos2);
+
+DFHACK_EXPORT df::enums::biome_type::biome_type GetBiomeType(int world_coord_x, int world_coord_y);
+DFHACK_EXPORT df::enums::biome_type::biome_type GetBiomeTypeWithRef(int world_coord_x, int world_coord_y, int world_ref_y_coord);
+
}
+
+
}
#endif
diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp
index 54f314db8..361ada0f1 100644
--- a/library/modules/Maps.cpp
+++ b/library/modules/Maps.cpp
@@ -46,6 +46,7 @@ using namespace std;
#include "modules/MapCache.h"
#include "modules/Maps.h"
+#include "df/biome_type.h"
#include "df/block_burrow.h"
#include "df/block_burrow_link.h"
#include "df/block_square_event_grassst.h"
@@ -711,3 +712,393 @@ bool Maps::canStepBetween(df::coord pos1, df::coord pos2)
return false;
}
+
+/* The code below is a heavily refactored version of code found at
+ https://github.com/ragundo/exportmaps/blob/master/cpp/df_utils/biome_type.cpp.
+*/
+
+/*
+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.
+*/
+
+namespace {
+ //----------------------------------------------------------------------------//
+ // Utility function
+ //
+ //----------------------------------------------------------------------------//
+ std::pair check_tropicality(df::region_map_entry& region,
+ int y_pos
+ )
+ {
+ int flip_latitude = df::global::world->world_data->flip_latitude;
+
+ bool is_possible_tropical_area_by_latitude = false;
+ bool is_tropical_area_by_latitude = false;
+
+ if (flip_latitude == -1) // NO POLES
+ {
+ // If there're no poles, tropical area is determined by temperature
+ is_possible_tropical_area_by_latitude = region.temperature >= 75;
+ is_tropical_area_by_latitude = region.temperature >= 85;
+ }
+
+ else
+ {
+ int v6 = 0;
+
+ df::world_data* wdata = df::global::world->world_data;
+
+ if (flip_latitude == 0) // NORTH POLE ONLY
+ {
+ v6 = y_pos;
+ }
+
+ else if (flip_latitude == 1) // SOUTH_POLE ONLY
+ {
+ v6 = df::global::world->world_data->world_height - y_pos - 1;
+ }
+
+ else if (flip_latitude == 2) // BOTH POLES
+ {
+ 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;
+
+ 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
+ //
+ // return some unknow parameter as a percentage
+ //----------------------------------------------------------------------------//
+ int get_region_parameter(int y,
+ int x
+ )
+ {
+ 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];
+ int flip_latitude = df::global::world->world_data->flip_latitude;
+ int rainfall = region.rainfall;
+ int result;
+ int y_pos = y;
+ 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;
+ }
+
+ return 100;
+ }
+}
+
+
+/*****************************************************************************
+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.
+*****************************************************************************/
+df::enums::biome_type::biome_type Maps::GetBiomeTypeWithRef(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;
+
+ int parameter = get_region_parameter(world_coord_y, world_coord_x);
+
+ // Begin the discrimination
+ if (region.flags.is_set(df::region_map_entry_flags::is_lake)) // is it a lake?
+ {
+ // 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 < 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 if (region.salinity < 66)
+ 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
+ }
+
+ // 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?
+ {
+ 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
+ }
+
+ // 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 < 10)
+ {
+ if (region.drainage < 33)
+ return df::enums::biome_type::biome_type::DESERT_SAND; // 26
+ else if (region.drainage < 66)
+ return df::enums::biome_type::biome_type::DESERT_ROCK; // 25
+ else // drainage >= 66
+ return df::enums::biome_type::biome_type::DESERT_BADLAND; // 24
+ }
+ else if (region.vegetation < 20)
+ {
+ if ((is_possible_tropical_area_by_latitude && (parameter < 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;
+ }
+ else if (region.vegetation < 33)
+ {
+ // vegetation between 20 and 32
+ if ((is_possible_tropical_area_by_latitude && (parameter <= 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;
+ }
+ else if (region.vegetation < 66)
+ {
+ if (region.drainage >= 33)
+ {
+ if (is_possible_tropical_area_by_latitude && (parameter < 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
+ }
+ // drainage < 33
+ {
+ if (region.salinity < 66)
+ {
+ if ((is_possible_tropical_area_by_latitude && (parameter < 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 && (parameter < 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
+ }
+ }
+ }
+
+ // Not a lake, mountain, ocean, glacier, tundra, desert, grassland or savanna
+ // vegetation >= 66
+ else if (region.drainage >= 33)
+ {
+ // 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
+ }
+ }
+ }
+
+ // Not a lake, mountain, ocean, glacier, tundra, desert, grassland, savanna or forest
+ // vegetation >= 66, drainage < 33
+
+ else 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 if (region.salinity >= 66)
+ // elevation between 100 and 149, vegetation >= 66, drainage < 33, not tropical area
+ return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_SALTWATER; // 4
+ else
+ return df::enums::biome_type::biome_type::SWAMP_TEMPERATE_FRESHWATER; // 3
+}
+
+/*****************************************************************************
+Module main function.
+Return the biome type, given a position coordinate expressed in world_tiles
+*****************************************************************************/
+df::enums::biome_type::biome_type Maps::GetBiomeType(int world_coord_x, int world_coord_y)
+{
+ return Maps::GetBiomeTypeWithRef(world_coord_x, world_coord_y, world_coord_y);
+}
+
diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake
index 1adcbe62f..45504c331 100644
--- a/plugins/Plugins.cmake
+++ b/plugins/Plugins.cmake
@@ -111,6 +111,7 @@ macro(dfhack_plugin)
set_source_files_properties( ${PLUGIN_PROTO_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE )
list(APPEND PLUGIN_SOURCES ${PLUGIN_PROTO_HDRS})
list(APPEND PLUGIN_SOURCES ${PLUGIN_PROTO_SRCS})
+ list(APPEND PLUGIN_SOURCES ${PLUGIN_PROTOS})
if(UNIX)
set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} -include Export.h")
diff --git a/plugins/embark-assistant/CMakeLists.txt b/plugins/embark-assistant/CMakeLists.txt
index 4fe95b8fd..cc66e59e8 100644
--- a/plugins/embark-assistant/CMakeLists.txt
+++ b/plugins/embark-assistant/CMakeLists.txt
@@ -1,7 +1,6 @@
project(embark-assistant)
# A list of source files
set(PROJECT_SRCS
- biome_type.cpp
embark-assistant.cpp
finder_ui.cpp
help_ui.cpp
@@ -12,7 +11,6 @@ set(PROJECT_SRCS
)
# A list of headers
set(PROJECT_HDRS
- biome_type.h
defs.h
embark-assistant.h
finder_ui.h
diff --git a/plugins/embark-assistant/biome_type.cpp b/plugins/embark-assistant/biome_type.cpp
deleted file mode 100644
index 01bc0044a..000000000
--- a/plugins/embark-assistant/biome_type.cpp
+++ /dev/null
@@ -1,754 +0,0 @@
-/* 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 "DataDefs.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
deleted file mode 100644
index 9ea562749..000000000
--- a/plugins/embark-assistant/biome_type.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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/survey.cpp b/plugins/embark-assistant/survey.cpp
index f19f3cd4a..68cd3597f 100644
--- a/plugins/embark-assistant/survey.cpp
+++ b/plugins/embark-assistant/survey.cpp
@@ -8,6 +8,7 @@
#include
#include "modules/Materials.h"
+#include "modules/Maps.h"
#include "DataDefs.h"
#include "df/builtin_mats.h"
@@ -55,7 +56,6 @@
#include "df/world_site_type.h"
#include "df/world_underground_region.h"
-#include "biome_type.h"
#include "defs.h"
#include "survey.h"
@@ -586,7 +586,7 @@ void embark_assist::survey::high_level_world_survey(embark_assist::defs::geo_dat
offset_count++;
results.biome_index[l] = world_data->region_map[adjusted.x][adjusted.y].region_id;
- results.biome[l] = get_biome_type(adjusted.x, adjusted.y, k);
+ results.biome[l] = DFHack::Maps::GetBiomeTypeWithRef(adjusted.x, adjusted.y, k);
temperature = world_data->region_map[adjusted.x][adjusted.y].temperature;
negative = temperature < 0;
diff --git a/plugins/proto/DwarfControl.proto b/plugins/proto/DwarfControl.proto
new file mode 100644
index 000000000..9bd63b8d3
--- /dev/null
+++ b/plugins/proto/DwarfControl.proto
@@ -0,0 +1,96 @@
+syntax = "proto2";
+package DwarfControl;
+
+//Attempts to provide a complete framework for reading everything from a fortress needed for vizualization
+option optimize_for = LITE_RUNTIME;
+
+// Plugin: RemoteFortressReader
+
+import "ui_sidebar_mode.proto";
+import "RemoteFortressReader.proto";
+
+// RPC GetSideMenu : EmptyMessage -> SidebarState
+// RPC SetSideMenu : SidebarCommand -> EmptyMessage
+
+
+enum BuildCategory
+{
+ NotCategory = 0;
+ SiegeEngines = 1;
+ Traps = 2;
+ Workshops = 3;
+ Furnaces = 4;
+ Constructions = 5;
+ MachineComponents = 6;
+ Track = 7;
+}
+
+enum MenuAction
+{
+ MenuNone = 0;
+ MenuSelect = 1;
+ MenuCancel = 2;
+ MenuSelectAll = 3;
+}
+
+enum BuildSelectorStage
+{
+ StageNoMat = 0;
+ StagePlace = 1;
+ StageItemSelect = 2;
+}
+
+message SidebarState
+{
+ optional proto.enums.ui_sidebar_mode.ui_sidebar_mode mode = 1;
+ repeated MenuItem menu_items = 2;
+ optional BuildSelector build_selector = 3;
+}
+
+message MenuItem
+{
+ optional RemoteFortressReader.BuildingType building_type = 1;
+ optional int32 existing_count = 2;
+ optional BuildCategory build_category = 3;
+}
+
+message SidebarCommand
+{
+ optional proto.enums.ui_sidebar_mode.ui_sidebar_mode mode = 1;
+ optional int32 menu_index = 2;
+ optional MenuAction action = 3;
+ optional RemoteFortressReader.Coord selection_coord = 4;
+}
+
+message BuiildReqChoice
+{
+ optional int32 distance = 1;
+ optional string name = 2;
+ optional int32 num_candidates = 3;
+ optional int32 used_count = 4;
+}
+
+message BuildItemReq
+{
+ //Put filter here = 1
+ optional int32 count_required = 2;
+ optional int32 count_max = 3;
+ optional int32 count_provided = 4;
+}
+
+message BuildSelector
+{
+ optional RemoteFortressReader.BuildingType building_type = 1;
+ optional BuildSelectorStage stage = 2;
+ repeated BuiildReqChoice choices = 3;
+ optional int32 sel_index = 4;
+ repeated BuildItemReq requirements = 5;
+ optional int32 req_index = 6;
+ repeated string errors = 7;
+ optional int32 radius_x_low = 8;
+ optional int32 radius_y_low = 9;
+ optional int32 radius_x_high = 10;
+ optional int32 radius_y_high = 11;
+ optional RemoteFortressReader.Coord cursor = 12;
+ repeated int32 tiles = 13;
+}
diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto
index af971d55d..ed7557a2f 100644
--- a/plugins/proto/RemoteFortressReader.proto
+++ b/plugins/proto/RemoteFortressReader.proto
@@ -42,6 +42,7 @@ import "ItemdefInstrument.proto";
// RPC MovementSelectCommand : IntMessage -> EmptyMessage
// RPC MiscMoveCommand : MiscMoveParams -> EmptyMessage
// RPC GetLanguage : EmptyMessage -> Language
+// RPC GetGameValidity : EmptyMessage -> SingleBool
//We use shapes, etc, because the actual tiletypes may differ between DF versions.
enum TiletypeShape
@@ -201,6 +202,14 @@ enum InventoryMode
Strapped = 10;
}
+enum ArmorLayer
+{
+ LAYER_UNDER = 0;
+ LAYER_OVER = 1;
+ LAYER_ARMOR = 2;
+ LAYER_COVER = 3;
+}
+
message Coord
{
optional int32 x = 1;
@@ -320,6 +329,31 @@ message Item
optional ArtImage image = 18;
}
+message PlantTile
+{
+ optional bool trunk = 1;
+ optional bool connection_east = 2;
+ optional bool connection_south = 3;
+ optional bool connection_west = 4;
+ optional bool connection_north = 5;
+ optional bool branches = 6;
+ optional bool twigs = 7;
+ optional TiletypeSpecial tile_type = 8;
+}
+
+message TreeInfo
+{
+ optional Coord size = 1;
+ repeated PlantTile tiles = 2;
+}
+
+message PlantInstance
+{
+ optional int32 plant_type = 1;
+ optional Coord pos = 2;
+ optional TreeInfo tree_info = 3;
+}
+
message MapBlock
{
required int32 map_x = 1;
@@ -371,6 +405,9 @@ message MaterialDefinition{
optional string name = 3;
optional ColorDefinition state_color = 4; //Simplifying colors to assume room temperature.
optional ItemdefInstrument.InstrumentDef instrument = 5;
+ optional int32 up_step = 6;
+ optional int32 down_step = 7;
+ optional ArmorLayer layer = 8;
}
message BuildingType
@@ -426,6 +463,20 @@ message InventoryItem
{
optional InventoryMode mode = 1;
optional Item item = 2;
+ optional int32 body_part_id = 3;
+}
+
+message WoundPart
+{
+ optional int32 global_layer_idx = 1;
+ optional int32 body_part_id = 2;
+ optional int32 layer_idx = 3;
+}
+
+message UnitWound
+{
+ repeated WoundPart parts = 1;
+ optional bool severed_part = 2;
}
message UnitDefinition
@@ -453,6 +504,9 @@ message UnitDefinition
optional float subpos_x = 21;
optional float subpos_y = 22;
optional float subpos_z = 23;
+ optional Coord facing = 24;
+ optional int32 age = 25;
+ repeated UnitWound wounds = 26;
}
message UnitList
@@ -787,6 +841,7 @@ message CreatureRaw
optional int32 adultsize = 9;
repeated CasteRaw caste = 10;
repeated TissueRaw tissues = 11;
+ repeated bool flags = 12;
}
message CreatureRawList
diff --git a/plugins/proto/ui_sidebar_mode.proto b/plugins/proto/ui_sidebar_mode.proto
new file mode 100644
index 000000000..b07bb1baa
--- /dev/null
+++ b/plugins/proto/ui_sidebar_mode.proto
@@ -0,0 +1,63 @@
+package proto.enums.ui_sidebar_mode;
+
+//Attempts to provide a complete framework for reading everything from a fortress needed for vizualization
+option optimize_for = LITE_RUNTIME;
+
+enum ui_sidebar_mode
+{
+ Default = 0;
+ Squads = 1;
+ DesignateMine = 2;
+ DesignateRemoveRamps = 3;
+ DesignateUpStair = 4;
+ DesignateDownStair = 5;
+ DesignateUpDownStair = 6;
+ DesignateUpRamp = 7;
+ DesignateChannel = 8;
+ DesignateGatherPlants = 9;
+ DesignateRemoveDesignation = 10;
+ DesignateSmooth = 11;
+ DesignateCarveTrack = 12;
+ DesignateEngrave = 13;
+ DesignateCarveFortification = 14;
+ Stockpiles = 15;
+ Build = 16;
+ QueryBuilding = 17;
+ Orders = 18;
+ OrdersForbid = 19;
+ OrdersRefuse = 20;
+ OrdersWorkshop = 21;
+ OrdersZone = 22;
+ BuildingItems = 23;
+ ViewUnits = 24;
+ LookAround = 25;
+ DesignateItemsClaim = 26;
+ DesignateItemsForbid = 27;
+ DesignateItemsMelt = 28;
+ DesignateItemsUnmelt = 29;
+ DesignateItemsDump = 30;
+ DesignateItemsUndump = 31;
+ DesignateItemsHide = 32;
+ DesignateItemsUnhide = 33;
+ DesignateChopTrees = 34;
+ DesignateToggleEngravings = 35;
+ DesignateToggleMarker = 36;
+ Hotkeys = 37;
+ DesignateTrafficHigh = 38;
+ DesignateTrafficNormal = 39;
+ DesignateTrafficLow = 40;
+ DesignateTrafficRestricted = 41;
+ Zones = 42;
+ ZonesPenInfo = 43;
+ ZonesPitInfo = 44;
+ ZonesHospitalInfo = 45;
+ ZonesGatherInfo = 46;
+ DesignateRemoveConstruction = 47;
+ DepotAccess = 48;
+ NotesPoints = 49;
+ NotesRoutes = 50;
+ Burrows = 51;
+ Hauling = 52;
+ ArenaWeather = 53;
+ ArenaTrees = 54;
+}
\ No newline at end of file
diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt
index f8694145a..55525bc21 100644
--- a/plugins/remotefortressreader/CMakeLists.txt
+++ b/plugins/remotefortressreader/CMakeLists.txt
@@ -4,27 +4,39 @@ set(PROJECT_SRCS
remotefortressreader.cpp
adventure_control.cpp
building_reader.cpp
+ dwarf_control.cpp
item_reader.cpp
)
# A list of headers
set(PROJECT_HDRS
adventure_control.h
building_reader.h
+ dwarf_control.h
item_reader.h
df_version_int.h
)
# proto files to include.
set(PROJECT_PROTO
- ${CMAKE_CURRENT_SOURCE_DIR}/../proto/RemoteFortressReader.pb.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/../proto/AdventureControl.pb.cc
- ${CMAKE_CURRENT_SOURCE_DIR}/../proto/ItemdefInstrument.pb.cc
+ RemoteFortressReader
+ AdventureControl
+ ItemdefInstrument
+ DwarfControl
+ ui_sidebar_mode
)
-set_source_files_properties(${PROJECT_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
-set_source_files_properties(${PROJECT_PROTO} PROPERTIES GENERATED TRUE)
+set(PLUGIN_PROTOS)
+foreach(pbuf ${PROJECT_PROTO})
+ list(APPEND PLUGIN_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/../proto/${pbuf}.proto)
+endforeach()
+
+string(REPLACE ".proto" ".pb.cc" PLUGIN_PROTO_SRCS "${PLUGIN_PROTOS}")
+string(REPLACE ".proto" ".pb.h" PLUGIN_PROTO_HDRS "${PLUGIN_PROTOS}")
+set_source_files_properties(${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS} PROPERTIES GENERATED TRUE)
+
+set_source_files_properties( ${PROJECT_HDRS} ${PLUGIN_PROTO_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};${PROJECT_PROTO})
+list(APPEND PROJECT_SRCS ${PROJECT_HDRS} ${PLUGIN_PROTOS} ${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS})
if(UNIX AND NOT APPLE)
set(PROJECT_LIBS ${PROJECT_LIBS} SDL)
diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp
index 5a0dd5c96..2d396980a 100644
--- a/plugins/remotefortressreader/building_reader.cpp
+++ b/plugins/remotefortressreader/building_reader.cpp
@@ -78,7 +78,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(-1);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt));
-
+ bld->set_name(ENUM_ATTR_STR(building_type, name, bt));
switch (bt)
{
case df::enums::building_type::NONE:
@@ -101,6 +101,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(furnace_type, st));
+ bld->set_name(ENUM_ATTR_STR(furnace_type, name, st));
if (st == furnace_type::Custom)
{
@@ -128,7 +129,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(shop_type, st));
-
+ bld->set_name(ENUM_KEY_STR(shop_type, st));
}
break;
case df::enums::building_type::Door:
@@ -149,6 +150,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(workshop_type, st));
+ bld->set_name(ENUM_ATTR_STR(workshop_type, name, st));
if (st == workshop_type::Custom)
{
@@ -190,7 +192,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(siegeengine_type, st));
-
+ bld->set_name(ENUM_KEY_STR(siegeengine_type, st));
}
break;
case df::enums::building_type::Trap:
@@ -201,7 +203,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(trap_type, st));
-
+ bld->set_name(ENUM_KEY_STR(trap_type, st));
}
break;
case df::enums::building_type::AnimalTrap:
@@ -224,7 +226,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(civzone_type, st));
-
+ bld->set_name(ENUM_KEY_STR(civzone_type, st));
}
break;
case df::enums::building_type::Weapon:
@@ -241,7 +243,7 @@ DFHack::command_result GetBuildingDefList(DFHack::color_ostream &stream, const D
bld->mutable_building_type()->set_building_subtype(st);
bld->mutable_building_type()->set_building_custom(-1);
bld->set_id(ENUM_KEY_STR(building_type, bt) + "/" + ENUM_KEY_STR(construction_type, st));
-
+ bld->set_name(ENUM_KEY_STR(construction_type, st));
}
break;
case df::enums::building_type::Hatch:
diff --git a/plugins/remotefortressreader/df_version_int.h b/plugins/remotefortressreader/df_version_int.h
index 35c9ed851..d83fa7548 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 44002
+#define DF_VERSION_INT 44012
diff --git a/plugins/remotefortressreader/dwarf_control.cpp b/plugins/remotefortressreader/dwarf_control.cpp
new file mode 100644
index 000000000..98b51175f
--- /dev/null
+++ b/plugins/remotefortressreader/dwarf_control.cpp
@@ -0,0 +1,493 @@
+#include "dwarf_control.h"
+#include "DataDefs.h"
+#include "df_version_int.h"
+
+#include "df/build_req_choice_genst.h"
+#include "df/build_req_choice_specst.h"
+#include "df/build_req_choicest.h"
+#include "df/building_def.h"
+#include "df/building_def_furnacest.h"
+#include "df/building_def_workshopst.h"
+#include "df/job.h"
+#include "df/job_list_link.h"
+#include "df/interface_button_construction_building_selectorst.h"
+#include "df/interface_button_construction_category_selectorst.h"
+#include "df/ui.h"
+#include "df/ui_build_selector.h"
+#include "df/ui_sidebar_menus.h"
+#include "df/viewscreen.h"
+#include "df/world.h"
+
+#include "modules/Buildings.h"
+#include "modules/Gui.h"
+#include "modules/Job.h"
+#include "modules/MapCache.h"
+#include "modules/Maps.h"
+#include "modules/World.h"
+
+#include "MiscUtils.h"
+
+#include
+
+using namespace DFHack;
+using namespace RemoteFortressReader;
+using namespace df::enums;
+using namespace Gui;
+using namespace df::global;
+
+extern std::queue keyQueue;
+
+void GetBuildingSize(
+ int16_t type,
+ int16_t subtype,
+ int16_t custom,
+ int16_t &rad_x_low,
+ int16_t &rad_y_low,
+ int16_t &rad_x_high,
+ int16_t &rad_y_high
+)
+{
+ rad_x_low = 0;
+ rad_y_low = 0;
+ rad_x_high = 0;
+ rad_y_high = 0;
+ df::building_def* customBuilding = 0;
+ switch (type)
+ {
+ case building_type::FarmPlot:
+ case building_type::Bridge:
+ case building_type::RoadDirt:
+ case building_type::RoadPaved:
+ case building_type::Stockpile:
+ case building_type::Civzone:
+ case building_type::ScrewPump:
+ case building_type::Construction:
+ case building_type::AxleHorizontal:
+ case building_type::WaterWheel:
+ case building_type::Rollers:
+ {
+ bool widthOdd = world->building_width % 2;
+ rad_x_low = world->building_width / 2;
+ if(widthOdd)
+ rad_x_high = world->building_width / 2;
+ else
+ rad_x_high = (world->building_width / 2) - 1;
+ bool heightOdd = world->building_width % 2;
+ rad_y_low = world->building_height / 2;
+ if (widthOdd)
+ rad_y_high = world->building_height / 2;
+ else
+ rad_y_high = (world->building_height / 2) - 1;
+ }
+ return;
+ case building_type::Furnace:
+ if (subtype != furnace_type::Custom)
+ {
+ rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
+ return;
+ }
+ customBuilding = world->raws.buildings.furnaces[custom];
+ break;
+ case building_type::TradeDepot:
+ case building_type::Shop:
+ rad_x_low = rad_y_low = rad_x_high = rad_y_high = 2;
+ return;
+ case building_type::Workshop:
+ switch (subtype)
+ {
+ case workshop_type::Carpenters:
+ case workshop_type::Farmers:
+ case workshop_type::Masons:
+ case workshop_type::Craftsdwarfs:
+ case workshop_type::Jewelers:
+ case workshop_type::MetalsmithsForge:
+ case workshop_type::MagmaForge:
+ case workshop_type::Bowyers:
+ case workshop_type::Mechanics:
+ case workshop_type::Butchers:
+ case workshop_type::Leatherworks:
+ case workshop_type::Tanners:
+ case workshop_type::Clothiers:
+ case workshop_type::Fishery:
+ case workshop_type::Still:
+ case workshop_type::Loom:
+ case workshop_type::Kitchen:
+ case workshop_type::Ashery:
+ case workshop_type::Dyers:
+ rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
+ return;
+ case workshop_type::Siege:
+ case workshop_type::Kennels:
+ rad_x_low = rad_y_low = rad_x_high = rad_y_high = 2;
+ return;
+ case workshop_type::Custom:
+ customBuilding = world->raws.buildings.workshops[custom];
+ break;
+ default:
+ return;
+ }
+ break;
+ case building_type::SiegeEngine:
+ case building_type::Wagon:
+ case building_type::Windmill:
+ rad_x_low = rad_y_low = rad_x_high = rad_y_high = 1;
+ return;
+ default:
+ return;
+ }
+ if (customBuilding)
+ {
+ rad_x_low = customBuilding->workloc_x;
+ rad_y_low = customBuilding->workloc_y;
+ rad_x_high = customBuilding->dim_x - rad_x_low - 1;
+ rad_y_high = customBuilding->dim_y - rad_y_low - 1;
+ return;
+ }
+}
+
+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);
+
+#if DF_VERSION_INT >= 43005
+ //remove and job postings related.
+ for (df::job_list_link * listing = &(df::global::world->jobs.list); listing != NULL; listing = listing->next)
+ {
+ if (listing->item == NULL)
+ continue;
+ auto type = listing->item->job_type;
+ switch (type)
+ {
+ case job_type::CarveFortification:
+ case job_type::DetailWall:
+ case job_type::DetailFloor:
+ case job_type::Dig:
+ case job_type::CarveUpwardStaircase:
+ case job_type::CarveDownwardStaircase:
+ case job_type::CarveUpDownStaircase:
+ case job_type::CarveRamp:
+ case job_type::DigChannel:
+ case job_type::FellTree:
+ case job_type::GatherPlants:
+ case job_type::RemoveConstruction:
+ case 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;
+}
+
+command_result SetPauseState(color_ostream &stream, const SingleBool *in)
+{
+ DFHack::World::SetPauseState(in->value());
+ return CR_OK;
+}
+
+void CopyBuildMenu(DwarfControl::SidebarState * out)
+{
+ auto menus = df::global::ui_sidebar_menus;
+ auto build_selector = df::global::ui_build_selector;
+ if (build_selector->building_type == -1)
+ for (size_t i = 0; i < menus->building.choices_visible.size(); i++)
+ {
+ auto menu_item = menus->building.choices_visible[i];
+ auto send_item = out->add_menu_items();
+ STRICT_VIRTUAL_CAST_VAR(building, df::interface_button_construction_building_selectorst, menu_item);
+ if (building)
+ {
+ auto send_bld = send_item->mutable_building_type();
+ send_bld->set_building_type(building->building_type);
+ send_bld->set_building_subtype(building->building_subtype);
+ send_bld->set_building_custom(building->custom_type);
+ send_item->set_existing_count(building->existing_count);
+ }
+ STRICT_VIRTUAL_CAST_VAR(sub_category, df::interface_button_construction_category_selectorst, menu_item);
+ if (sub_category)
+ {
+ send_item->set_build_category((DwarfControl::BuildCategory)sub_category->category_id);
+ }
+ }
+ else
+ {
+ auto send_selector = out->mutable_build_selector();
+ auto send_bld = send_selector->mutable_building_type();
+ send_bld->set_building_type(build_selector->building_type);
+ send_bld->set_building_subtype(build_selector->building_subtype);
+ send_bld->set_building_custom(build_selector->custom_type);
+ send_selector->set_stage((DwarfControl::BuildSelectorStage)build_selector->stage);
+ for (size_t i = 0; i < build_selector->errors.size(); i++)
+ {
+ if (build_selector->errors[i])
+ send_selector->add_errors(*build_selector->errors[i]);
+ }
+ for (size_t i = 0; i < build_selector->choices.size(); i++)
+ {
+ auto choice = build_selector->choices[i];
+ auto send_choice = send_selector->add_choices();
+ send_choice->set_distance(choice->distance);
+ std::string name;
+ choice->getName(&name);
+ send_choice->set_name(name);
+ send_choice->set_num_candidates(choice->getNumCandidates());
+ send_choice->set_used_count(choice->getUsedCount());
+ }
+ int16_t x_low, y_low, x_high, y_high;
+ GetBuildingSize(build_selector->building_type, build_selector->building_subtype, build_selector->custom_type, x_low, y_low, x_high, y_high);
+ send_selector->set_radius_x_low(x_low);
+ send_selector->set_radius_y_low(y_low);
+ send_selector->set_radius_x_high(x_high);
+ send_selector->set_radius_y_high(y_high);
+ if (build_selector->stage >= 1)
+ {
+ auto send_cursor = send_selector->mutable_cursor();
+ send_cursor->set_x(cursor->x);
+ send_cursor->set_y(cursor->y);
+ send_cursor->set_z(cursor->z);
+ }
+
+ for (int y = 0; y < (y_low + y_high + 1); y++)
+ for (int x = 0; x < (x_low + x_high + 1); x++)
+ {
+ send_selector->add_tiles(build_selector->tiles[x][y]);
+ }
+ }
+}
+
+command_result GetSideMenu(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, DwarfControl::SidebarState *out)
+{
+ auto ui = df::global::ui;
+ out->set_mode((proto::enums::ui_sidebar_mode::ui_sidebar_mode)ui->main.mode);
+ auto mode = ui->main.mode;
+ switch (mode)
+ {
+ case ui_sidebar_mode::Default:
+ break;
+ case ui_sidebar_mode::Squads:
+ break;
+ case ui_sidebar_mode::DesignateMine:
+ break;
+ case ui_sidebar_mode::DesignateRemoveRamps:
+ break;
+ case ui_sidebar_mode::DesignateUpStair:
+ break;
+ case ui_sidebar_mode::DesignateDownStair:
+ break;
+ case ui_sidebar_mode::DesignateUpDownStair:
+ break;
+ case ui_sidebar_mode::DesignateUpRamp:
+ break;
+ case ui_sidebar_mode::DesignateChannel:
+ break;
+ case ui_sidebar_mode::DesignateGatherPlants:
+ break;
+ case ui_sidebar_mode::DesignateRemoveDesignation:
+ break;
+ case ui_sidebar_mode::DesignateSmooth:
+ break;
+ case ui_sidebar_mode::DesignateCarveTrack:
+ break;
+ case ui_sidebar_mode::DesignateEngrave:
+ break;
+ case ui_sidebar_mode::DesignateCarveFortification:
+ break;
+ case ui_sidebar_mode::Stockpiles:
+ break;
+ case ui_sidebar_mode::Build:
+ CopyBuildMenu(out);
+ break;
+ case ui_sidebar_mode::QueryBuilding:
+ break;
+ case ui_sidebar_mode::Orders:
+ break;
+ case ui_sidebar_mode::OrdersForbid:
+ break;
+ case ui_sidebar_mode::OrdersRefuse:
+ break;
+ case ui_sidebar_mode::OrdersWorkshop:
+ break;
+ case ui_sidebar_mode::OrdersZone:
+ break;
+ case ui_sidebar_mode::BuildingItems:
+ break;
+ case ui_sidebar_mode::ViewUnits:
+ break;
+ case ui_sidebar_mode::LookAround:
+ break;
+ case ui_sidebar_mode::DesignateItemsClaim:
+ break;
+ case ui_sidebar_mode::DesignateItemsForbid:
+ break;
+ case ui_sidebar_mode::DesignateItemsMelt:
+ break;
+ case ui_sidebar_mode::DesignateItemsUnmelt:
+ break;
+ case ui_sidebar_mode::DesignateItemsDump:
+ break;
+ case ui_sidebar_mode::DesignateItemsUndump:
+ break;
+ case ui_sidebar_mode::DesignateItemsHide:
+ break;
+ case ui_sidebar_mode::DesignateItemsUnhide:
+ break;
+ case ui_sidebar_mode::DesignateChopTrees:
+ break;
+ case ui_sidebar_mode::DesignateToggleEngravings:
+ break;
+ case ui_sidebar_mode::DesignateToggleMarker:
+ break;
+ case ui_sidebar_mode::Hotkeys:
+ break;
+ case ui_sidebar_mode::DesignateTrafficHigh:
+ break;
+ case ui_sidebar_mode::DesignateTrafficNormal:
+ break;
+ case ui_sidebar_mode::DesignateTrafficLow:
+ break;
+ case ui_sidebar_mode::DesignateTrafficRestricted:
+ break;
+ case ui_sidebar_mode::Zones:
+ break;
+ case ui_sidebar_mode::ZonesPenInfo:
+ break;
+ case ui_sidebar_mode::ZonesPitInfo:
+ break;
+ case ui_sidebar_mode::ZonesHospitalInfo:
+ break;
+ case ui_sidebar_mode::ZonesGatherInfo:
+ break;
+ case ui_sidebar_mode::DesignateRemoveConstruction:
+ break;
+ case ui_sidebar_mode::DepotAccess:
+ break;
+ case ui_sidebar_mode::NotesPoints:
+ break;
+ case ui_sidebar_mode::NotesRoutes:
+ break;
+ case ui_sidebar_mode::Burrows:
+ break;
+ case ui_sidebar_mode::Hauling:
+ break;
+ case ui_sidebar_mode::ArenaWeather:
+ break;
+ case ui_sidebar_mode::ArenaTrees:
+ break;
+ default:
+ break;
+ }
+ return CR_OK;
+}
+
+command_result SetSideMenu(DFHack::color_ostream &stream, const DwarfControl::SidebarCommand *in)
+{
+ auto ui = df::global::ui;
+ if (in->has_mode())
+ {
+ ui_sidebar_mode::ui_sidebar_mode set_mode = (ui_sidebar_mode::ui_sidebar_mode)in->mode();
+ if (ui->main.mode != set_mode)
+ {
+ ui->main.mode = ui_sidebar_mode::Default;
+ switch (set_mode)
+ {
+ case ui_sidebar_mode::Build:
+ keyQueue.push(interface_key::D_BUILDING);
+ break;
+ default:
+ ui->main.mode = set_mode;
+ break;
+ }
+ }
+ }
+ switch (ui->main.mode)
+ {
+ case ui_sidebar_mode::Build:
+ if (in->has_action())
+ {
+ int index = 0;
+ if (in->has_menu_index())
+ index = in->menu_index();
+ if(ui_build_selector->building_type == -1)
+ df::global::ui_sidebar_menus->building.cursor = index;
+ if (ui_build_selector->stage == 2)
+ {
+ ui_build_selector->sel_index = index;
+ }
+ }
+ if (ui_build_selector->stage == 1)
+ {
+ if (in->has_selection_coord())
+ {
+ df::global::cursor->x = in->selection_coord().x();
+ df::global::cursor->y = in->selection_coord().y();
+ df::global::cursor->z = in->selection_coord().z();
+ getCurViewscreen()->feed_key(interface_key::CURSOR_LEFT);
+ getCurViewscreen()->feed_key(interface_key::CURSOR_RIGHT);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ auto viewScreen = getCurViewscreen();
+ if (in->has_action())
+ {
+ switch (in->action())
+ {
+ case DwarfControl::MenuSelect:
+ keyQueue.push(interface_key::SELECT);
+ break;
+ case DwarfControl::MenuCancel:
+ keyQueue.push(interface_key::LEAVESCREEN);
+ break;
+ default:
+ break;
+ }
+ }
+ return CR_OK;
+}
diff --git a/plugins/remotefortressreader/dwarf_control.h b/plugins/remotefortressreader/dwarf_control.h
new file mode 100644
index 000000000..b16a4365d
--- /dev/null
+++ b/plugins/remotefortressreader/dwarf_control.h
@@ -0,0 +1,15 @@
+#ifndef DWARF_CONTROL_H
+#define DWARF_CONTROL_H
+
+#include "RemoteClient.h"
+#include "RemoteFortressReader.pb.h"
+#include "DwarfControl.pb.h"
+
+DFHack::command_result SendDigCommand(DFHack::color_ostream &stream, const RemoteFortressReader::DigCommand *in);
+DFHack::command_result SetPauseState(DFHack::color_ostream &stream, const RemoteFortressReader::SingleBool *in);
+DFHack::command_result GetSideMenu(DFHack::color_ostream &stream, const dfproto::EmptyMessage *in, DwarfControl::SidebarState *out);
+DFHack::command_result SetSideMenu(DFHack::color_ostream &stream, const DwarfControl::SidebarCommand *in);
+
+#endif // !DWARF_CONTROL_H
+
+
diff --git a/plugins/remotefortressreader/item_reader.cpp b/plugins/remotefortressreader/item_reader.cpp
index 3884d269f..620e06310 100644
--- a/plugins/remotefortressreader/item_reader.cpp
+++ b/plugins/remotefortressreader/item_reader.cpp
@@ -26,7 +26,13 @@
#include "df/item_statuest.h"
#include "df/item_threadst.h"
#include "df/item_toolst.h"
+#include "df/itemdef_armorst.h"
+#include "df/itemdef_glovesst.h"
+#include "df/itemdef_helmst.h"
#include "df/itemdef_instrumentst.h"
+#include "df/itemdef_pantsst.h"
+#include "df/itemdef_shieldst.h"
+#include "df/itemdef_shoesst.h"
#include "df/itemdef_toolst.h"
#include "df/itemimprovement.h"
#include "df/itemimprovement_art_imagest.h"
@@ -658,13 +664,70 @@ DFHack::command_result GetItemList(DFHack::color_ostream &stream, const DFHack::
reg->set_pitch_range_max(instrument->registers[j]->pitch_range_max);
}
send_instrument->set_description(DF2UTF(instrument->description));
- break;
}
+ break;
case df::enums::item_type::TOOL:
{
VIRTUAL_CAST_VAR(tool, df::itemdef_toolst, item);
mat_def->set_name(DF2UTF(tool->name));
}
+ break;
+ case df::enums::item_type::ARMOR:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_armorst, item))
+ {
+ mat_def->set_up_step(armor->ubstep);
+ mat_def->set_down_step(armor->lbstep);
+ mat_def->set_layer((ArmorLayer)armor->props.layer);
+ }
+ }
+ break;
+ case df::enums::item_type::SHOES:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_shoesst, item))
+ {
+ mat_def->set_up_step(armor->upstep);
+ mat_def->set_down_step(10000);
+ mat_def->set_layer((ArmorLayer)armor->props.layer);
+ }
+ }
+ break;
+ case df::enums::item_type::SHIELD:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_shieldst, item))
+ {
+ mat_def->set_up_step(armor->upstep);
+ mat_def->set_down_step(10000);
+ }
+ }
+ break;
+ case df::enums::item_type::HELM:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_helmst, item))
+ {
+ mat_def->set_layer((ArmorLayer)armor->props.layer);
+ }
+ }
+ break;
+ case df::enums::item_type::GLOVES:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_glovesst, item))
+ {
+ mat_def->set_up_step(armor->upstep);
+ mat_def->set_down_step(10000);
+ mat_def->set_layer((ArmorLayer)armor->props.layer);
+ }
+ }
+ break;
+ case df::enums::item_type::PANTS:
+ {
+ if (VIRTUAL_CAST_VAR(armor, df::itemdef_pantsst, item))
+ {
+ mat_def->set_down_step(armor->lbstep);
+ mat_def->set_layer((ArmorLayer)armor->props.layer);
+ }
+ }
+ break;
default:
break;
}
diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp
index 7dced3b9f..cd9ebd87e 100644
--- a/plugins/remotefortressreader/remotefortressreader.cpp
+++ b/plugins/remotefortressreader/remotefortressreader.cpp
@@ -1,5 +1,5 @@
#include "df_version_int.h"
-#define RFR_VERSION "0.19.1"
+#define RFR_VERSION "0.20.2"
#include
#include
@@ -63,7 +63,7 @@
#include "df/flow_guide_item_cloudst.h"
#include "df/graphic.h"
#include "df/historical_figure.h"
-
+#include "df/identity.h"
#include "df/job.h"
#include "df/job_type.h"
#include "df/job_item.h"
@@ -92,7 +92,10 @@
#include "df/ui.h"
#include "df/unit.h"
#include "df/unit_inventory_item.h"
+#include "df/unit_wound.h"
#include "df/viewscreen_choose_start_sitest.h"
+#include "df/viewscreen_loadgamest.h"
+#include "df/viewscreen_savegamest.h"
#include "df/vehicle.h"
#include "df/world.h"
#include "df/world_data.h"
@@ -117,6 +120,7 @@
#include "adventure_control.h"
#include "building_reader.h"
+#include "dwarf_control.h"
#include "item_reader.h"
using namespace DFHack;
@@ -161,13 +165,11 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in
static command_result GetPartialPlantRaws(color_ostream &stream, const ListRequest *in, PlantRawList *out);
static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, ScreenCapture *out);
static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in);
-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);
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);
-
+static command_result GetGameValidity(color_ostream &stream, const EmptyMessage * in, SingleBool *out);
void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos);
@@ -208,54 +210,6 @@ command_result loadArtImageChunk(color_ostream &out, vector & parameter
return CR_OK;
}
-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 (size_t creatureIndex = 0; creatureIndex < world->raws.creatures.all.size(); creatureIndex++)
- {
- auto creatureRaw = world->raws.creatures.all[creatureIndex];
- for (size_t casteIndex = 0; casteIndex < creatureRaw->caste.size(); casteIndex++)
- {
- df::caste_raw *casteRaw = creatureRaw->caste[casteIndex];
- for (size_t 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
-#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.close();
-
- return CR_OK;
-}
-
command_result RemoteFortressReader_version(color_ostream &out, vector ¶meters)
{
out.print(RFR_VERSION);
@@ -267,16 +221,6 @@ 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)
{
- //// 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."));
commands.push_back(PluginCommand(
"load-art-image-chunk",
@@ -329,6 +273,9 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &)
svc->addFunction("MovementSelectCommand", MovementSelectCommand, SF_ALLOW_REMOTE);
svc->addFunction("MiscMoveCommand", MiscMoveCommand, SF_ALLOW_REMOTE);
svc->addFunction("GetLanguage", GetLanguage, SF_ALLOW_REMOTE);
+ svc->addFunction("GetSideMenu", GetSideMenu, SF_ALLOW_REMOTE);
+ svc->addFunction("SetSideMenu", SetSideMenu, SF_ALLOW_REMOTE);
+ svc->addFunction("GetGameValidity", GetGameValidity, SF_ALLOW_REMOTE);
return svc;
}
@@ -1506,7 +1453,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in
goto ItsAir;
}
}
- ItsAir:
+ ItsAir:
if (block->flows.size() > 0)
nonAir = true;
if (nonAir || firstBlock)
@@ -1556,9 +1503,9 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in
segment_passed = 0;
// 'rotate' directions
- int buffer = di;
+ int filename = di;
di = -dj;
- dj = buffer;
+ dj = filename;
// increase segment length if necessary
if (dj == 0) {
@@ -1702,6 +1649,24 @@ static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in,
return GetUnitListInside(stream, NULL, out);
}
+float lerp(float a, float b, float f)
+{
+ return a + f * (b - a);
+}
+
+void GetWounds(df::unit_wound * wound, UnitWound * send_wound)
+{
+ for (size_t i = 0; i < wound->parts.size(); i++)
+ {
+ auto part = wound->parts[i];
+ auto send_part = send_wound->add_parts();
+ send_part->set_global_layer_idx(part->global_layer_idx);
+ send_part->set_body_part_id(part->body_part_id);
+ send_part->set_layer_idx(part->layer_idx);
+ }
+ send_wound->set_severed_part(wound->flags.bits.severed_part);
+}
+
static command_result GetUnitListInside(color_ostream &stream, const BlockRequest *in, UnitList *out)
{
auto world = df::global::world;
@@ -1724,6 +1689,25 @@ static command_result GetUnitListInside(color_ostream &stream, const BlockReques
if (unit->pos.y < in->min_y() * 16 || unit->pos.y >= in->max_y() * 16)
continue;
}
+
+ using df::global::cur_year;
+ using df::global::cur_year_tick;
+
+ int year_ticks = 403200;
+ int birth_time = unit->birth_year * year_ticks + unit->birth_time;
+ int cur_time = *cur_year * year_ticks + *cur_year_tick;
+
+ if (unit->curse_year >= 0)
+ {
+ if (auto identity = Units::getIdentity(unit))
+ {
+ if (identity->histfig_id < 0)
+ birth_time = identity->birth_year * year_ticks + identity->birth_second;
+ }
+ }
+
+ send_unit->set_age(cur_time - birth_time);
+
ConvertDfColor(Units::getProfessionColor(unit), send_unit->mutable_profession_color());
send_unit->set_flags1(unit->flags1.whole);
send_unit->set_flags2(unit->flags2.whole);
@@ -1806,6 +1790,7 @@ static command_result GetUnitListInside(color_ostream &stream, const BlockReques
auto inventory_item = unit->inventory[j];
auto sent_item = send_unit->add_inventory();
sent_item->set_mode((InventoryMode)inventory_item->mode);
+ sent_item->set_body_part_id(inventory_item->body_part_id);
CopyItem(sent_item->mutable_item(), inventory_item->item);
}
@@ -1821,8 +1806,51 @@ static command_result GetUnitListInside(color_ostream &stream, const BlockReques
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);
+ auto facing = send_unit->mutable_facing();
+ facing->set_x(item->speed_x);
+ facing->set_y(item->speed_x);
+ facing->set_z(item->speed_x);
+ break;
+ }
+ }
+ else
+ {
+ for (size_t i = 0; i < unit->actions.size(); i++)
+ {
+ auto action = unit->actions[i];
+ switch (action->type)
+ {
+ case unit_action_type::Move:
+ if (unit->path.path.x.size() > 0)
+ {
+ send_unit->set_subpos_x(lerp(0, unit->path.path.x[0] - unit->pos.x, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init));
+ send_unit->set_subpos_y(lerp(0, unit->path.path.y[0] - unit->pos.y, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init));
+ send_unit->set_subpos_z(lerp(0, unit->path.path.z[0] - unit->pos.z, (float)(action->data.move.timer_init - action->data.move.timer) / action->data.move.timer_init));
+ }
+ break;
+ case unit_action_type::Job:
+ {
+ auto facing = send_unit->mutable_facing();
+ facing->set_x(action->data.job.x - unit->pos.x);
+ facing->set_y(action->data.job.y - unit->pos.y);
+ facing->set_z(action->data.job.z - unit->pos.z);
+ }
+ default:
+ break;
+ }
+ }
+ if (unit->path.path.x.size() > 0)
+ {
+ auto facing = send_unit->mutable_facing();
+ facing->set_x(unit->path.path.x[0] - unit->pos.x);
+ facing->set_y(unit->path.path.y[0] - unit->pos.y);
+ facing->set_z(unit->path.path.z[0] - unit->pos.z);
}
}
+ for (size_t i = 0; i < unit->body.wounds.size(); i++)
+ {
+ GetWounds(unit->body.wounds[i], send_unit->add_wounds());
+ }
}
return CR_OK;
}
@@ -1847,6 +1875,14 @@ static command_result GetViewInfo(color_ostream &stream, const EmptyMessage *in,
}
#endif
+ auto dims = Gui::getDwarfmodeViewDims();
+
+ x += dims.map_x1;
+ y += dims.map_y1;
+
+ w = dims.map_x2 - dims.map_x1;
+ h = dims.map_y2 - dims.map_y1;
+
out->set_view_pos_x(x);
out->set_view_pos_y(y);
out->set_view_pos_z(z);
@@ -2793,6 +2829,10 @@ static command_result GetPartialCreatureRaws(color_ostream &stream, const ListRe
CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index);
}
+ FOR_ENUM_ITEMS(creature_raw_flags, flag)
+ {
+ send_creature->add_flags(orig_creature->flags.is_set(flag));
+ }
}
return CR_OK;
@@ -2893,94 +2933,26 @@ static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEve
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);
-
-#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;
-#endif
- }
-
- mc.WriteAll();
- return CR_OK;
-}
-
-static command_result SetPauseState(color_ostream &stream, const SingleBool *in)
+static command_result GetPauseState(color_ostream &stream, const EmptyMessage *in, SingleBool *out)
{
- DFHack::World::SetPauseState(in->value());
+ out->set_value(World::ReadPauseState());
return CR_OK;
}
-static command_result GetPauseState(color_ostream &stream, const EmptyMessage *in, SingleBool *out)
+static command_result GetGameValidity(color_ostream &stream, const EmptyMessage * in, SingleBool *out)
{
- out->set_value(World::ReadPauseState());
+ auto viewScreen = Gui::getCurViewscreen();
+ if (strict_virtual_cast(viewScreen))
+ {
+ out->set_value(false);
+ return CR_OK;
+ }
+ else if (strict_virtual_cast(viewScreen))
+ {
+ out->set_value(false);
+ return CR_OK;
+ }
+ out->set_value(true);
return CR_OK;
}