diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py new file mode 100644 index 000000000..a45f07372 --- /dev/null +++ b/.ycm_extra_conf.py @@ -0,0 +1,130 @@ +'''This file provides editor completions while working on DFHack using ycmd: +https://github.com/Valloric/ycmd +''' + +# pylint: disable=import-error,invalid-name,missing-docstring,unused-argument + +import os +import ycm_core + +def DirectoryOfThisScript(): + return os.path.dirname(os.path.abspath(__file__)) + +# We need to tell YouCompleteMe how to compile this project. We do this using +# clang's "Compilation Database" system, which essentially just dumps a big +# json file into the build folder. +# More details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# We don't use clang, but luckily CMake supports generating a database on its +# own, using: +# set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) + +for potential_build_folder in ['build', 'build-osx']: + if os.path.exists(DirectoryOfThisScript() + os.path.sep + potential_build_folder + + os.path.sep + 'compile_commands.json'): + database = ycm_core.CompilationDatabase(potential_build_folder) + break +else: + raise RuntimeError("Can't find dfhack build folder: not one of build, build-osx") + + +def MakeRelativePathsInFlagsAbsolute(flags, working_directory): + if not working_directory: + return list(flags) + new_flags = [] + make_next_absolute = False + path_flags = ['-isystem', '-I', '-iquote', '--sysroot='] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith('/'): + new_flag = os.path.join(working_directory, flag) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith(path_flag): + path = flag[len(path_flag):] + new_flag = path_flag + os.path.join(working_directory, path) + break + + if new_flag: + new_flags.append(new_flag) + return new_flags + + +def IsHeaderFile(filename): + extension = os.path.splitext(filename)[1] + return extension in ['.h', '.hxx', '.hpp', '.hh'] + + +SOURCE_EXTENSIONS = ['.cpp', '.cxx', '.cc', '.c', '.m', '.mm'] + +def PotentialAlternatives(header): + dirname, filename = os.path.split(header) + basename, _ = os.path.splitext(filename) + + source_dirs = [dirname] + + if dirname.endswith(os.path.sep + 'include'): + # if we're in a folder 'include', also look in its parent + parent = os.path.abspath(os.path.join(dirname, os.path.pardir)) + source_dirs.append(parent) + # and ../src (used by lua dependency) + source_dirs.append(os.path.join(parent, 'src')) + + include_idx = dirname.rfind(os.path.sep + 'include' + os.path.sep) + if include_idx != -1: + # we're in a subfolder of a parent '/include/' + # .../include/subdir/path + # look in .../subdir/path + source_dirs.append( + dirname[:include_idx] + + os.path.sep + + dirname[include_idx + len('include') + 2*len(os.path.sep):] + ) + + for source_dir in source_dirs: + for ext in SOURCE_EXTENSIONS: + yield source_dir + os.path.sep + basename + ext + + +def GetCompilationInfoForFile(filename): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile(filename): + for alternative in PotentialAlternatives(filename): + if os.path.exists(alternative): + compilation_info = database.GetCompilationInfoForFile( + alternative + ) + + if compilation_info.compiler_flags_: + return compilation_info + return None + else: + return database.GetCompilationInfoForFile(filename) + + +def FlagsForFile(filename, **kwargs): + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile(filename) + if not compilation_info: + return None + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ + ) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/CMakeLists.txt b/CMakeLists.txt index 392b5ddb5..7da735015 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,9 @@ ${dfhack_SOURCE_DIR}/CMake/Modules ${CMAKE_MODULE_PATH} ) +# generates compile_commands.json, used for autocompletion by some editors +SET(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # mixing the build system with the source code is ugly and stupid. enforce the opposite :) if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message(FATAL_ERROR "In-source builds are not allowed.") diff --git a/NEWS.rst b/NEWS.rst index 73f42b46f..7fbfdd56a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -53,6 +53,7 @@ New Scripts New Features ------------ +- `buildingplan`: Support for floodgates, grates, and bars - `confirm`: Added a confirmation for retiring locations - `exportlegends`: Exports more information (poetic/musical/dance forms, written/artifact content, landmasses, extra histfig information, and more) - `search-plugin`: Support for new screens: diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index e4c647f7f..1a1e754d0 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -57,12 +57,21 @@ Process::Process(VersionInfoFactory * known_versions) my_descriptor = 0; my_pe = 0; + // valgrind replaces readlink for /proc/self/exe, but not open. + char self_exe[1024]; + memset(self_exe, 0, sizeof(self_exe)); + std::string self_exe_name; + if (readlink(exe_link_name, self_exe, sizeof(self_exe) - 1) < 0) + self_exe_name = exe_link_name; + else + self_exe_name = self_exe; + md5wrapper md5; uint32_t length; uint8_t first_kb [1024]; memset(first_kb, 0, sizeof(first_kb)); // get hash of the running DF process - my_md5 = md5.getHashFromFile(exe_link_name, length, (char *) first_kb); + my_md5 = md5.getHashFromFile(self_exe_name, length, (char *) first_kb); // create linux process, add it to the vector VersionInfo * vinfo = known_versions->getVersionInfoByMD5(my_md5); if(vinfo) diff --git a/library/include/BitArray.h b/library/include/BitArray.h index a507a38a4..1469091d1 100644 --- a/library/include/BitArray.h +++ b/library/include/BitArray.h @@ -164,7 +164,6 @@ namespace DFHack out << sstr.str(); return out; } - //private: uint8_t * bits; uint32_t size; }; @@ -233,4 +232,4 @@ namespace DFHack m_data[idx] = item; } }; -} \ No newline at end of file +} diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 58c1a87f9..a6589bac1 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -49,30 +49,35 @@ using namespace std; using namespace DFHack; #include "DataDefs.h" -#include "df/world.h" -#include "df/ui.h" -#include "df/ui_look_list.h" -#include "df/d_init.h" -#include "df/item.h" -#include "df/unit.h" -#include "df/job.h" -#include "df/job_item.h" -#include "df/general_ref_building_holderst.h" -#include "df/buildings_other_id.h" -#include "df/building_design.h" -#include "df/building_def.h" #include "df/building_axle_horizontalst.h" -#include "df/building_trapst.h" +#include "df/building_bars_floorst.h" +#include "df/building_bars_verticalst.h" #include "df/building_bridgest.h" -#include "df/building_coffinst.h" #include "df/building_civzonest.h" -#include "df/building_stockpilest.h" +#include "df/building_coffinst.h" +#include "df/building_def.h" +#include "df/building_design.h" +#include "df/building_floodgatest.h" #include "df/building_furnacest.h" -#include "df/building_workshopst.h" +#include "df/building_grate_floorst.h" +#include "df/building_grate_wallst.h" +#include "df/building_rollersst.h" #include "df/building_screw_pumpst.h" +#include "df/building_stockpilest.h" +#include "df/building_trapst.h" #include "df/building_water_wheelst.h" #include "df/building_wellst.h" -#include "df/building_rollersst.h" +#include "df/building_workshopst.h" +#include "df/buildings_other_id.h" +#include "df/d_init.h" +#include "df/general_ref_building_holderst.h" +#include "df/item.h" +#include "df/job.h" +#include "df/job_item.h" +#include "df/ui.h" +#include "df/ui_look_list.h" +#include "df/unit.h" +#include "df/world.h" using namespace df::enums; using df::global::ui; @@ -345,30 +350,62 @@ df::building *Buildings::allocInstance(df::coord pos, df::building_type type, in switch (type) { case building_type::Well: - { - auto obj = (df::building_wellst*)bld; + { + if (VIRTUAL_CAST_VAR(obj, df::building_wellst, bld)) obj->bucket_z = bld->z; - break; - } + break; + } case building_type::Furnace: - { - auto obj = (df::building_furnacest*)bld; + { + if (VIRTUAL_CAST_VAR(obj, df::building_furnacest, bld)) obj->melt_remainder.resize(df::inorganic_raw::get_vector().size(), 0); - break; - } + break; + } case building_type::Coffin: - { - auto obj = (df::building_coffinst*)bld; + { + if (VIRTUAL_CAST_VAR(obj, df::building_coffinst, bld)) obj->initBurialFlags(); // DF has this copy&pasted - break; - } + break; + } case building_type::Trap: + { + if (VIRTUAL_CAST_VAR(obj, df::building_trapst, bld)) { - auto obj = (df::building_trapst*)bld; if (obj->trap_type == trap_type::PressurePlate) obj->ready_timeout = 500; - break; } + break; + } + case building_type::Floodgate: + { + if (VIRTUAL_CAST_VAR(obj, df::building_floodgatest, bld)) + obj->gate_flags.bits.closed = true; + break; + } + case building_type::GrateWall: + { + if (VIRTUAL_CAST_VAR(obj, df::building_grate_wallst, bld)) + obj->gate_flags.bits.closed = true; + break; + } + case building_type::GrateFloor: + { + if (VIRTUAL_CAST_VAR(obj, df::building_grate_floorst, bld)) + obj->gate_flags.bits.closed = true; + break; + } + case building_type::BarsVertical: + { + if (VIRTUAL_CAST_VAR(obj, df::building_bars_verticalst, bld)) + obj->gate_flags.bits.closed = true; + break; + } + case building_type::BarsFloor: + { + if (VIRTUAL_CAST_VAR(obj, df::building_bars_floorst, bld)) + obj->gate_flags.bits.closed = true; + break; + } default: break; } diff --git a/plugins/buildingplan-lib.cpp b/plugins/buildingplan-lib.cpp index c933ce11b..93efd60f6 100644 --- a/plugins/buildingplan-lib.cpp +++ b/plugins/buildingplan-lib.cpp @@ -241,13 +241,13 @@ void ViewscreenChooseMaterial::render() int32_t y = gps->dimy - 3; int32_t x = 2; - OutputHotkeyString(x, y, "Toggle", "Enter"); + OutputHotkeyString(x, y, "Toggle", interface_key::SELECT); x += 3; - OutputHotkeyString(x, y, "Save", "Shift-Enter"); + OutputHotkeyString(x, y, "Save", interface_key::SEC_SELECT); x += 3; - OutputHotkeyString(x, y, "Clear", "C"); + OutputHotkeyString(x, y, "Clear", interface_key::CUSTOM_SHIFT_C); x += 3; - OutputHotkeyString(x, y, "Cancel", "Esc"); + OutputHotkeyString(x, y, "Cancel", interface_key::LEAVESCREEN); } // START Room Reservation @@ -538,13 +538,12 @@ void Planner::initialize() add_building_type(Chair, CHAIR); add_building_type(Coffin, COFFIN); add_building_type(Door, DOOR); - // add_building_type(Floodgate, FLOODGATE); not displayed before or after being built + add_building_type(Floodgate, FLOODGATE); add_building_type(Hatch, HATCH_COVER); - // not displayed before or after being built: - // add_building_type(GrateWall, GRATE); - // add_building_type(GrateFloor, GRATE); - // add_building_type(BarsVertical, BAR); - // add_building_type(BarsFloor, BAR); + add_building_type(GrateWall, GRATE); + add_building_type(GrateFloor, GRATE); + add_building_type(BarsVertical, BAR); + add_building_type(BarsFloor, BAR); add_building_type(Cabinet, CABINET); add_building_type(Box, BOX); // skip kennels, farm plot diff --git a/plugins/ruby/building.rb b/plugins/ruby/building.rb index 492d5249d..7a85e9314 100644 --- a/plugins/ruby/building.rb +++ b/plugins/ruby/building.rb @@ -57,10 +57,15 @@ module DFHack bld.setSubtype(subtype) bld.setCustomType(custom) case type + when :Well; bld.bucket_z = bld.z when :Furnace; bld.melt_remainder[world.raws.inorganics.length] = 0 when :Coffin; bld.initBurialFlags - when :Trap; bld.unk_cc = 500 if bld.trap_type == :PressurePlate + when :Trap; bld.ready_timeout = 500 if bld.trap_type == :PressurePlate when :Floodgate; bld.gate_flags.closed = true + when :GrateWall; bld.gate_flags.closed = true + when :GrateFloor; bld.gate_flags.closed = true + when :BarsVertical; bld.gate_flags.closed = true + when :BarsFloor; bld.gate_flags.closed = true end bld end