Merge remote-tracking branch 'DFHack/develop' into remote_control
commit
6a516d7034
@ -0,0 +1,43 @@
|
||||
#include "Error.h"
|
||||
#include "MiscUtils.h"
|
||||
|
||||
using namespace DFHack::Error;
|
||||
|
||||
inline std::string safe_str(const char *s)
|
||||
{
|
||||
return s ? s : "(NULL)";
|
||||
}
|
||||
|
||||
NullPointer::NullPointer(const char *varname)
|
||||
:All("NULL pointer: " + safe_str(varname)),
|
||||
varname(varname)
|
||||
{}
|
||||
|
||||
InvalidArgument::InvalidArgument(const char *expr)
|
||||
:All("Invalid argument; expected: " + safe_str(expr)),
|
||||
expr(expr)
|
||||
{}
|
||||
|
||||
VTableMissing::VTableMissing(const char *name)
|
||||
:All("Missing vtable address: " + safe_str(name)),
|
||||
name(name)
|
||||
{}
|
||||
|
||||
SymbolsXmlParse::SymbolsXmlParse(const char* desc, int id, int row, int 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("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("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))
|
||||
{}
|
@ -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})
|
@ -0,0 +1,754 @@
|
||||
/* 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 <utility>
|
||||
|
||||
#include "DataDefs.h"
|
||||
#include <df/region_map_entry.h>
|
||||
#include <df/world.h>
|
||||
#include <df/world_data.h>
|
||||
#include <df/biome_type.h>
|
||||
|
||||
#include "biome_type.h"
|
||||
|
||||
/*****************************************************************************
|
||||
Local functions forward declaration
|
||||
*****************************************************************************/
|
||||
std::pair<bool, bool> 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<bool, bool> 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<bool, bool> 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<bool, bool>(is_possible_tropical_area_by_latitude,
|
||||
is_tropical_area_by_latitude
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Utility function
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
std::pair<bool, bool> 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<bool, bool>(is_possible_tropical_area_by_latitude,
|
||||
is_tropical_area_by_latitude
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Utility function
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
std::pair<bool, bool> 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<bool, bool>(is_possible_tropical_area_by_latitude,
|
||||
is_tropical_area_by_latitude
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Utility function
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
std::pair<bool, bool> 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<bool, bool>(is_possible_tropical_area_by_latitude,
|
||||
is_tropical_area_by_latitude
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Utility function
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
std::pair<bool, bool> 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<bool, bool>(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
|
||||
}
|
||||
}
|
@ -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);
|
@ -0,0 +1,256 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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<bool> metals;
|
||||
std::vector<bool> economics;
|
||||
std::vector<bool> minerals;
|
||||
};
|
||||
|
||||
typedef std::array<std::array<mid_level_tile, 16>, 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<bool> metals;
|
||||
std::vector<bool> economics;
|
||||
std::vector<bool> 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<bool> possible_metals;
|
||||
std::vector<bool> possible_economics;
|
||||
std::vector<bool> possible_minerals;
|
||||
};
|
||||
|
||||
typedef std::vector<geo_datum> 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<uint16_t> metals;
|
||||
std::vector<uint16_t> economics;
|
||||
std::vector<uint16_t> minerals;
|
||||
// Could add savagery, evilness, and biomes, but DF provides those easily.
|
||||
};
|
||||
|
||||
typedef std::vector<sites> site_lists;
|
||||
|
||||
typedef std::vector<std::vector<region_tile_datum>> 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<std::vector<matches>> 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<int8_t>(evil_savagery_ranges::High) + 1];
|
||||
evil_savagery_values evilness[static_cast<int8_t>(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);
|
||||
}
|
||||
}
|
@ -0,0 +1,296 @@
|
||||
#include "Core.h"
|
||||
#include <Console.h>
|
||||
#include <Export.h>
|
||||
#include <PluginManager.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <modules/Gui.h>
|
||||
#include <modules/Screen.h>
|
||||
|
||||
#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<df::viewscreen_choose_start_sitest>(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<df::viewscreen_choose_start_sitest>(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 <std::string> & parameters);
|
||||
|
||||
//=======================================================================================
|
||||
|
||||
DFhackCExport command_result plugin_init (color_ostream &out, std::vector <PluginCommand> &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 the 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 <std::string> & parameters)
|
||||
{
|
||||
if (!parameters.empty())
|
||||
return CR_WRONG_USAGE;
|
||||
|
||||
CoreSuspender suspend;
|
||||
|
||||
auto screen = Gui::getViewscreenByType<df::viewscreen_choose_start_sitest>(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;
|
||||
}
|
@ -0,0 +1 @@
|
||||
#pragma once
|
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
}
|
||||
}
|
@ -0,0 +1,314 @@
|
||||
#include "Core.h"
|
||||
#include <Console.h>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <modules/Gui.h>
|
||||
|
||||
#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();
|
||||
|
||||
void feed(std::set<df::interface_key> *input);
|
||||
|
||||
void render();
|
||||
|
||||
std::string getFocusString() { return "Help UI"; }
|
||||
|
||||
private:
|
||||
pages current_page = pages::Intro;
|
||||
};
|
||||
|
||||
//===============================================================================
|
||||
|
||||
void ViewscreenHelpUi::feed(std::set<df::interface_key> *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<std::string> 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 <ESC>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 embark_assist::help_ui::init(DFHack::Plugin *plugin_self) {
|
||||
Screen::show(new embark_assist::help_ui::ViewscreenHelpUi(), plugin_self);
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,439 @@
|
||||
#include <modules/Gui.h>
|
||||
|
||||
#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<display_strings> 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<df::interface_key> *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<df::viewscreen_choose_start_sitest>(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;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <VTableInterpose.h>
|
||||
#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();
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
#include "screen.h"
|
||||
|
||||
namespace embark_assist {
|
||||
namespace screen {
|
||||
}
|
||||
}
|
||||
|
||||
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 (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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
|
||||
#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();
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
#include "df/global_objects.h"
|
||||
#include "modules/Gui.h"
|
||||
#include "modules/Screen.h"
|
||||
#include "df/enabler.h"
|
||||
#include "df/viewscreen_dwarfmodest.h"
|
||||
#include "df/viewscreen_titlest.h"
|
||||
|
||||
struct dwarfmode_pausing_fps_counter_hook : df::viewscreen_dwarfmodest {
|
||||
typedef df::viewscreen_dwarfmodest interpose_base;
|
||||
|
||||
static const uint32_t history_length = 3;
|
||||
|
||||
// whether init.txt have [FPS:YES]
|
||||
static bool init_have_fps_yes()
|
||||
{
|
||||
static bool first = true;
|
||||
static bool init_have_fps_yes;
|
||||
|
||||
if (first && df::global::gps)
|
||||
{
|
||||
// if first time called, then display_frames is set iff init.txt have [FPS:YES]
|
||||
first = false;
|
||||
init_have_fps_yes = (df::global::gps->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);
|
@ -1 +1 @@
|
||||
Subproject commit 8d079a59122d9ba72ce9c0f7687402a343d09bc7
|
||||
Subproject commit 28a1ccc9883d85106fa3b0ed59ddd57fcfc3f5c7
|
@ -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')
|
@ -0,0 +1,2 @@
|
||||
:lua dfhack.internal.addScriptPath(os.getenv('TRAVIS_BUILD_DIR'))
|
||||
test/main
|
@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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 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
|
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
cd ..
|
||||
grep DF_VERSION CMakeLists.txt | perl -ne 'print "$&\n" if /[\d\.]+/'
|
@ -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)
|
Loading…
Reference in New Issue