diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d70a124d..cf87ba54f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,8 +64,8 @@ OPTION(BUILD_PLUGINS "Build the plugins." ON) IF(UNIX) add_definitions(-DLINUX_BUILD) SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall") - SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -march=i686 -std=c++0x") - SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32 -march=i686") + SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x") + SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic") ENDIF() #add depends to include path diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 9545c49f9..c8fe57a92 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -15,7 +15,9 @@ include_directories (depends/tinyxml) include_directories (depends/tthread) add_subdirectory (depends/protobuf) -execute_process(COMMAND perl xml/list.pl xml include/df ";" +SET(PERL_EXECUTABLE "perl" CACHE FILEPATH "This is the perl executable to run in the codegen step. Tweak it if you need to run a specific one.") + +execute_process(COMMAND ${PERL_EXECUTABLE} xml/list.pl xml include/df ";" WORKING_DIRECTORY ${dfapi_SOURCE_DIR} OUTPUT_VARIABLE GENERATED_HDRS) @@ -142,7 +144,7 @@ FILE(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/*.xml) ADD_CUSTOM_COMMAND( OUTPUT ${dfapi_SOURCE_DIR}/include/df/static.inc - COMMAND perl xml/codegen.pl xml include/df + COMMAND ${PERL_EXECUTABLE} xml/codegen.pl xml include/df WORKING_DIRECTORY ${dfapi_SOURCE_DIR} MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS} @@ -164,7 +166,7 @@ IF(UNIX) ENDIF() IF(UNIX) - SET(PROJECT_LIBS rt ) + SET(PROJECT_LIBS rt dl) ELSE(WIN32) #FIXME: do we really need this? SET(PROJECT_LIBS psapi ${dfhack_SOURCE_DIR}/library/depends/ntdll/ntdll.lib) diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index b3d70f6b9..55dc9e404 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -262,6 +262,13 @@ inline bool bits_match(unsigned required, unsigned ok, unsigned mask) return (required & mask) == (required & mask & ok); } +template +inline T clip_range(T a, T1 minv, T2 maxv) { + if (a < minv) return minv; + if (a > maxv) return maxv; + return a; +} + /** * Returns the amount of milliseconds elapsed since the UNIX epoch. * Works on both windows and linux. diff --git a/library/include/df/custom/coord.methods.inc b/library/include/df/custom/coord.methods.inc index 64d170376..a66a71919 100644 --- a/library/include/df/custom/coord.methods.inc +++ b/library/include/df/custom/coord.methods.inc @@ -22,6 +22,15 @@ bool operator<(const coord &other) const return z < other.z; } +coord operator+(const coord &other) const +{ + return coord(x + other.x, y + other.y, z + other.z); +} +coord operator-(const coord &other) const +{ + return coord(x - other.x, y - other.y, z - other.z); +} + coord operator/(int number) const { return coord(x/number, y/number, z); diff --git a/library/include/df/custom/coord2d.methods.inc b/library/include/df/custom/coord2d.methods.inc index b6b47bca1..f617001cb 100644 --- a/library/include/df/custom/coord2d.methods.inc +++ b/library/include/df/custom/coord2d.methods.inc @@ -18,6 +18,15 @@ bool operator<(const coord2d &other) const return y < other.y; } +coord2d operator+(const coord2d &other) const +{ + return coord2d(x + other.x, y + other.y); +} +coord2d operator-(const coord2d &other) const +{ + return coord2d(x - other.x, y - other.y); +} + coord2d operator/(int number) const { return coord2d(x/number, y/number); diff --git a/library/xml b/library/xml index 7aa928ebe..64a7aeb6a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7aa928ebe466a4a6036e6bb9e72b12416f0168e4 +Subproject commit 64a7aeb6a87b7b5067ace8f6a869b7b4fe6561a4 diff --git a/plugins/fixveins.cpp b/plugins/fixveins.cpp index 44b211758..e86bb01d6 100644 --- a/plugins/fixveins.cpp +++ b/plugins/fixveins.cpp @@ -65,19 +65,27 @@ DFhackCExport command_result df_fixveins (Core * c, vector & parameters for (int k = 0; k < 16; k++) has_mineral[k] |= mineral->tile_bitmask[k]; } + t_feature local, global; + Maps::GetGlobalFeature(global, block->global_feature); + Maps::GetLocalFeature(local, df::coord2d(block->map_pos.x / 16, block->map_pos.y / 16), block->local_feature); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { + bool has_feature = ((block->designation[x][y].bits.feature_global) && (global.main_material != -1) && (global.sub_material != -1)) || + ((block->designation[x][y].bits.feature_local) && (local.main_material != -1) && (local.sub_material != -1)); + bool has_vein = has_mineral[y] & (1 << x); + if (has_feature) + has_vein = false; int16_t oldT = block->tiletype[x][y]; TileMaterial mat = tileMaterial(oldT); - if ((mat == VEIN) && !(has_mineral[y] & (1 << x))) + if ((mat == VEIN) && !has_vein) mineral_removed += setTileMaterial(block->tiletype[x][y], STONE); - if ((mat == STONE) && (has_mineral[y] & (1 << x))) + if ((mat == STONE) && has_vein) mineral_added += setTileMaterial(block->tiletype[x][y], VEIN); - if ((mat == FEATSTONE) && !(block->designation[x][y].bits.feature_local || block->designation[x][y].bits.feature_global)) + if ((mat == FEATSTONE) && !has_feature) feature_removed += setTileMaterial(block->tiletype[x][y], STONE); - if ((mat == STONE) && (block->designation[x][y].bits.feature_local || block->designation[x][y].bits.feature_global)) + if ((mat == STONE) && has_feature) feature_added += setTileMaterial(block->tiletype[x][y], FEATSTONE); } } diff --git a/plugins/mode.cpp b/plugins/mode.cpp index e8ef7fa4a..f318c3853 100644 --- a/plugins/mode.cpp +++ b/plugins/mode.cpp @@ -113,7 +113,7 @@ DFhackCExport command_result mode (Core * c, vector & parameters) printCurrentModes(gm, c->con); if(set) { - if(gm.g_mode == GAMEMODE_NONE || gm.g_type == GAMETYPE_VIEW_LEGENDS || gm.g_type == GAMETYPE_DWARF_RECLAIM) + if( gm.g_mode == GAMEMODE_NONE || gm.g_type == GAMETYPE_VIEW_LEGENDS ) { c->con.printerr("It is not safe to set modes in menus.\n"); return CR_FAILURE; @@ -123,6 +123,7 @@ DFhackCExport command_result mode (Core * c, vector & parameters) << "1 = Adventurer Mode" << endl << "2 = Arena Mode" << endl << "3 = Arena, controlling creature" << endl + << "4 = Reclaim Fortress Mode" << endl << "c = cancel/do nothing" << endl; uint32_t select=99; @@ -135,7 +136,7 @@ DFhackCExport command_result mode (Core * c, vector & parameters) const char * start = selected.c_str(); char * end = 0; select = strtol(start, &end, 10); - if(!end || end==start || select > 3) + if(!end || end==start || select > 4) { c->con.printerr("This is not a valid selection.\n"); goto input_again; @@ -159,6 +160,10 @@ DFhackCExport command_result mode (Core * c, vector & parameters) gm.g_mode = GAMEMODE_ADVENTURE; gm.g_type = GAMETYPE_ADVENTURE_ARENA; break; + case 4: + gm.g_mode = GAMEMODE_DWARF; + gm.g_type = GAMETYPE_DWARF_RECLAIM; + break; } c->Suspend(); world->WriteGameMode(gm); diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index 7a2c18dc8..d550132a5 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -19,12 +19,21 @@ using namespace std; #include "PluginManager.h" #include "modules/MapCache.h" +#include "MiscUtils.h" + #include "DataDefs.h" #include "df/world.h" +#include "df/world_data.h" +#include "df/world_region_details.h" +#include "df/world_geo_biome.h" +#include "df/world_geo_layer.h" +#include "df/inclusion_type.h" +#include "df/viewscreen_choose_start_sitest.h" using namespace DFHack; using namespace df::enums; using df::global::world; +using df::coord2d; struct matdata { @@ -41,9 +50,9 @@ struct matdata lower_z = copyme.lower_z; upper_z = copyme.upper_z; } - unsigned int add( int z_level = invalid_z ) + unsigned int add( int z_level = invalid_z, int delta = 1 ) { - count ++; + count += delta; if(z_level != invalid_z) { if(lower_z == invalid_z || z_level < lower_z) @@ -187,6 +196,12 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector " all - Scan the whole map, as if it was revealed.\n" " value - Show material value in the output. Most useful for gems.\n" " hell - Show the Z range of HFS tubes. Implies 'all'.\n" + "Pre-embark estimate:\n" + " If called during the embark selection screen, displays\n" + " an estimate of layer stone availability. If the 'all'\n" + " option is specified, also estimates veins.\n" + " The estimate is computed either for 1 embark tile of the\n" + " blinking biome, or for all tiles of the embark rectangle.\n" )); return CR_OK; } @@ -196,6 +211,120 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) return CR_OK; } +static coord2d biome_delta[] = { + coord2d(-1,1), coord2d(0,1), coord2d(1,1), + coord2d(-1,0), coord2d(0,0), coord2d(1,0), + coord2d(-1,-1), coord2d(0,-1), coord2d(1,-1) +}; + +static command_result embark_prospector(DFHack::Core *c, df::viewscreen_choose_start_sitest *screen, + bool showHidden, bool showValue) +{ + if (!world || !world->world_data) + { + c->con.printerr("World data is not available.\n"); + return CR_FAILURE; + } + + df::world_data *data = world->world_data; + coord2d cur_region = screen->region_pos; + int d_idx = linear_index(data->region_details, &df::world_region_details::pos, cur_region); + auto cur_details = vector_get(data->region_details, d_idx); + + if (!cur_details) + { + c->con.printerr("Current region details are not available.\n"); + return CR_FAILURE; + } + + // Compute biomes + std::map biomes; + + if (screen->biome_highlighted) + { + c->con.print("Processing one embark tile of biome F%d.\n\n", screen->biome_idx+1); + biomes[screen->biome_rgn[screen->biome_idx]]++; + } + else + { + for (int x = screen->embark_pos_min.x; x <= screen->embark_pos_max.x; x++) + { + for (int y = screen->embark_pos_min.y; y <= screen->embark_pos_max.y; y++) + { + int bv = clip_range(cur_details->biome[x][y], 1, 9); + biomes[cur_region + biome_delta[bv-1]]++; + } + } + } + + // Compute material maps + MatMap layerMats; + MatMap veinMats; + + for (auto biome_it = biomes.begin(); biome_it != biomes.end(); ++biome_it) + { + int bx = clip_range(biome_it->first.x, 0, data->world_width-1); + int by = clip_range(biome_it->first.y, 0, data->world_height-1); + auto ®ion = data->region_map[bx][by]; + df::world_geo_biome *geo_biome = df::world_geo_biome::find(region.geo_index); + + if (!geo_biome) + { + c->con.printerr("Region geo-biome not found: (%d,%d)\n", bx, by); + return CR_FAILURE; + } + + int cnt = biome_it->second; + + for (unsigned i = 0; i < geo_biome->layers.size(); i++) + { + auto layer = geo_biome->layers[i]; + + for (int z = layer->bottom_height; z <= layer->top_height; z++) + { + layerMats[layer->mat_index].add(z, 48*48*cnt); + + for (unsigned j = 0; j < layer->vein_mat.size(); j++) + { + // TODO: find out how to estimate the real density + int bias = 100; + switch (layer->vein_type[j]) + { + case inclusion_type::VEIN: + bias = 360; + break; + case inclusion_type::CLUSTER: + bias = 1800; + break; + case inclusion_type::CLUSTER_SMALL: + bias = 18; + break; + case inclusion_type::CLUSTER_ONE: + bias = 3; + break; + } + + veinMats[layer->vein_mat[j]].add(z, layer->vein_unk_38[j]*bias*cnt/100); + } + } + } + } + + // Print the report + c->con << "Layer materials:" << std::endl; + printMats(c->con, layerMats, world->raws.inorganics, showValue); + + if (showHidden) { + DFHack::Materials *mats = c->getMaterials(); + printVeins(c->con, veinMats, mats, showValue); + mats->Finish(); + } + + c->con << "Warning: the above data is only a very rough estimate." << std::endl; + + return CR_OK; +} + DFhackCExport command_result prospector (DFHack::Core * c, vector & parameters) { bool showHidden = false; @@ -222,13 +351,19 @@ DFhackCExport command_result prospector (DFHack::Core * c, vector & par else return CR_WRONG_USAGE; } - uint32_t x_max = 0, y_max = 0, z_max = 0; CoreSuspender suspend(c); + + // Embark screen active: estimate using world geology data + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, c->getTopViewscreen())) + return embark_prospector(c, screen, showHidden, showValue); + if (!Maps::IsValid()) { c->con.printerr("Map is not available!\n"); return CR_FAILURE; } + + uint32_t x_max = 0, y_max = 0, z_max = 0; Maps::getSize(x_max, y_max, z_max); MapExtras::MapCache map; diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 9631ef091..0639a308f 100755 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -14,7 +14,9 @@ #include "df/world.h" #include "df/plant_raw.h" #include "df/item_flags.h" +#include "df/items_other_id.h" +using namespace std; using namespace DFHack; using namespace DFHack::Simple; using namespace df::enums; @@ -24,7 +26,7 @@ const int buffer = 20; // seed number buffer - 20 is reasonable bool running = false; // whether seedwatch is counting the seeds or not // abbreviations for the standard plants -std::map abbreviations; +map abbreviations; bool ignoreSeeds(df::item_flags& f) // seeds with the following flags should not be counted { @@ -64,7 +66,7 @@ void printHelp(Core& core) // prints help if(!abbreviations.empty()) { core.con.print("You can use these abbreviations for the plant tokens:\n"); - for(std::map::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) + for(map::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) { core.con.print("%s -> %s\n", i->first.c_str(), i->second.c_str()); } @@ -83,7 +85,7 @@ void printHelp(Core& core) // prints help }; // searches abbreviations, returns expansion if so, returns original if not -std::string searchAbbreviations(std::string in) +string searchAbbreviations(string in) { if(abbreviations.count(in) > 0) { @@ -95,7 +97,7 @@ std::string searchAbbreviations(std::string in) } }; -DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& parameters) +DFhackCExport command_result df_seedwatch(Core* pCore, vector& parameters) { Core& core = *pCore; if(!core.isValid()) @@ -104,8 +106,8 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& } CoreSuspender suspend(pCore); - std::map materialsReverser; - for(std::size_t i = 0; i < world->raws.plants.all.size(); ++i) + map materialsReverser; + for(size_t i = 0; i < world->raws.plants.all.size(); ++i) { materialsReverser[world->raws.plants.all[i]->id] = i; } @@ -122,7 +124,7 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& return CR_OK; } - std::string par; + string par; int limit; switch(parameters.size()) { @@ -159,7 +161,7 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& { core.con.print("seedwatch is not supervising. Use 'seedwatch start' to start supervision.\n"); } - std::map watchMap; + map watchMap; Kitchen::fillWatchMap(watchMap); if(watchMap.empty()) { @@ -168,7 +170,7 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& else { core.con.print("The watch list is:\n"); - for(std::map::const_iterator i = watchMap.begin(); i != watchMap.end(); ++i) + for(map::const_iterator i = watchMap.begin(); i != watchMap.end(); ++i) { core.con.print("%s : %u\n", world->raws.plants.all[i->first]->id.c_str(), i->second); } @@ -176,7 +178,7 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& } else if(par == "debug") { - std::map watchMap; + map watchMap; Kitchen::fillWatchMap(watchMap); Kitchen::debug_print(core); } @@ -199,7 +201,7 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& */ else { - std::string token = searchAbbreviations(par); + string token = searchAbbreviations(par); if(materialsReverser.count(token) > 0) { Kitchen::removeLimit(materialsReverser[token]); @@ -216,14 +218,14 @@ DFhackCExport command_result df_seedwatch(Core* pCore, std::vector& if(limit < 0) limit = 0; if(parameters[0] == "all") { - for(std::map::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) + for(map::const_iterator i = abbreviations.begin(); i != abbreviations.end(); ++i) { if(materialsReverser.count(i->second) > 0) Kitchen::setLimit(materialsReverser[i->second], limit); } } else { - std::string token = searchAbbreviations(parameters[0]); + string token = searchAbbreviations(parameters[0]); if(materialsReverser.count(token) > 0) { Kitchen::setLimit(materialsReverser[token], limit); @@ -248,7 +250,7 @@ DFhackCExport const char* plugin_name(void) return "seedwatch"; } -DFhackCExport command_result plugin_init(Core* pCore, std::vector& commands) +DFhackCExport command_result plugin_init(Core* pCore, vector& commands) { commands.clear(); commands.push_back(PluginCommand("seedwatch", "Switches cookery based on quantity of seeds, to keep reserves", df_seedwatch)); @@ -316,24 +318,17 @@ DFhackCExport command_result plugin_onupdate(Core* pCore) return CR_OK; } // this is dwarf mode, continue - std::map seedCount; // the number of seeds + map seedCount; // the number of seeds // count all seeds and plants by RAW material - for(std::size_t i = 0; i < world->items.all.size(); ++i) + for(size_t i = 0; i < world->items.other[items_other_id::SEEDS].size(); ++i) { - df::item * item = world->items.all[i]; + df::item * item = world->items.other[items_other_id::SEEDS][i]; t_materialIndex materialIndex = item->getMaterialIndex(); - switch(item->getType()) - { - case item_type::SEEDS: - if(!ignoreSeeds(item->flags)) ++seedCount[materialIndex]; - break; - case item_type::PLANT: - break; - } + if(!ignoreSeeds(item->flags)) ++seedCount[materialIndex]; } - std::map watchMap; + map watchMap; Kitchen::fillWatchMap(watchMap); for(auto i = watchMap.begin(); i != watchMap.end(); ++i) {