Merge remote-tracking branch 'PatrikLundell/embark-assistant' into develop
						commit
						ef3adbe816
					
				@ -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 th  pre embark screen is\n"
 | 
			
		||||
        "  displayed and shows extended (and correct(?)) resource information for\n"
 | 
			
		||||
        "  the embark rectangle as well as normally undisplayed sites in the\n"
 | 
			
		||||
        "  current embark region. It also has a site selection tool with more\n"
 | 
			
		||||
        "  options than DF's vanilla search tool. For detailed help invoke the\n"
 | 
			
		||||
        "  in game info screen. Requires 42 lines to display properly.\n"
 | 
			
		||||
    ));
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//=======================================================================================
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_shutdown (color_ostream &out)
 | 
			
		||||
{
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//=======================================================================================
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event)
 | 
			
		||||
{
 | 
			
		||||
    switch (event) {
 | 
			
		||||
      case DFHack::SC_UNKNOWN:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_WORLD_LOADED:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_WORLD_UNLOADED:
 | 
			
		||||
      case DFHack::SC_MAP_LOADED:
 | 
			
		||||
          if (embark_assist::main::state) {
 | 
			
		||||
              embark_assist::main::shutdown();
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_MAP_UNLOADED:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_VIEWSCREEN_CHANGED:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_CORE_INITIALIZED:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_BEGIN_UNLOAD:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_PAUSED:
 | 
			
		||||
          break;
 | 
			
		||||
 | 
			
		||||
      case DFHack::SC_UNPAUSED:
 | 
			
		||||
          break;
 | 
			
		||||
    }
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//=======================================================================================
 | 
			
		||||
 | 
			
		||||
command_result embark_assistant(color_ostream &out, std::vector <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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue