From 2882422a3e3cfe253c8902006d97dea082ed220a Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 9 Nov 2015 22:58:46 -0500 Subject: [PATCH 001/222] Don't require short script help to start with a space Ref #742 --- library/Core.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 130ec222d..63357b145 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -261,7 +261,12 @@ static std::string getScriptHelp(std::string path, std::string helpprefix) std::string help; if (getline(script, help) && help.substr(0,helpprefix.length()) == helpprefix) - return help.substr(helpprefix.length()); + { + help = help.substr(helpprefix.length()); + while (help.size() && help[0] == ' ') + help = help.substr(1); + return help; + } } return "No help available."; @@ -276,13 +281,13 @@ static void listScripts(PluginManager *plug_mgr, std::map &pset, { if (hasEnding(files[i], ".lua")) { - std::string help = getScriptHelp(path + files[i], "-- "); + std::string help = getScriptHelp(path + files[i], "--"); pset[prefix + files[i].substr(0, files[i].size()-4)] = help; } else if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() && hasEnding(files[i], ".rb")) { - std::string help = getScriptHelp(path + files[i], "# "); + std::string help = getScriptHelp(path + files[i], "#"); pset[prefix + files[i].substr(0, files[i].size()-3)] = help; } @@ -649,14 +654,14 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v } string file = findScript(parts[0] + ".lua"); if ( file != "" ) { - string help = getScriptHelp(file, "-- "); + string help = getScriptHelp(file, "--"); con.print("%s: %s\n", parts[0].c_str(), help.c_str()); return CR_OK; } if (plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) { file = findScript(parts[0] + ".rb"); if ( file != "" ) { - string help = getScriptHelp(file, "# "); + string help = getScriptHelp(file, "#"); con.print("%s: %s\n", parts[0].c_str(), help.c_str()); return CR_OK; } From e209e3937aa35f47066db2a5c605bf78831cdcca Mon Sep 17 00:00:00 2001 From: Sebastian Wolfertz Date: Tue, 10 Nov 2015 07:50:38 +0100 Subject: [PATCH 002/222] Typo Restrictliquid fixed restrictliquid is actually restrictliquids. This time with lengthened underline for sphinx. --- docs/Plugins.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 0cd16a075..a171ea598 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1494,7 +1494,7 @@ The only undo option is to restore your save from backup. alltraffic ========== Set traffic designations for every single tile of the map - useful for resetting -traffic designations. See also `filltraffic`, `restrictice`, and `restrictliquid`. +traffic designations. See also `filltraffic`, `restrictice`, and `restrictliquids`. Options: @@ -1813,7 +1813,7 @@ Options: filltraffic =========== Set traffic designations using flood-fill starting at the cursor. -See also `alltraffic`, `restrictice`, and `restrictliquid`. Options: +See also `alltraffic`, `restrictice`, and `restrictliquids`. Options: :H: High Traffic :N: Normal Traffic @@ -1998,12 +1998,12 @@ Regrows all the grass. Not much to it ;) restrictice =========== Restrict traffic on all tiles on top of visible ice. -See also `alltraffic`, `filltraffic`, and `restrictliquid`. +See also `alltraffic`, `filltraffic`, and `restrictliquids`. -.. _restrictliquid: +.. _restrictliquids: -restrictliquid -============== +restrictliquids +=============== Restrict traffic on all visible tiles with liquid. See also `alltraffic`, `filltraffic`, and `restrictice`. From 72adb904f6bd0a64488865e255ce63b60d53b1c2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 10 Nov 2015 16:57:38 -0500 Subject: [PATCH 003/222] Document multilib packages --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index f4655d8bf..173783a90 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -70,7 +70,7 @@ You should be able to find them in your distro repositories. * On Arch linux, ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) * On 64-bit Ubuntu, ``apt-get install zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl``. -* On 32-bit Ubuntu, ``apt-get install zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. +* On 32-bit Ubuntu, ``apt-get install gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. * Debian-derived distros should have similar requirements. To build Stonesense, you'll also need OpenGL headers. From 07839c511ace37979e90ccb5ba0d254d2180bdb3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 10 Nov 2015 17:00:49 -0500 Subject: [PATCH 004/222] Update CMakeLists.txt * Require Git * Only complain about Sphinx if BUILD_DOCS is enabled * Just issue a warning for GCC >= 5.x on Linux --- CMakeLists.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6228a9e1..8e24db16e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,11 @@ macro(CHECK_GCC COMPILER_PATH) execute_process(COMMAND ${COMPILER_PATH} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) if (${GCC_VERSION_OUT} VERSION_LESS "4.5" OR ${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") - message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 through 4.9") + if ((LINUX) AND (${GCC_VERSION_OUT} VERSION_GREATER "5.0")) + message(WARNING "You are using GCC ${GCC_VERSION_OUT}, which is not recommended - see Compile.rst for more information.") + else() + message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 through 4.9") + endif() endif() endmacro() @@ -176,9 +180,9 @@ include_directories(${ZLIB_INCLUDE_DIRS}) include_directories(depends/clsocket/src) add_subdirectory(depends) -find_package(Git) +find_package(Git REQUIRED) if(NOT GIT_FOUND) - message(FATAL_ERROR "could not find git") + message(SEND_ERROR "could not find git") endif() # build the lib itself @@ -196,7 +200,7 @@ endif() add_subdirectory(scripts) -find_package(Sphinx) +find_package(Sphinx QUIET) if (BUILD_DOCS) if (NOT SPHINX_FOUND) message(SEND_ERROR "Sphinx not found but BUILD_DOCS enabled") From 7663a9a7a7c8408f75253f261f250ff95584ed3e Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 10 Nov 2015 17:24:10 -0500 Subject: [PATCH 005/222] confirm haul-delete: Additional UI state restrictions Fixes #744 --- plugins/confirm.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index 73d92b894..a2cd8f050 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -323,7 +323,12 @@ class hauling_route_delete_confirmation : public confirmationmain.mode == ui_sidebar_mode::Hauling && ui->hauling.view_routes.size()) + if (ui->main.mode == ui_sidebar_mode::Hauling && + ui->hauling.view_routes.size() && + !ui->hauling.in_name && + !ui->hauling.in_stop && + !ui->hauling.in_assign_vehicle + ) return key == df::interface_key::D_HAULING_REMOVE; return false; } From 583ee40cba0da74ff080d37dd50e075229044829 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 10 Nov 2015 17:26:01 -0500 Subject: [PATCH 006/222] Update NEWS.rst --- NEWS.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index fb16ab3f8..8bec5b809 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -29,6 +29,12 @@ Changelog .. contents:: :depth: 2 +DFHack future +============= + +Fixes +----- +- confirm haul-delete: Fixed issue preventing deletion of stop conditions or using "x" in route names DFHack 0.40.24-r4 ================= From 9c62ff1d7f2a1f3983ab835c9813ef83724c3a0f Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 10 Nov 2015 18:43:34 -0500 Subject: [PATCH 007/222] Blacklist GCC 5 on Linux again GCC 5 mangles some symbols, such as "plugin_globals" -> "plugin_globals[abi:c++11]" (or "_Z14plugin_globalsB5cxx11"), even when declared with 'extern "C"'. This breaks plugins, in particular. --- CMakeLists.txt | 6 +----- docs/Compile.rst | 15 +++++++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e24db16e..cbbbd9727 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,11 +25,7 @@ macro(CHECK_GCC COMPILER_PATH) execute_process(COMMAND ${COMPILER_PATH} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) if (${GCC_VERSION_OUT} VERSION_LESS "4.5" OR ${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") - if ((LINUX) AND (${GCC_VERSION_OUT} VERSION_GREATER "5.0")) - message(WARNING "You are using GCC ${GCC_VERSION_OUT}, which is not recommended - see Compile.rst for more information.") - else() - message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 through 4.9") - endif() + message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 through 4.9") endif() endmacro() diff --git a/docs/Compile.rst b/docs/Compile.rst index 173783a90..6b0cf6857 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -53,12 +53,15 @@ DFHack is meant to be installed into an existing DF folder, so get one ready. We assume that any Linux platform will have ``git`` available. -To build DFHack you need a 32-bit version of GCC. GCC 4.5 is easiest to work -with due to avoiding libstdc++ issues (see below), but any later 4.x version -should work as well. GCC 5.x may work but is discouraged for releases because it -won't work on systems without GCC 5.x installed. On 64-bit distributions, you'll -need the multilib development tools and libraries (``gcc-multilib`` or -``gcc-4.x-multilib`` on Debian). Alternatively, you might be able to use ``lxc`` +To build DFHack you need a version of GCC 4.x capable of compiling for 32-bit +(i386) targets. GCC 4.5 is easiest to work with due to avoiding libstdc++ issues +(see below), but any later 4.x version should work as well. GCC 5.x will not +work due to ABI changes (the entire plugin loading system won't work, for +example). On 64-bit distributions, you'll need the multilib development tools +and libraries (``gcc-multilib`` or ``gcc-4.x-multilib`` on Debian). Note that +installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will +typically *not* work, as it depends on several other 32-bit libraries that +conflict with system libraries. Alternatively, you might be able to use ``lxc`` to :forums:`create a virtual 32-bit environment <139553.msg5435310#msg5435310>`. From e7c3b03adaec30251c9045d3460028739b2a5ac3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 11 Nov 2015 23:00:20 -0500 Subject: [PATCH 008/222] Misc. confirm plugin cleanup This avoids the need to list newly-added classes in multiple places (which could be extended to the search plugin) and gets rid of a few ugly macros, along with a few other minor changes. --- plugins/confirm.cpp | 151 ++++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 70 deletions(-) diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index a2cd8f050..e89a00b94 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -33,48 +33,61 @@ struct conf_wrapper; static std::map confirmations; template -bool in_vector (std::vector &vec, FT item) +inline bool in_vector (std::vector &vec, FT item) { return std::find(vec.begin(), vec.end(), item) != vec.end(); } -#define goods_selected_func(list) \ -static bool list##_goods_selected(df::viewscreen_tradegoodsst *screen) \ -{ \ - for (auto it = screen->list##_selected.begin(); it != screen->list##_selected.end(); ++it) \ - if (*it) return true; \ - return false; \ -} -goods_selected_func(trader); -goods_selected_func(broker); -#undef goods_selected_func +namespace trade { + static bool goods_selected (const std::vector &selected) + { + for (auto it = selected.begin(); it != selected.end(); ++it) + if (*it) + return true; + return false; + } + inline bool trader_goods_selected (df::viewscreen_tradegoodsst *screen) + { + return goods_selected(screen->trader_selected); + } + inline bool broker_goods_selected (df::viewscreen_tradegoodsst *screen) + { + return goods_selected(screen->broker_selected); + } -#define goods_all_selected_func(list) \ -static bool list##_goods_all_selected(df::viewscreen_tradegoodsst *screen) \ -{ \ - for (size_t i = 0; i < screen->list##_selected.size(); ++i) \ - { \ - if (!screen->list##_selected[i]) \ - { \ - std::vector *refs = &screen->list##_items[i]->general_refs; \ - bool in_container = false; \ - for (auto it = refs->begin(); it != refs->end(); ++it) \ - { \ - if (virtual_cast(*it)) \ - { \ - in_container = true; \ - break; \ - } \ - } \ - if (!in_container) \ - return false; \ - } \ - } \ - return true; \ + static bool goods_all_selected(const std::vector &selected, const std::vector &items) \ + { + for (size_t i = 0; i < selected.size(); ++i) + { + if (!selected[i]) + { + // check to see if item is in a container + // (if the container is not selected, it will be detected separately) + std::vector &refs = items[i]->general_refs; + bool in_container = false; + for (auto it = refs.begin(); it != refs.end(); ++it) + { + if (virtual_cast(*it)) + { + in_container = true; + break; + } + } + if (!in_container) + return false; + } + } + return true; + } + inline bool trader_goods_all_selected(df::viewscreen_tradegoodsst *screen) + { + return goods_all_selected(screen->trader_selected, screen->trader_items); + } + inline bool broker_goods_all_selected(df::viewscreen_tradegoodsst *screen) + { + return goods_all_selected(screen->broker_selected, screen->broker_items); + } } -goods_all_selected_func(trader); -goods_all_selected_func(broker); -#undef goods_all_selected_func template class confirmation { @@ -172,6 +185,7 @@ public: } } virtual bool intercept_key (df::interface_key key) = 0; + virtual string get_id() = 0; virtual string get_title() { return "Confirm"; } virtual string get_message() = 0; virtual UIColor get_color() { return COLOR_YELLOW; } @@ -181,9 +195,10 @@ protected: }; struct conf_wrapper { +private: bool enabled; std::set hooks; - +public: conf_wrapper() :enabled(false) {} @@ -203,8 +218,22 @@ struct conf_wrapper { enabled = state; return true; } + inline bool is_enabled() { return enabled; } }; +template +int conf_register(confirmation *c, ...) +{ + conf_wrapper *w = new conf_wrapper; + confirmations[c->get_id()] = w; + va_list args; + va_start(args, c); + while (VMethodInterposeLinkBase *hook = va_arg(args, VMethodInterposeLinkBase*)) + w->add_hook(hook); + va_end(args); + return 0; +} + #define IMPLEMENT_CONFIRMATION_HOOKS(cls) IMPLEMENT_CONFIRMATION_HOOKS_PRIO(cls, 0) #define IMPLEMENT_CONFIRMATION_HOOKS_PRIO(cls, prio) \ static cls cls##_instance; \ @@ -229,7 +258,12 @@ struct cls##_hooks : cls::screen_type { \ }; \ IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, feed, prio); \ IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, render, prio); \ -IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, key_conflict, prio); +IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, key_conflict, prio); \ +static int conf_register_##cls = conf_register(&cls##_instance, \ + &INTERPOSE_HOOK(cls##_hooks, feed), \ + &INTERPOSE_HOOK(cls##_hooks, render), \ + &INTERPOSE_HOOK(cls##_hooks, key_conflict), \ + NULL); class trade_confirmation : public confirmation { public: @@ -241,13 +275,13 @@ public: virtual string get_title() { return "Confirm trade"; } virtual string get_message() { - if (trader_goods_selected(screen) && broker_goods_selected(screen)) + if (trade::trader_goods_selected(screen) && trade::broker_goods_selected(screen)) return "Are you sure you want to trade the selected goods?"; - else if (trader_goods_selected(screen)) + else if (trade::trader_goods_selected(screen)) return "You are not giving any items. This is likely\n" "to irritate the merchants.\n" "Attempt to trade anyway?"; - else if (broker_goods_selected(screen)) + else if (trade::broker_goods_selected(screen)) return "You are not receiving any items. You may want to\n" "offer these items instead or choose items to receive.\n" "Attempt to trade anyway?"; @@ -264,7 +298,7 @@ public: virtual bool intercept_key (df::interface_key key) { return key == df::interface_key::LEAVESCREEN && - (trader_goods_selected(screen) || broker_goods_selected(screen)); + (trade::trader_goods_selected(screen) || trade::broker_goods_selected(screen)); } virtual string get_id() { return "trade-cancel"; } virtual string get_title() { return "Cancel trade"; } @@ -276,7 +310,7 @@ class trade_seize_confirmation : public confirmationin_right_pane && broker_goods_selected(screen) && !broker_goods_all_selected(screen)) + if (screen->in_right_pane && trade::broker_goods_selected(screen) && !trade::broker_goods_all_selected(screen)) return true; - else if (!screen->in_right_pane && trader_goods_selected(screen) && !trader_goods_all_selected(screen)) + else if (!screen->in_right_pane && trade::trader_goods_selected(screen) && !trade::trader_goods_all_selected(screen)) return true; } return false; @@ -403,31 +437,8 @@ public: }; IMPLEMENT_CONFIRMATION_HOOKS(route_delete_confirmation); -#define CHOOK(cls) \ - HOOK_ACTION(cls, render) \ - HOOK_ACTION(cls, feed) \ - HOOK_ACTION(cls, key_conflict) - -#define CHOOKS \ - CHOOK(trade_confirmation) \ - CHOOK(trade_cancel_confirmation) \ - CHOOK(trade_seize_confirmation) \ - CHOOK(trade_offer_confirmation) \ - CHOOK(trade_select_all_confirmation) \ - CHOOK(hauling_route_delete_confirmation) \ - CHOOK(depot_remove_confirmation) \ - CHOOK(squad_disband_confirmation) \ - CHOOK(note_delete_confirmation) \ - CHOOK(route_delete_confirmation) - DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) { -#define HOOK_ACTION(cls, method) \ - if (confirmations.find(cls##_instance.get_id()) == confirmations.end()) \ - confirmations[cls##_instance.get_id()] = new conf_wrapper; \ - confirmations[cls##_instance.get_id()]->add_hook(&INTERPOSE_HOOK(cls##_hooks, method)); - CHOOKS -#undef HOOK_ACTION commands.push_back(PluginCommand( "confirm", "Confirmation dialogs", @@ -485,7 +496,7 @@ command_result df_confirm (color_ostream &out, vector & parameters) out << "Available options: \n"; for (auto it = confirmations.begin(); it != confirmations.end(); ++it) { - out << " " << it->first << ": " << (it->second->enabled ? "enabled" : "disabled") << std::endl; + out << " " << it->first << ": " << (it->second->is_enabled() ? "enabled" : "disabled") << std::endl; } return CR_OK; } From 07a310b0f28cbcdf47cc33220e2f32f9724591d9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 11 Nov 2015 23:14:30 -0500 Subject: [PATCH 009/222] Prevent "confirm squad-disband" from triggering unnecessarily --- plugins/confirm.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index e89a00b94..e3e8308a4 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -405,7 +405,10 @@ class squad_disband_confirmation : public confirmationnum_squads && key == df::interface_key::D_MILITARY_DISBAND_SQUAD; + return screen->page == df::viewscreen_layer_militaryst::T_page::Positions && + screen->num_squads && + !screen->in_rename_alert && + key == df::interface_key::D_MILITARY_DISBAND_SQUAD; } virtual string get_id() { return "squad-disband"; } virtual string get_title() { return "Disband squad"; } From 9273c177c19a080ba4ee7d8df00cd78e31ba86d8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 11 Nov 2015 23:14:58 -0500 Subject: [PATCH 010/222] Add "confirm uniform-delete" --- plugins/confirm.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index e3e8308a4..3b3771956 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -416,6 +416,21 @@ public: }; IMPLEMENT_CONFIRMATION_HOOKS(squad_disband_confirmation); +class uniform_delete_confirmation : public confirmation { +public: + virtual bool intercept_key (df::interface_key key) + { + return screen->page == df::viewscreen_layer_militaryst::T_page::Uniforms && + !screen->equip.uniforms.empty() && + !screen->equip.in_name_uniform && + key == df::interface_key::D_MILITARY_DELETE_UNIFORM; + } + virtual string get_id() { return "uniform-delete"; } + virtual string get_title() { return "Delete uniform"; } + virtual string get_message() { return "Are you sure you want to delete this uniform?"; } +}; +IMPLEMENT_CONFIRMATION_HOOKS(uniform_delete_confirmation); + class note_delete_confirmation : public confirmation { public: virtual bool intercept_key (df::interface_key key) From 875ecf7827aa107a18ce9bf14254d58d8676525e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Nov 2015 21:48:51 -0500 Subject: [PATCH 011/222] Update Core::top_viewscreen before calling state change handlers This was previously done right before SC_VIEWSCREEN_CHANGED events were handled, meaning that code handling earlier events that used top_viewscreen (rather than getCurViewscreen()) could refer to an invalid viewscreen, i.e. in the tick after it was deleted. Fixes #747 --- library/Core.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 63357b145..a932e49e7 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1721,6 +1721,14 @@ void Core::doUpdate(color_ostream &out, bool first_update) screen = screen->child; } + // detect if the viewscreen changed, and trigger events later + bool vs_changed = false; + if (screen != top_viewscreen) + { + top_viewscreen = screen; + vs_changed = true; + } + bool is_load_save = strict_virtual_cast(screen) || strict_virtual_cast(screen) || @@ -1770,12 +1778,8 @@ void Core::doUpdate(color_ostream &out, bool first_update) } } - // detect if the viewscreen changed - if (screen != top_viewscreen) - { - top_viewscreen = screen; + if (vs_changed) onStateChange(out, SC_VIEWSCREEN_CHANGED); - } if (df::global::pause_state) { From 928bcb6d95d29be41b52872df9e0ee83aa4ad238 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 15 Nov 2015 11:15:05 -0500 Subject: [PATCH 012/222] military search: Don't try to pass selection in empty list to DF Fixes #748 --- plugins/search.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/search.cpp b/plugins/search.cpp index 6d12e922c..f5b10f156 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -1327,12 +1327,15 @@ public: { // About to make an assignment, so restore original list (it will be changed by the game) int32_t *cursor = get_viewscreen_cursor(); - df::unit *selected_unit = get_primary_list()->at(*cursor); + auto list = get_primary_list(); + if (*cursor >= list->size()) + return false; + df::unit *selected_unit = list->at(*cursor); clear_search(); - for (*cursor = 0; *cursor < get_primary_list()->size(); (*cursor)++) + for (*cursor = 0; *cursor < list->size(); (*cursor)++) { - if (get_primary_list()->at(*cursor) == selected_unit) + if (list->at(*cursor) == selected_unit) break; } From fff9072b0736d94d81648856179d953f5c2061f8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 13 Nov 2015 20:10:29 -0500 Subject: [PATCH 013/222] Add initial support for hooking into Gui-related functions --- library/CMakeLists.txt | 1 + library/include/modules/GuiHooks.h | 67 ++++++++++++++++++++ library/include/modules/Screen.h | 7 +++ library/modules/Screen.cpp | 24 +++++--- plugins/devel/CMakeLists.txt | 1 + plugins/devel/color-dfhack-text.cpp | 96 +++++++++++++++++++++++++++++ 6 files changed, 187 insertions(+), 9 deletions(-) create mode 100644 library/include/modules/GuiHooks.h create mode 100644 plugins/devel/color-dfhack-text.cpp diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 3cd415780..206badeb0 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -119,6 +119,7 @@ include/modules/Units.h include/modules/Engravings.h include/modules/EventManager.h include/modules/Gui.h +include/modules/GuiHooks.h include/modules/Items.h include/modules/Job.h include/modules/kitchen.h diff --git a/library/include/modules/GuiHooks.h b/library/include/modules/GuiHooks.h new file mode 100644 index 000000000..c9a68d92f --- /dev/null +++ b/library/include/modules/GuiHooks.h @@ -0,0 +1,67 @@ +#pragma once +#include +namespace DFHack { + #define GUI_HOOK_DECLARE(name, rtype, args) DFHACK_EXPORT extern DFHack::GuiHooks::Hook name + #define GUI_HOOK_DEFINE(name, base_func) DFHack::GuiHooks::Hook name(base_func) + #define GUI_HOOK_TOP(name) name.top() + #define GUI_HOOK_CALLBACK(hook, name, callback) DFHack::GuiHooks::Hook::Callback name(&hook, callback) + namespace GuiHooks { + template + class Hook { + typedef Hook T_hook; + friend class Callback; + T_func *base_func; + std::vector funcs; + void add(T_func *func) + { + if (std::find(funcs.begin(), funcs.end(), func) == funcs.end()) + funcs.push_back(func); + } + void remove(T_func *func) + { + auto it = std::find(funcs.begin(), funcs.end(), func); + if (it != funcs.end()) + funcs.erase(it); + } + public: + Hook(T_func* base) : base_func(base) + { } + T_func* top() + { + return funcs.empty() ? base_func : funcs[funcs.size() - 1]; + } + T_func* next(T_func* cur) + { + if (funcs.size()) + { + auto it = std::find(funcs.begin(), funcs.end(), cur); + if (it != funcs.end() && it != funcs.begin()) + return *(it - 1); + } + return base_func; + } + + class Callback { + T_func *func; + T_hook *hook; + public: + Callback(T_hook *hook, T_func *func) : hook(hook), func(func) + { } + ~Callback() + { + disable(); + } + inline T_func *next() { return hook->next(func); } + void apply (bool enable) + { + if (enable) + hook->add(func); + else + hook->remove(func); + } + inline void enable() { apply(true); } + inline void disable() { apply(false); } + }; + }; + } +} diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index ab032c4e3..389becbfe 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -36,6 +36,8 @@ distribution. #include "df/graphic.h" #include "df/viewscreen.h" +#include "modules/GuiHooks.h" + namespace df { struct job; @@ -288,6 +290,11 @@ namespace DFHack private: void do_paint_string(const std::string &str, const Pen &pen); }; + + namespace Hooks { + GUI_HOOK_DECLARE(set_tile, void, (const Pen &pen, int x, int y, bool map)); + } + } class DFHACK_EXPORT dfhack_viewscreen : public df::viewscreen { diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 517414766..2d9408aeb 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -32,6 +32,7 @@ distribution. using namespace std; #include "modules/Screen.h" +#include "modules/GuiHooks.h" #include "MemAccess.h" #include "VersionInfo.h" #include "Types.h" @@ -93,8 +94,9 @@ bool Screen::inGraphicsMode() return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS); } -static void doSetTile(const Pen &pen, int index) +static void real_doSetTile(const Pen &pen, int x, int y, bool map) { + int index = ((x * gps->dimy) + y); auto screen = gps->screen + index*4; screen[0] = uint8_t(pen.ch); screen[1] = uint8_t(pen.fg) & 15; @@ -107,6 +109,12 @@ static void doSetTile(const Pen &pen, int index) gps->screentexpos_cbr[index] = pen.tile_bg; } +GUI_HOOK_DEFINE(Screen::Hooks::set_tile, real_doSetTile); +static void doSetTile(const Pen &pen, int x, int y, bool map) +{ + GUI_HOOK_TOP(Screen::Hooks::set_tile)(pen, x, y, map); +} + bool Screen::paintTile(const Pen &pen, int x, int y) { if (!gps || !pen.valid()) return false; @@ -114,7 +122,7 @@ bool Screen::paintTile(const Pen &pen, int x, int y) auto dim = getWindowSize(); if (x < 0 || x >= dim.x || y < 0 || y >= dim.y) return false; - doSetTile(pen, x*dim.y + y); + doSetTile(pen, x, y, false); return true; } @@ -188,10 +196,8 @@ bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2) for (int x = x1; x <= x2; x++) { - int index = x*dim.y; - for (int y = y1; y <= y2; y++) - doSetTile(pen, index+y); + doSetTile(pen, x, y, false); } return true; @@ -208,13 +214,13 @@ bool Screen::drawBorder(const std::string &title) for (int x = 0; x < dim.x; x++) { - doSetTile(border, x * dim.y + 0); - doSetTile(border, x * dim.y + dim.y - 1); + doSetTile(border, x, 0, false); + doSetTile(border, x, dim.y - 1, false); } for (int y = 0; y < dim.y; y++) { - doSetTile(border, 0 * dim.y + y); - doSetTile(border, (dim.x - 1) * dim.y + y); + doSetTile(border, 0, y, false); + doSetTile(border, dim.x - 1, dim.y + y, false); } paintString(signature, dim.x-8, dim.y-1, "DFHack"); diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index 79bf55ff6..1f3ff6f75 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -5,6 +5,7 @@ endif() ADD_DEFINITIONS(-DDEV_PLUGIN) #DFHACK_PLUGIN(autolabor2 autolabor2.cpp) DFHACK_PLUGIN(buildprobe buildprobe.cpp) +DFHACK_PLUGIN(color-dfhack-text color-dfhack-text.cpp) DFHACK_PLUGIN(counters counters.cpp) DFHACK_PLUGIN(dumpmats dumpmats.cpp) DFHACK_PLUGIN(eventExample eventExample.cpp) diff --git a/plugins/devel/color-dfhack-text.cpp b/plugins/devel/color-dfhack-text.cpp new file mode 100644 index 000000000..45147fba6 --- /dev/null +++ b/plugins/devel/color-dfhack-text.cpp @@ -0,0 +1,96 @@ +#include "Console.h" +#include "Core.h" +#include "DataDefs.h" +#include "Export.h" +#include "PluginManager.h" + +#include "modules/Screen.h" + +using namespace DFHack; + +DFHACK_PLUGIN("color-dfhack-text"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +struct { + bool flicker; + uint8_t color; + short tick; +} config; + +void color_text_tile(const Screen::Pen &pen, int x, int y, bool map); +GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, color_text_hook, color_text_tile); +void color_text_tile(const Screen::Pen &pen, int x, int y, bool map) +{ + Screen::Pen pen2 = pen; + uint8_t color = config.flicker ? config.tick % 8 : config.color; + pen2.fg = color; + pen2.bg = color; + pen2.bold = true; + return color_text_hook.next()(pen2, x, y, map); +} + +DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) +{ + color_text_hook.apply(enable); + is_enabled = enable; + return CR_OK; +} + +command_result color(color_ostream &out, std::vector ¶ms) +{ + plugin_enable(out, true); + std::string p0 = toLower(params[0]); +#define CHECK_COLOR(color_name) else if (p0 == toLower(std::string(#color_name))) \ + { config.flicker = false; config.color = COLOR_##color_name % 8; } + if (params.empty()) + return CR_OK; + CHECK_COLOR(RED) + CHECK_COLOR(GREEN) + CHECK_COLOR(BLUE) + CHECK_COLOR(YELLOW) + CHECK_COLOR(BROWN) + CHECK_COLOR(CYAN) + CHECK_COLOR(MAGENTA) + CHECK_COLOR(WHITE) + CHECK_COLOR(GREY) + CHECK_COLOR(BLACK) +#undef CHECK_COLOR + else if (p0 == "flicker") + { + config.flicker = true; + } + else if (p0 == "disable") + { + plugin_enable(out, false); + } + else if (p0 != "enable") + { + out.printerr("Unrecognized option: %s\n", p0.c_str()); + return CR_WRONG_USAGE; + } + return CR_OK; +} + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + commands.push_back(PluginCommand( + "color-dfhack-text", + "color |flicker|enable|disable", + color, + false + )); + config.flicker = false; + config.color = COLOR_RED; + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown (color_ostream &out) +{ + return CR_OK; +} + +DFhackCExport command_result plugin_onupdate (color_ostream &out) +{ + ++config.tick; + return CR_OK; +} From fcfffd1cb60ac2a3c0efce27f866675b7fbe83fb Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Nov 2015 13:03:38 -0500 Subject: [PATCH 014/222] Track state of gui hooks Also fix a bug in drawborder() and expand color-dfhack-text to test multiple hooks --- library/include/modules/GuiHooks.h | 4 ++ library/modules/Screen.cpp | 2 +- plugins/devel/color-dfhack-text.cpp | 95 ++++++++++++++++++++--------- 3 files changed, 72 insertions(+), 29 deletions(-) diff --git a/library/include/modules/GuiHooks.h b/library/include/modules/GuiHooks.h index c9a68d92f..62f412961 100644 --- a/library/include/modules/GuiHooks.h +++ b/library/include/modules/GuiHooks.h @@ -44,6 +44,7 @@ namespace DFHack { class Callback { T_func *func; T_hook *hook; + bool enabled; public: Callback(T_hook *hook, T_func *func) : hook(hook), func(func) { } @@ -58,9 +59,12 @@ namespace DFHack { hook->add(func); else hook->remove(func); + enabled = enable; } inline void enable() { apply(true); } inline void disable() { apply(false); } + inline bool is_enabled() { return enabled; } + inline void toggle() { apply(!enabled); } }; }; } diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 2d9408aeb..307da11cf 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -220,7 +220,7 @@ bool Screen::drawBorder(const std::string &title) for (int y = 0; y < dim.y; y++) { doSetTile(border, 0, y, false); - doSetTile(border, dim.x - 1, dim.y + y, false); + doSetTile(border, dim.x - 1, y, false); } paintString(signature, dim.x-8, dim.y-1, "DFHack"); diff --git a/plugins/devel/color-dfhack-text.cpp b/plugins/devel/color-dfhack-text.cpp index 45147fba6..70dcb130f 100644 --- a/plugins/devel/color-dfhack-text.cpp +++ b/plugins/devel/color-dfhack-text.cpp @@ -10,6 +10,7 @@ using namespace DFHack; DFHACK_PLUGIN("color-dfhack-text"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); +REQUIRE_GLOBAL(gps); struct { bool flicker; @@ -29,44 +30,82 @@ void color_text_tile(const Screen::Pen &pen, int x, int y, bool map) return color_text_hook.next()(pen2, x, y, map); } +void aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map); +GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, aaaaa_set_tile_hook, aaaaa_set_tile); +void aaaaa_set_tile(const Screen::Pen &pen, int x, int y, bool map) +{ + Screen::Pen pen2 = pen; + if ((pen.ch >= 'A' && pen.ch <= 'Z') || (pen.ch >= '0' && pen.ch <= '9')) + pen2.ch = 'A'; + else if (pen.ch >= 'a' && pen.ch <= 'z') + pen2.ch = 'a'; + aaaaa_set_tile_hook.next()(pen2, x, y, map); +} + +void shift_set_tile(const Screen::Pen &pen, int x, int y, bool map); +GUI_HOOK_CALLBACK(Screen::Hooks::set_tile, shift_set_tile_hook, shift_set_tile); +void shift_set_tile(const Screen::Pen &pen, int x, int y, bool map) +{ + x = (x + 1) % gps->dimx; + shift_set_tile_hook.next()(pen, x, y, map); +} + DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) { color_text_hook.apply(enable); + if (!enable) + { + shift_set_tile_hook.disable(); + aaaaa_set_tile_hook.disable(); + } is_enabled = enable; return CR_OK; } command_result color(color_ostream &out, std::vector ¶ms) { - plugin_enable(out, true); - std::string p0 = toLower(params[0]); -#define CHECK_COLOR(color_name) else if (p0 == toLower(std::string(#color_name))) \ - { config.flicker = false; config.color = COLOR_##color_name % 8; } if (params.empty()) - return CR_OK; - CHECK_COLOR(RED) - CHECK_COLOR(GREEN) - CHECK_COLOR(BLUE) - CHECK_COLOR(YELLOW) - CHECK_COLOR(BROWN) - CHECK_COLOR(CYAN) - CHECK_COLOR(MAGENTA) - CHECK_COLOR(WHITE) - CHECK_COLOR(GREY) - CHECK_COLOR(BLACK) -#undef CHECK_COLOR - else if (p0 == "flicker") - { - config.flicker = true; - } - else if (p0 == "disable") - { - plugin_enable(out, false); - } - else if (p0 != "enable") + return plugin_enable(out, true); + for (auto it = params.begin(); it != params.end(); ++it) { - out.printerr("Unrecognized option: %s\n", p0.c_str()); - return CR_WRONG_USAGE; + std::string p = toLower(*it); + if (!p.size()) + continue; + #define CHECK_COLOR(color_name) else if (p == toLower(std::string(#color_name))) \ + { config.flicker = false; config.color = COLOR_##color_name % 8; plugin_enable(out, true); } + CHECK_COLOR(RED) + CHECK_COLOR(GREEN) + CHECK_COLOR(BLUE) + CHECK_COLOR(YELLOW) + CHECK_COLOR(BROWN) + CHECK_COLOR(CYAN) + CHECK_COLOR(MAGENTA) + CHECK_COLOR(WHITE) + CHECK_COLOR(GREY) + CHECK_COLOR(BLACK) + #undef CHECK_COLOR + else if (p == "flicker") + { + config.flicker = true; + plugin_enable(out, true); + } + else if (p.size() >= 3 && p.substr(0, 3) == "aaa") + { + aaaaa_set_tile_hook.toggle(); + } + else if (p == "shift") + { + shift_set_tile_hook.toggle(); + } + else if (p == "disable") + { + plugin_enable(out, false); + } + else if (p != "enable") + { + out.printerr("Unrecognized option: %s\n", p.c_str()); + return CR_WRONG_USAGE; + } } return CR_OK; } @@ -75,7 +114,7 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector |flicker|enable|disable", + "color |flicker|enable|disable|shift|aaaaa", color, false )); From 1ff9277e129ee21836a2a30d67756a00233367df Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Nov 2015 13:25:01 -0500 Subject: [PATCH 015/222] Remove plugin export functionality (unused) --- library/PluginManager.cpp | 34 --------------------------------- library/include/PluginManager.h | 23 ---------------------- 2 files changed, 57 deletions(-) diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index af0375963..2dad07797 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -353,7 +353,6 @@ bool Plugin::load(color_ostream &con) plugin_enable = (command_result (*)(color_ostream &,bool)) LookupPlugin(plug, "plugin_enable"); plugin_is_enabled = (bool*) LookupPlugin(plug, "plugin_is_enabled"); plugin_eval_ruby = (command_result (*)(color_ostream &, const char*)) LookupPlugin(plug, "plugin_eval_ruby"); - plugin_get_exports = (PluginExports* (*)(void)) LookupPlugin(plug, "plugin_get_exports"); index_lua(plug); plugin_lib = plug; commands.clear(); @@ -611,16 +610,6 @@ Plugin::plugin_state Plugin::getState() const return state; } -PluginExports *Plugin::getExports() -{ - if (!plugin_get_exports) - return NULL; - PluginExports *exports = plugin_get_exports(); - if (!exports->bind(plugin_lib)) - return NULL; - return exports; -}; - void Plugin::index_lua(DFLibrary *lib) { if (auto cmdlist = (CommandReg*)LookupPlugin(lib, "plugin_lua_commands")) @@ -793,19 +782,6 @@ void Plugin::push_function(lua_State *state, LuaFunction *fn) lua_pushcclosure(state, lua_fun_wrapper, 4); } -bool PluginExports::bind(DFLibrary *lib) -{ - for (auto it = bindings.begin(); it != bindings.end(); ++it) - { - std::string name = it->first; - void** dest = it->second; - *dest = LookupPlugin(lib, name.c_str()); - if (!*dest) - return false; - } - return true; -} - PluginManager::PluginManager(Core * core) : core(core) { plugin_mutex = new recursive_mutex(); @@ -960,16 +936,6 @@ Plugin *PluginManager::getPluginByCommand(const std::string &command) return NULL; } -void *PluginManager::getPluginExports(const std::string &name) -{ - Plugin *plug = getPluginByName(name); - if (!plug) - return NULL; - if (plug->getState() != Plugin::plugin_state::PS_LOADED) - return NULL; - return plug->getExports(); -} - // FIXME: handle name collisions... command_result PluginManager::InvokeCommand(color_ostream &out, const std::string & command, std::vector & parameters) { diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index aba6aaa0f..42bebb2d3 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -50,7 +50,6 @@ namespace df namespace DFHack { class Core; - class PluginExports; class PluginManager; class virtual_identity; class RPCService; @@ -170,7 +169,6 @@ namespace DFHack command_result invoke(color_ostream &out, const std::string & command, std::vector & parameters); bool can_invoke_hotkey(const std::string & command, df::viewscreen *top ); plugin_state getState () const; - PluginExports *getExports(); RPCService *rpc_connect(color_ostream &out); @@ -237,16 +235,7 @@ namespace DFHack command_result (*plugin_enable)(color_ostream &, bool); RPCService* (*plugin_rpcconnect)(color_ostream &); command_result (*plugin_eval_ruby)(color_ostream &, const char*); - PluginExports* (*plugin_get_exports)(void); }; - class DFHACK_EXPORT PluginExports { - protected: - friend class Plugin; - std::map bindings; - bool bind(DFLibrary* lib); - }; - #define PLUGIN_EXPORT_BIND(sym) bindings.insert(std::pair(#sym, (void**)&this->sym)) - #define PLUGIN_EXPORT_BINDN(sym, name) bindings.insert(std::pair(name, (void**)&this->sym)) class DFHACK_EXPORT PluginManager { // PRIVATE METHODS @@ -275,7 +264,6 @@ namespace DFHack Plugin *getPluginByName (const std::string &name) { return (*this)[name]; } Plugin *getPluginByCommand (const std::string &command); - void *getPluginExports(const std::string &name); command_result InvokeCommand(color_ostream &out, const std::string & command, std::vector & parameters); bool CanInvokeHotkey(const std::string &command, df::viewscreen *top); Plugin* operator[] (const std::string name); @@ -324,17 +312,6 @@ namespace DFHack DFhackDataExport bool plugin_is_enabled = false; \ bool &varname = plugin_is_enabled; -#define DFHACK_PLUGIN_EXPORTS(clsname) \ - DFhackCExport PluginExports* plugin_get_exports() \ - { \ - static clsname* instance = NULL; \ - if (!instance) \ - instance = new clsname; \ - return (PluginExports*)instance; \ - } -#define GET_PLUGIN_EXPORTS(plugname, clsname) \ - (clsname*)DFHack::Core::getInstance().getPluginManager()->getPluginExports(plugname) - #define DFHACK_PLUGIN_LUA_COMMANDS \ DFhackCExport const DFHack::CommandReg plugin_lua_commands[] = #define DFHACK_PLUGIN_LUA_FUNCTIONS \ From 610170b0b01edc7818cb9fd4bde0dc535c601e8e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Nov 2015 14:14:32 -0500 Subject: [PATCH 016/222] Add hooks for getDwarfmodeViewDims and getDepthAt (new) --- library/include/modules/Gui.h | 11 +++++++++++ library/modules/Gui.cpp | 21 +++++++++++++++++++-- library/modules/Screen.cpp | 4 ++-- plugins/devel/color-dfhack-text.cpp | 1 + plugins/mousequery.cpp | 2 +- 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 645a0fac2..effa7347e 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -38,6 +38,8 @@ distribution. #include "df/announcement_flags.h" #include "df/unit_report_type.h" +#include "modules/GuiHooks.h" + namespace df { struct viewscreen; struct job; @@ -150,6 +152,10 @@ namespace DFHack DFHACK_EXPORT bool setDesignationCoords (const int32_t x, const int32_t y, const int32_t z); DFHACK_EXPORT bool getMousePos (int32_t & x, int32_t & y); + + // The distance from the z-level of the tile at map coordinates (x, y) to the closest ground z-level below + // Defaults to 0, unless overriden by plugins + DFHACK_EXPORT int getDepthAt (int32_t x, int32_t y); /* * Gui screens */ @@ -183,5 +189,10 @@ namespace DFHack DFHACK_EXPORT bool getMenuWidth(uint8_t & menu_width, uint8_t & area_map_width); DFHACK_EXPORT bool setMenuWidth(const uint8_t menu_width, const uint8_t area_map_width); + + namespace Hooks { + GUI_HOOK_DECLARE(depth_at, int, (int32_t x, int32_t y)); + GUI_HOOK_DECLARE(dwarfmode_view_dims, DwarfmodeDims, ()); + } } } diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 0a17bbac8..8de672ec6 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1358,9 +1358,9 @@ df::coord Gui::getCursorPos() return df::coord(cursor->x, cursor->y, cursor->z); } -Gui::DwarfmodeDims Gui::getDwarfmodeViewDims() +Gui::DwarfmodeDims getDwarfmodeViewDims_default() { - DwarfmodeDims dims; + Gui::DwarfmodeDims dims; auto ws = Screen::getWindowSize(); dims.y1 = 1; @@ -1403,6 +1403,12 @@ Gui::DwarfmodeDims Gui::getDwarfmodeViewDims() return dims; } +GUI_HOOK_DEFINE(Gui::Hooks::dwarfmode_view_dims, getDwarfmodeViewDims_default); +Gui::DwarfmodeDims Gui::getDwarfmodeViewDims() +{ + return GUI_HOOK_TOP(Gui::Hooks::dwarfmode_view_dims)(); +} + void Gui::resetDwarfmodeView(bool pause) { using df::global::cursor; @@ -1524,6 +1530,17 @@ bool Gui::getMousePos (int32_t & x, int32_t & y) return (x == -1) ? false : true; } +int getDepthAt_default (int32_t x, int32_t y) +{ + return 0; +} + +GUI_HOOK_DEFINE(Gui::Hooks::depth_at, getDepthAt_default); +int Gui::getDepthAt (int32_t x, int32_t y) +{ + return GUI_HOOK_TOP(Gui::Hooks::depth_at)(x, y); +} + bool Gui::getWindowSize (int32_t &width, int32_t &height) { if (gps) { diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 307da11cf..c0ced42a2 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -94,7 +94,7 @@ bool Screen::inGraphicsMode() return init && init->display.flag.is_set(init_display_flags::USE_GRAPHICS); } -static void real_doSetTile(const Pen &pen, int x, int y, bool map) +static void doSetTile_default(const Pen &pen, int x, int y, bool map) { int index = ((x * gps->dimy) + y); auto screen = gps->screen + index*4; @@ -109,7 +109,7 @@ static void real_doSetTile(const Pen &pen, int x, int y, bool map) gps->screentexpos_cbr[index] = pen.tile_bg; } -GUI_HOOK_DEFINE(Screen::Hooks::set_tile, real_doSetTile); +GUI_HOOK_DEFINE(Screen::Hooks::set_tile, doSetTile_default); static void doSetTile(const Pen &pen, int x, int y, bool map) { GUI_HOOK_TOP(Screen::Hooks::set_tile)(pen, x, y, map); diff --git a/plugins/devel/color-dfhack-text.cpp b/plugins/devel/color-dfhack-text.cpp index 70dcb130f..761782303 100644 --- a/plugins/devel/color-dfhack-text.cpp +++ b/plugins/devel/color-dfhack-text.cpp @@ -4,6 +4,7 @@ #include "Export.h" #include "PluginManager.h" +#include "modules/Gui.h" #include "modules/Screen.h" using namespace DFHack; diff --git a/plugins/mousequery.cpp b/plugins/mousequery.cpp index b0835832f..389d443cf 100644 --- a/plugins/mousequery.cpp +++ b/plugins/mousequery.cpp @@ -65,7 +65,7 @@ static df::coord get_mouse_pos(int32_t &mx, int32_t &my) pos.x = vx + mx - 1; pos.y = vy + my - 1; - pos.z = vz; + pos.z = vz - Gui::getDepthAt(pos.x, pos.y); return pos; } From 7ea0e198b3b4542cf9dca5d4fb6e27a5b1b6f245 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 15 Nov 2015 23:27:53 -0500 Subject: [PATCH 017/222] fix-unit-occupancy: Only check unit list once Fixes #749 --- plugins/fix-unit-occupancy.cpp | 102 ++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 21 deletions(-) diff --git a/plugins/fix-unit-occupancy.cpp b/plugins/fix-unit-occupancy.cpp index 4675b5cfb..f6a26c669 100644 --- a/plugins/fix-unit-occupancy.cpp +++ b/plugins/fix-unit-occupancy.cpp @@ -4,6 +4,7 @@ #include "Export.h" #include "PluginManager.h" +#include "modules/Maps.h" #include "modules/Units.h" #include "modules/Translation.h" #include "modules/World.h" @@ -49,6 +50,52 @@ df::unit *findUnit(int x, int y, int z) return NULL; } +struct uo_buf { + uint32_t dim_x, dim_y, dim_z; + size_t size; + uint8_t *buf; + uo_buf() : size(0), buf(NULL) + { } + ~uo_buf() + { + if (buf) + free(buf); + } + void resize() + { + Maps::getSize(dim_x, dim_y, dim_z); + dim_x *= 16; + dim_y *= 16; + size = dim_x * dim_y * dim_z; + buf = (uint8_t*)realloc(buf, size); + clear(); + } + inline void clear() + { + memset(buf, 0, size); + } + inline size_t offset (uint32_t x, uint32_t y, uint32_t z) + { + return (dim_x * dim_y * z) + (dim_x * y) + x; + } + inline uint8_t get (uint32_t x, uint32_t y, uint32_t z) + { + return buf[offset(x, y, z)]; + } + inline void set (uint32_t x, uint32_t y, uint32_t z, uint8_t val) + { + buf[offset(x, y, z)] = val; + } + inline void get_coords (size_t off, uint32_t &x, uint32_t &y, uint32_t &z) + { + x = off % dim_x; + y = (off / dim_x) % dim_y; + z = off / (dim_x * dim_y); + } +}; + +static uo_buf uo_buffer; + struct uo_opts { bool dry_run; bool use_cursor; @@ -64,10 +111,21 @@ unsigned fix_unit_occupancy (color_ostream &out, uo_opts &opts) if (!Core::getInstance().isWorldLoaded()) return 0; + if (!World::isFortressMode() && !opts.use_cursor) + { + out.printerr("Can only scan entire map in fortress mode\n"); + return 0; + } + if (opts.use_cursor && cursor->x < 0) + { out.printerr("No cursor\n"); + return 0; + } + uo_buffer.resize(); unsigned count = 0; + float time1 = getClock(); for (size_t i = 0; i < world->map.map_blocks.size(); i++) { @@ -85,33 +143,35 @@ unsigned fix_unit_occupancy (color_ostream &out, uo_opts &opts) int map_y = y + block->map_pos.y; if (opts.use_cursor && (map_x != cursor->x || map_y != cursor->y)) continue; - bool cur_occupancy = block->occupancy[x][y].bits.unit; - bool fixed_occupancy = cur_occupancy; - df::unit *cur_unit = findUnit(map_x, map_y, map_z); - if (cur_occupancy && !cur_unit) - { - out.print("%sFixing occupancy at (%i, %i, %i) - no unit found\n", - opts.dry_run ? "(Dry run) " : "", - map_x, map_y, map_z); - fixed_occupancy = false; - } - // else if (!cur_occupancy && cur_unit) - // { - // out.printerr("Unit found at (%i, %i, %i): %s\n", map_x, map_y, map_z, get_unit_description(cur_unit).c_str()); - // fixed_occupancy = true; - // } - if (cur_occupancy != fixed_occupancy && !opts.dry_run) - { - ++count; - block->occupancy[x][y].bits.unit = fixed_occupancy; - } + if (block->occupancy[x][y].bits.unit) + uo_buffer.set(map_x, map_y, map_z, 1); } } } + + for (auto u = world->units.active.begin(); u != world->units.active.end(); ++u) + uo_buffer.set((**u).pos.x, (**u).pos.y, (**u).pos.z, 0); + + for (size_t i = 0; i < uo_buffer.size; i++) + { + if (uo_buffer.buf[i]) + { + uint32_t x, y, z; + uo_buffer.get_coords(i, x, y, z); + out.print("(%u, %u, %u) - no unit found\n", x, y, z); + ++count; + if (!opts.dry_run) + { + df::map_block *b = Maps::getTileBlock(x, y, z); + b->occupancy[x % 16][y % 16].bits.unit = false; + } + } + } + float time2 = getClock(); std::cerr << "fix-unit-occupancy: elapsed time: " << time2 - time1 << " secs" << endl; if (count) - out << "Fixed occupancy of " << count << " tiles [fix-unit-occupancy]" << endl; + out << (opts.dry_run ? "[dry run] " : "") << "Fixed occupancy of " << count << " tiles [fix-unit-occupancy]" << endl; return count; } From 9c4fc64ac570e701ab15d421599ad9555ecf47fe Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 16 Nov 2015 21:47:29 -0500 Subject: [PATCH 018/222] Fix display issue in tweak max-wheelbarrow --- plugins/tweak/tweaks/max-wheelbarrow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tweak/tweaks/max-wheelbarrow.h b/plugins/tweak/tweaks/max-wheelbarrow.h index b21fe22c1..37f292d6b 100644 --- a/plugins/tweak/tweaks/max-wheelbarrow.h +++ b/plugins/tweak/tweaks/max-wheelbarrow.h @@ -35,7 +35,7 @@ struct max_wheelbarrow_hook : df::viewscreen_dwarfmodest { { auto dims = Gui::getDwarfmodeViewDims(); Screen::paintString(Screen::Pen(' ', COLOR_LIGHTCYAN), - dims.menu_x1 + 22, dims.y1 + 6, wheelbarrow_entry + "_"); + dims.menu_x1 + 22, dims.y1 + 6, wheelbarrow_entry + "_ "); } } From 2ba9ef04e30f42f966aba243c97dfa1135021930 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Tue, 17 Nov 2015 13:55:43 +0930 Subject: [PATCH 019/222] Replace drybuckets plugin with a script Also closes #248, by checking job and building flags. --- NEWS.rst | 4 +++ docs/Plugins.rst | 4 --- plugins/CMakeLists.txt | 1 - plugins/drybuckets.cpp | 52 ------------------------------------- scripts/fix/dry-buckets.lua | 22 ++++++++++++++++ 5 files changed, 26 insertions(+), 57 deletions(-) delete mode 100644 plugins/drybuckets.cpp create mode 100644 scripts/fix/dry-buckets.lua diff --git a/NEWS.rst b/NEWS.rst index 8bec5b809..d3f60beb8 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,6 +36,10 @@ Fixes ----- - confirm haul-delete: Fixed issue preventing deletion of stop conditions or using "x" in route names +New Scripts +----------- +- `fix/dry-buckets`: replaces the ``drybuckets`` plugin + DFHack 0.40.24-r4 ================= diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 0cd16a075..c0c049708 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -182,10 +182,6 @@ Shows all items needed for the currently active strange mood. Bugfixes ======== -drybuckets -========== -Removes water from all buckets in your fortress, allowing them to be used for making lye. - fixdiplomats ============ Adds a Diplomat position to all Elven civilizations, allowing them to negotiate diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 115f6196e..aca7d0996 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -115,7 +115,6 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(dig dig.cpp) DFHACK_PLUGIN(digFlood digFlood.cpp) add_subdirectory(diggingInvaders) - DFHACK_PLUGIN(drybuckets drybuckets.cpp) DFHACK_PLUGIN(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) diff --git a/plugins/drybuckets.cpp b/plugins/drybuckets.cpp deleted file mode 100644 index 711a05928..000000000 --- a/plugins/drybuckets.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Dry Buckets : Remove all "water" objects from buckets scattered around the fortress - -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" - -#include "DataDefs.h" -#include "df/world.h" -#include "df/item.h" -#include "df/builtin_mats.h" - -using std::string; -using std::vector; -using namespace DFHack; -using namespace df::enums; - -DFHACK_PLUGIN("drybuckets"); -REQUIRE_GLOBAL(world); - -command_result df_drybuckets (color_ostream &out, vector & parameters) -{ - if (!parameters.empty()) - return CR_WRONG_USAGE; - - CoreSuspender suspend; - - int dried_total = 0; - for (size_t i = 0; i < world->items.all.size(); i++) - { - df::item *item = world->items.all[i]; - if ((item->getType() == item_type::LIQUID_MISC) && (item->getMaterial() == builtin_mats::WATER)) - { - item->flags.bits.garbage_collect = 1; - dried_total++; - } - } - if (dried_total) - out.print("Done. %d buckets of water marked for emptying.\n", dried_total); - return CR_OK; -} - -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand("drybuckets", "Removes water from buckets.", df_drybuckets)); - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} diff --git a/scripts/fix/dry-buckets.lua b/scripts/fix/dry-buckets.lua new file mode 100644 index 000000000..ddf5302b7 --- /dev/null +++ b/scripts/fix/dry-buckets.lua @@ -0,0 +1,22 @@ +-- Removes water from buckets (for lye-making). +--[[=begin + +fix/dry-buckets +=============== +Removes water from all buckets in your fortress, allowing them +to be used for making lye. Skips buckets in buildings (eg a well), +being carried, or currently used by a job. + +=end]] + +local emptied = 0 +local water_type = dfhack.matinfo.find('WATER').type + +for _,item in ipairs(df.global.world.items.all) do + if item:getMaterial() == water_type and not (item.flags.in_job or item.flags.in_building) then + dfhack.items.remove(item) + emptied = emptied + 1 + end +end + +print('Emptied '..emptied..' buckets.') From 842b9c5191a74e5516662fb96621d62b6f2b978a Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Tue, 17 Nov 2015 16:43:56 +0930 Subject: [PATCH 020/222] Implement feature as a script, add magma option Functionality is exactly equivalent to the plugin, but with a new option for players who want to enable magma furnaces without spoilers. --- NEWS.rst | 5 +- docs/Plugins.rst | 17 ------- plugins/CMakeLists.txt | 1 - plugins/feature.cpp | 113 ----------------------------------------- scripts/feature.lua | 58 +++++++++++++++++++++ 5 files changed, 61 insertions(+), 133 deletions(-) delete mode 100644 plugins/feature.cpp create mode 100644 scripts/feature.lua diff --git a/NEWS.rst b/NEWS.rst index d3f60beb8..76818b14a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,9 +36,10 @@ Fixes ----- - confirm haul-delete: Fixed issue preventing deletion of stop conditions or using "x" in route names -New Scripts ------------ +Misc Improvements +----------------- - `fix/dry-buckets`: replaces the ``drybuckets`` plugin +- `feature`: now implemented by a script DFHack 0.40.24-r4 ================= diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c0c049708..3e806d61c 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1787,23 +1787,6 @@ Usage: :digFlood digAll1: ignore the monitor list and dig any vein :digFlood digAll0: disable digAll mode -.. _feature: - -feature -======= -Enables management of map features. - -* Discovering a magma feature (magma pool, volcano, magma sea, or curious - underground structure) permits magma workshops and furnaces to be built. -* Discovering a cavern layer causes plants (trees, shrubs, and grass) from - that cavern to grow within your fortress. - -Options: - -:list: Lists all map features in your current embark by index. -:show X: Marks the selected map feature as discovered. -:hide X: Marks the selected map feature as undiscovered. - .. _filltraffic: filltraffic diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index aca7d0996..f5c0929e0 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -119,7 +119,6 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(embark-tools embark-tools.cpp) DFHACK_PLUGIN(eventful eventful.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(fastdwarf fastdwarf.cpp) - DFHACK_PLUGIN(feature feature.cpp) DFHACK_PLUGIN(filltraffic filltraffic.cpp) DFHACK_PLUGIN(fix-armory fix-armory.cpp) DFHACK_PLUGIN(fixpositions fixpositions.cpp) diff --git a/plugins/feature.cpp b/plugins/feature.cpp deleted file mode 100644 index 30c71cda2..000000000 --- a/plugins/feature.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// Map feature manager - list features and discover/undiscover individual ones - -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" - -#include "DataDefs.h" -#include "df/world.h" -#include "df/feature_init.h" - -#include - -using std::vector; -using std::string; -using std::endl; -using namespace DFHack; -using namespace df::enums; - -DFHACK_PLUGIN("feature"); -REQUIRE_GLOBAL(world); - - -static command_result feature(color_ostream &out, vector ¶meters) -{ - CoreSuspender suspend; - - if (parameters.empty()) - return CR_WRONG_USAGE; - - string cmd = parameters[0]; - - if (cmd == "list") - { - if (parameters.size() != 1) - return CR_WRONG_USAGE; - for (size_t i = 0; i < world->features.map_features.size(); i++) - { - df::feature_init *feature_init = world->features.map_features[i]; - string name; - feature_init->getName(&name); - out.print("Feature #%i (\"%s\", type %s) is %s\n", - i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str(), - feature_init->flags.is_set(feature_init_flags::Discovered) ? "discovered" : "hidden"); - } - } - else if(cmd == "show") - { - if (parameters.size() != 2) - return CR_WRONG_USAGE; - size_t i = atoi(parameters[1].c_str()); - if ((i < 0) || (i >= world->features.map_features.size())) - { - out.print("No such feature!\n"); - return CR_FAILURE; - } - df::feature_init *feature_init = world->features.map_features[i]; - if (feature_init->flags.is_set(feature_init_flags::Discovered)) - { - out.print("Selected feature is already discovered!\n"); - return CR_OK; - } - feature_init->flags.set(feature_init_flags::Discovered); - string name; - feature_init->getName(&name); - out.print("Feature #%i (\"%s\", type %s) is now discovered\n", - i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str()); - } - else if(cmd == "hide") - { - if (parameters.size() != 2) - return CR_WRONG_USAGE; - size_t i = atoi(parameters[1].c_str()); - if ((i < 0) || (i >= world->features.map_features.size())) - { - out.print("No such feature!\n"); - return CR_FAILURE; - } - df::feature_init *feature_init = world->features.map_features[i]; - if (!feature_init->flags.is_set(feature_init_flags::Discovered)) - { - out.print("Selected feature is already hidden!\n"); - return CR_OK; - } - feature_init->flags.clear(feature_init_flags::Discovered); - string name; - feature_init->getName(&name); - out.print("Feature #%i (\"%s\", type %s) is now hidden\n", - i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str()); - } - else return CR_WRONG_USAGE; - - return CR_OK; -} - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand( - "feature", "List or manage map features.", feature, false, - " feature list\n" - " Lists all map features in the region.\n" - " feature show \n" - " Marks the specified map feature as discovered.\n" - " feature hide \n" - " Marks the specified map feature as undiscovered.\n" - )); - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown (color_ostream &out) -{ - return CR_OK; -} \ No newline at end of file diff --git a/scripts/feature.lua b/scripts/feature.lua new file mode 100644 index 000000000..0c242ad9f --- /dev/null +++ b/scripts/feature.lua @@ -0,0 +1,58 @@ +-- List or manage map features & enable magma furnaces +local help = [[=begin + +feature +======= +Enables management of map features. + +* Discovering a magma feature (magma pool, volcano, magma sea, or curious + underground structure) permits magma workshops and furnaces to be built. +* Discovering a cavern layer causes plants (trees, shrubs, and grass) from + that cavern to grow within your fortress. + +Options: + +:list: Lists all map features in your current embark by index. +:magma: Enable magma furnaces (discovers a random magma feature). +:show X: Marks the selected map feature as discovered. +:hide X: Marks the selected map feature as undiscovered. + +=end]] + +local map_features = df.global.world.features.map_features + +function toggle_feature(idx, discovered) + map_features[tonumber(idx)].flags.Discovered = discovered +end + +function list_features() + for idx, feat in ipairs(map_features) do + local kind = df.feature_type[feat:getType()]:gsub('_', ' ') + local discovered = feat.flags.Discovered and 'shown. ' or 'hidden.' + print('Feature #'..idx..' is '..discovered..' It is a "'..kind..'".') + end +end + +function enable_magma_funaces() + for idx, feat in ipairs(map_features) do + if tostring(feat):find('magma') ~= nil then + toggle_feature(idx, true) + print('Enabled magma furnaces.') + return + end + end + dfhack.printerr('Could not find a magma-bearing feature.') +end + +local args = {...} +if args[1] == 'list' then + list_features() +elseif args[1] == 'magma' then + enable_magma_funaces() +elseif args[1] == 'show' then + toggle_feature(args[2], true) +elseif args[1] == 'hide' then + toggle_feature(args[2], false) +else + print(help) +end From 1067eeb6d348aefce3a2bfcda82eaeabdc403c58 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Tue, 17 Nov 2015 16:52:06 +0930 Subject: [PATCH 021/222] Improve drybuckets checks Must also be liquid and in a container. --- scripts/fix/dry-buckets.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/fix/dry-buckets.lua b/scripts/fix/dry-buckets.lua index ddf5302b7..6e5ca24cf 100644 --- a/scripts/fix/dry-buckets.lua +++ b/scripts/fix/dry-buckets.lua @@ -13,7 +13,10 @@ local emptied = 0 local water_type = dfhack.matinfo.find('WATER').type for _,item in ipairs(df.global.world.items.all) do - if item:getMaterial() == water_type and not (item.flags.in_job or item.flags.in_building) then + if item:getMaterial() == water_type + and item:getType() == df.item_types.LIQUID_MISC + and dfhack.items.getContainer ~= nil + and not (item.flags.in_job or item.flags.in_building) then dfhack.items.remove(item) emptied = emptied + 1 end From c152b9033ae9fe64c8a45c1f5a51c3f07c2c224c Mon Sep 17 00:00:00 2001 From: Putnam3145 Date: Tue, 17 Nov 2015 09:58:04 -0800 Subject: [PATCH 022/222] Add indeterminate orientation to gaydar --- scripts/gaydar.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/gaydar.lua b/scripts/gaydar.lua index 83de3ae6a..0c344a9e7 100644 --- a/scripts/gaydar.lua +++ b/scripts/gaydar.lua @@ -72,6 +72,9 @@ local function determineorientation(unit) if unit.sex~=-1 then local return_string='' local orientation=unit.status.current_soul.orientation_flags + if orientation.indeterminate then + return 'indeterminate (probably adventurer)' + end local male_interested,asexual=false,true if orientation.romance_male then return_string=return_string..' likes males' @@ -144,6 +147,7 @@ function isNotStraight(v) if v:find(string.char(12)) and v:find(' female') then return true end if v:find(string.char(11)) and v:find(' male') then return true end if v:find('asexual') then return true end + if v:find('indeterminate') then return true end return false end @@ -155,7 +159,7 @@ function isGay(v) end function isAsexual(v) - if v:find('asexual') then return true else return false end + if v:find('asexual') or v:find('indeterminate') then return true else return false end end function isBi(v) From 67aed5618385bb023e0e0e4e43c3b9d74bd75012 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 17 Nov 2015 17:38:53 -0500 Subject: [PATCH 023/222] Allow adding plugins temporarily without modifying plugins/CMakeLists.txt Useful to avoid issues when switching between branches that modify plugins/CMakeLists.txt --- .gitignore | 2 +- plugins/CMakeLists.custom.txt | 3 +++ plugins/CMakeLists.txt | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 plugins/CMakeLists.custom.txt diff --git a/.gitignore b/.gitignore index 70ccb0445..1c9659b90 100644 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,4 @@ tags .DS_Store # autogenerated include-all.rst files -**include-all.rst \ No newline at end of file +**include-all.rst diff --git a/plugins/CMakeLists.custom.txt b/plugins/CMakeLists.custom.txt new file mode 100644 index 000000000..35a9d0efc --- /dev/null +++ b/plugins/CMakeLists.custom.txt @@ -0,0 +1,3 @@ +# You can add custom plugins here to avoid touching plugins/CMakeLists.txt, +# This can be useful if you've made modifications to that file and try to +# switch between branches that have also made modifications to it. diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 115f6196e..aee9d1421 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -180,3 +180,5 @@ OPTION(BUILD_SKELETON "Build the skeleton plugin." OFF) if(BUILD_SKELETON) add_subdirectory(skeleton) endif() + +INCLUDE(CMakeLists.custom.txt) From b7dd93b6e8847c45a0e905453f7c50c46ec20d86 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 21 Nov 2015 18:59:30 -0500 Subject: [PATCH 024/222] Implement most of the confirm plugin in Lua This should make resolving future issues easier, although implementing new confirmations in lua isn't possible yet (each one requires a line in confirm.cpp). This also resolves an issue with note-delete and route-delete, with dfhack/df-structures@1bc4f61 --- library/xml | 2 +- plugins/CMakeLists.txt | 2 +- plugins/confirm.cpp | 344 +++++++++++++++++----------------------- plugins/lua/confirm.lua | 229 ++++++++++++++++++++++++++ 4 files changed, 375 insertions(+), 202 deletions(-) create mode 100644 plugins/lua/confirm.lua diff --git a/library/xml b/library/xml index 378a580f7..1bc4f6133 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 378a580f7e333607a64a301d598e3885954a5d9d +Subproject commit 1bc4f6133c8a5bbd397001f97647c15724317e07 diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index aee9d1421..f30f00f08 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -108,7 +108,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(cleanowned cleanowned.cpp) DFHACK_PLUGIN(colonies colonies.cpp) DFHACK_PLUGIN(command-prompt command-prompt.cpp) - DFHACK_PLUGIN(confirm confirm.cpp) + DFHACK_PLUGIN(confirm confirm.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(createitem createitem.cpp) DFHACK_PLUGIN(cursecheck cursecheck.cpp) DFHACK_PLUGIN(deramp deramp.cpp) diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index 3b3771956..dd951a85c 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -6,6 +6,8 @@ #include "Export.h" #include "PluginManager.h" #include "VTableInterpose.h" +#include "LuaTools.h" +#include "LuaWrapper.h" #include "uicommon.h" #include "modules/Gui.h" @@ -38,6 +40,16 @@ inline bool in_vector (std::vector &vec, FT item) return std::find(vec.begin(), vec.end(), item) != vec.end(); } +string char_replace (string s, char a, char b) +{ + string res = s; + size_t i = res.size(); + while (i--) + if (res[i] == a) + res[i] = b; + return res; +} + namespace trade { static bool goods_selected (const std::vector &selected) { @@ -89,6 +101,70 @@ namespace trade { } } +namespace conf_lua { + static color_ostream_proxy *out; + static lua_State *l_state; + bool init (color_ostream &dfout) + { + out = new color_ostream_proxy(Core::getInstance().getConsole()); + l_state = Lua::Open(*out); + return l_state; + } + void cleanup() + { + if (out) + { + delete out; + out = NULL; + } + lua_close(l_state); + } + bool call (const char *func, int nargs = 0, int nres = 0) + { + if (!Lua::PushModulePublic(*out, l_state, "plugins.confirm", func)) + return false; + if (nargs > 0) + lua_insert(l_state, lua_gettop(l_state) - nargs); + return Lua::SafeCall(*out, l_state, nargs, nres); + } + template + void push (T val) + { + Lua::Push(l_state, val); + } + template + void table_set (lua_State *L, KeyType k, ValueType v) + { + Lua::Push(L, k); + Lua::Push(L, v); + lua_settable(L, -3); + } + namespace api { + int get_ids (lua_State *L) + { + lua_newtable(L); + for (auto it = confirmations.begin(); it != confirmations.end(); ++it) + table_set(L, it->first, true); + return 1; + } + } +} + +#define CONF_LUA_FUNC(ns, name) {#name, df::wrap_function(ns::name, true)} +DFHACK_PLUGIN_LUA_FUNCTIONS { + CONF_LUA_FUNC(trade, broker_goods_selected), + CONF_LUA_FUNC(trade, broker_goods_all_selected), + CONF_LUA_FUNC(trade, trader_goods_selected), + CONF_LUA_FUNC(trade, trader_goods_all_selected), + DFHACK_LUA_END +}; + +#define CONF_LUA_CMD(name) {#name, conf_lua::api::name} +DFHACK_PLUGIN_LUA_COMMANDS { + CONF_LUA_CMD(get_ids), + DFHACK_LUA_END +}; + template class confirmation { public: @@ -184,11 +260,42 @@ public: state = INACTIVE; } } - virtual bool intercept_key (df::interface_key key) = 0; virtual string get_id() = 0; - virtual string get_title() { return "Confirm"; } - virtual string get_message() = 0; - virtual UIColor get_color() { return COLOR_YELLOW; } + #define CONF_LUA_START using namespace conf_lua; Lua::StackUnwinder unwind(l_state); push(screen); push(get_id()); + bool intercept_key (df::interface_key key) + { + CONF_LUA_START; + push(key); + if (call("intercept_key", 3, 1)) + return lua_toboolean(l_state, -1); + else + return false; + }; + string get_title() + { + CONF_LUA_START; + if (call("get_title", 2, 1) && lua_isstring(l_state, -1)) + return lua_tostring(l_state, -1); + else + return "Confirm"; + } + string get_message() + { + CONF_LUA_START; + if (call("get_message", 2, 1) && lua_isstring(l_state, -1)) + return lua_tostring(l_state, -1); + else + return ""; + }; + UIColor get_color() + { + CONF_LUA_START; + if (call("get_color", 2, 1) && lua_isnumber(l_state, -1)) + return lua_tointeger(l_state, -1) % 16; + else + return COLOR_YELLOW; + } + #undef CONF_LUA_START protected: cstate state; df::interface_key last_key; @@ -234,8 +341,7 @@ int conf_register(confirmation *c, ...) return 0; } -#define IMPLEMENT_CONFIRMATION_HOOKS(cls) IMPLEMENT_CONFIRMATION_HOOKS_PRIO(cls, 0) -#define IMPLEMENT_CONFIRMATION_HOOKS_PRIO(cls, prio) \ +#define IMPLEMENT_CONFIRMATION_HOOKS(cls, prio) \ static cls cls##_instance; \ struct cls##_hooks : cls::screen_type { \ typedef cls::screen_type interpose_base; \ @@ -265,198 +371,33 @@ static int conf_register_##cls = conf_register(&cls##_instance, \ &INTERPOSE_HOOK(cls##_hooks, key_conflict), \ NULL); -class trade_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return key == df::interface_key::TRADE_TRADE; - } - virtual string get_id() { return "trade"; } - virtual string get_title() { return "Confirm trade"; } - virtual string get_message() - { - if (trade::trader_goods_selected(screen) && trade::broker_goods_selected(screen)) - return "Are you sure you want to trade the selected goods?"; - else if (trade::trader_goods_selected(screen)) - return "You are not giving any items. This is likely\n" - "to irritate the merchants.\n" - "Attempt to trade anyway?"; - else if (trade::broker_goods_selected(screen)) - return "You are not receiving any items. You may want to\n" - "offer these items instead or choose items to receive.\n" - "Attempt to trade anyway?"; - else - return "No items are selected. This is likely\n" - "to irritate the merchants.\n" - "Attempt to trade anyway?"; - } -}; -IMPLEMENT_CONFIRMATION_HOOKS(trade_confirmation); - -class trade_cancel_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return key == df::interface_key::LEAVESCREEN && - (trade::trader_goods_selected(screen) || trade::broker_goods_selected(screen)); - } - virtual string get_id() { return "trade-cancel"; } - virtual string get_title() { return "Cancel trade"; } - virtual string get_message() { return "Are you sure you want leave this screen?\nSelected items will not be saved."; } -}; -IMPLEMENT_CONFIRMATION_HOOKS_PRIO(trade_cancel_confirmation, -1); - -class trade_seize_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return trade::trader_goods_selected(screen) && key == df::interface_key::TRADE_SEIZE; - } - virtual string get_id() { return "trade-seize"; } - virtual string get_title() { return "Confirm seize"; } - virtual string get_message() { return "Are you sure you want to sieze these goods?"; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(trade_seize_confirmation); - -class trade_offer_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return trade::broker_goods_selected(screen) && key == df::interface_key::TRADE_OFFER; - } - virtual string get_id() { return "trade-offer"; } - virtual string get_title() { return "Confirm offer"; } - virtual string get_message() { return "Are you sure you want to offer these goods?\nYou will receive no payment."; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(trade_offer_confirmation); - -class trade_select_all_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - if (key == df::interface_key::SEC_SELECT) - { - if (screen->in_right_pane && trade::broker_goods_selected(screen) && !trade::broker_goods_all_selected(screen)) - return true; - else if (!screen->in_right_pane && trade::trader_goods_selected(screen) && !trade::trader_goods_all_selected(screen)) - return true; - } - return false; - } - virtual string get_id() { return "trade-select-all"; } - virtual string get_title() { return "Confirm selection"; } - virtual string get_message() - { - return "Selecting all goods will overwrite your current selection\n" - "and cannot be undone. Continue?"; - } -}; -IMPLEMENT_CONFIRMATION_HOOKS(trade_select_all_confirmation); +#define DEFINE_CONFIRMATION(cls, screen, prio) \ + class confirmation_##cls : public confirmation { \ + virtual string get_id() { static string id = char_replace(#cls, '_', '-'); return id; } \ + }; \ + IMPLEMENT_CONFIRMATION_HOOKS(confirmation_##cls, prio); -class hauling_route_delete_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - if (ui->main.mode == ui_sidebar_mode::Hauling && - ui->hauling.view_routes.size() && - !ui->hauling.in_name && - !ui->hauling.in_stop && - !ui->hauling.in_assign_vehicle - ) - return key == df::interface_key::D_HAULING_REMOVE; - return false; - } - virtual string get_id() { return "haul-delete"; } - virtual string get_title() { return "Confirm deletion"; } - virtual string get_message() - { - std::string type = (ui->hauling.view_stops[ui->hauling.cursor_top]) ? "stop" : "route"; - return std::string("Are you sure you want to delete this ") + type + "?"; - } -}; -IMPLEMENT_CONFIRMATION_HOOKS(hauling_route_delete_confirmation); - -class depot_remove_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - df::building_tradedepotst *depot = virtual_cast(Gui::getAnyBuilding(screen)); - if (depot && key == df::interface_key::DESTROYBUILDING) - { - for (auto it = ui->caravans.begin(); it != ui->caravans.end(); ++it) - { - if ((**it).time_remaining) - return true; - } - } - return false; - } - virtual string get_id() { return "depot-remove"; } - virtual string get_title() { return "Confirm depot removal"; } - virtual string get_message() - { - return "Are you sure you want to remove this depot?\n" - "Merchants are present and will lose profits."; - } -}; -IMPLEMENT_CONFIRMATION_HOOKS(depot_remove_confirmation); - -class squad_disband_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return screen->page == df::viewscreen_layer_militaryst::T_page::Positions && - screen->num_squads && - !screen->in_rename_alert && - key == df::interface_key::D_MILITARY_DISBAND_SQUAD; - } - virtual string get_id() { return "squad-disband"; } - virtual string get_title() { return "Disband squad"; } - virtual string get_message() { return "Are you sure you want to disband this squad?"; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(squad_disband_confirmation); - -class uniform_delete_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return screen->page == df::viewscreen_layer_militaryst::T_page::Uniforms && - !screen->equip.uniforms.empty() && - !screen->equip.in_name_uniform && - key == df::interface_key::D_MILITARY_DELETE_UNIFORM; - } - virtual string get_id() { return "uniform-delete"; } - virtual string get_title() { return "Delete uniform"; } - virtual string get_message() { return "Are you sure you want to delete this uniform?"; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(uniform_delete_confirmation); - -class note_delete_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return ui->main.mode == ui_sidebar_mode::NotesPoints && key == df::interface_key::D_NOTE_DELETE; - } - virtual string get_id() { return "note-delete"; } - virtual string get_title() { return "Delete note"; } - virtual string get_message() { return "Are you sure you want to delete this note?"; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(note_delete_confirmation); - -class route_delete_confirmation : public confirmation { -public: - virtual bool intercept_key (df::interface_key key) - { - return ui->main.mode == ui_sidebar_mode::NotesRoutes && key == df::interface_key::D_NOTE_ROUTE_DELETE; - } - virtual string get_id() { return "route-delete"; } - virtual string get_title() { return "Delete route"; } - virtual string get_message() { return "Are you sure you want to delete this route?"; } -}; -IMPLEMENT_CONFIRMATION_HOOKS(route_delete_confirmation); +/* This section defines stubs for all confirmation dialogs, with methods + implemented in plugins/lua/confirm.lua. + IDs (used in the "confirm enable/disable" command, by Lua, and in the docs) + are obtained by replacing '_' with '-' in the first argument to DEFINE_CONFIRMATION +*/ +DEFINE_CONFIRMATION(trade, viewscreen_tradegoodsst, 0); +DEFINE_CONFIRMATION(trade_cancel, viewscreen_tradegoodsst, -1); +DEFINE_CONFIRMATION(trade_seize, viewscreen_tradegoodsst, 0); +DEFINE_CONFIRMATION(trade_offer, viewscreen_tradegoodsst, 0); +DEFINE_CONFIRMATION(trade_select_all, viewscreen_tradegoodsst, 0); +DEFINE_CONFIRMATION(haul_delete, viewscreen_dwarfmodest, 0); +DEFINE_CONFIRMATION(depot_remove, viewscreen_dwarfmodest, 0); +DEFINE_CONFIRMATION(squad_disband, viewscreen_layer_militaryst, 0); +DEFINE_CONFIRMATION(uniform_delete, viewscreen_layer_militaryst, 0); +DEFINE_CONFIRMATION(note_delete, viewscreen_dwarfmodest, 0); +DEFINE_CONFIRMATION(route_delete, viewscreen_dwarfmodest, 0); DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) { + if (!conf_lua::init(out)) + return CR_FAILURE; commands.push_back(PluginCommand( "confirm", "Confirmation dialogs", @@ -480,6 +421,12 @@ DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) } is_enabled = enable; } + if (is_enabled) + { + using namespace conf_lua; + Lua::StackUnwinder unwind(l_state); + call("check"); + } return CR_OK; } @@ -487,6 +434,7 @@ DFhackCExport command_result plugin_shutdown (color_ostream &out) { if (plugin_enable(out, false) != CR_OK) return CR_FAILURE; + conf_lua::cleanup(); return CR_OK; } @@ -509,13 +457,11 @@ command_result df_confirm (color_ostream &out, vector & parameters) { CoreSuspender suspend; bool state = true; - if (in_vector(parameters, "help") || in_vector(parameters, "status")) + if (parameters.empty() || in_vector(parameters, "help") || in_vector(parameters, "status")) { out << "Available options: \n"; for (auto it = confirmations.begin(); it != confirmations.end(); ++it) - { - out << " " << it->first << ": " << (it->second->is_enabled() ? "enabled" : "disabled") << std::endl; - } + out.print(" %20s: %s\n", it->first.c_str(), it->second->is_enabled() ? "enabled" : "disabled"); return CR_OK; } for (auto it = parameters.begin(); it != parameters.end(); ++it) @@ -527,9 +473,7 @@ command_result df_confirm (color_ostream &out, vector & parameters) else if (*it == "all") { for (auto it = confirmations.begin(); it != confirmations.end(); ++it) - { it->second->apply(state); - } } else enable_conf(out, *it, state); diff --git a/plugins/lua/confirm.lua b/plugins/lua/confirm.lua new file mode 100644 index 000000000..d60d52387 --- /dev/null +++ b/plugins/lua/confirm.lua @@ -0,0 +1,229 @@ +local _ENV = mkmodule('plugins.confirm') + +local ui = df.global.ui + +local confs = {} +-- Wraps df.interface_key[foo] functionality but fails with invalid keys +keys = {} +setmetatable(keys, { + __index = function(self, k) + return df.interface_key[k] and df.interface_key[k] or error('Invalid key: ' .. tostring(k)) + end, + __newindex = function() error('Table is read-only') end +}) +--[[ The screen where a confirmation has been triggered +Note that this is *not* necessarily the topmost viewscreen, so do not use +gui.getCurViewscreen() or related functions. ]] +screen = nil + +function if_nil(obj, default) + if obj == nil then + return default + else + return obj + end +end + +function defconf(id) + if not get_ids()[id] then + error('Bad confirmation ID (not defined in plugin): ' .. id) + end + local cls = {} + cls.intercept_key = function(key) return false end + cls.get_title = function() return if_nil(cls.title, '') end + cls.get_message = function() return if_nil(cls.message, '') end + cls.get_color = function() return if_nil(cls.color, COLOR_YELLOW) end + confs[id] = cls + return cls +end + +--[[ Beginning of confirmation definitions +All confirmations declared in confirm.cpp must have a corresponding call to +defconf() here, and should implement intercept_key(), get_title(), and +get_message(). get_color() can also be implemented here, but the default should +be sufficient. + +In cases where getter functions always return the same value (e.g. get_title()), +they can be replaced with a field named after the method without the "get_" +prefix: + + trade.title = "Confirm trade" + +is equivalent to: + + function trade.get_title() return "Confirm trade" end + +]] + +trade = defconf('trade') +function trade.intercept_key(key) + return screen.in_edit_count == 0 and + key == keys.TRADE_TRADE +end +trade.title = "Confirm trade" +function trade.get_message() + if trader_goods_selected(screen) and broker_goods_selected(screen) then + return "Are you sure you want to trade the selected goods?" + elseif trader_goods_selected(screen) then + return "You are not giving any items. This is likely\n" .. + "to irritate the merchants.\n" .. + "Attempt to trade anyway?" + elseif broker_goods_selected(screen) then + return "You are not receiving any items. You may want to\n" .. + "offer these items instead or choose items to receive.\n" .. + "Attempt to trade anyway?" + else + return "No items are selected. This is likely\n" .. + "to irritate the merchants.\n" .. + "Attempt to trade anyway?" + end +end + +trade_cancel = defconf('trade-cancel') +function trade_cancel.intercept_key(key) + return screen.in_edit_count == 0 and + key == keys.LEAVESCREEN and + (trader_goods_selected(screen) or broker_goods_selected(screen)) +end +trade_cancel.title = "Cancel trade" +trade_cancel.message = "Are you sure you want leave this screen?\nSelected items will not be saved." + +trade_seize = defconf('trade-seize') +function trade_seize.intercept_key(key) + return screen.in_edit_count == 0 and + trader_goods_selected(screen) and + key == keys.TRADE_SEIZE +end +trade_seize.title = "Confirm seize" +trade_seize.message = "Are you sure you want to sieze these goods?" + +trade_offer = defconf('trade-offer') +function trade_offer.intercept_key(key) + return screen.in_edit_count == 0 and + broker_goods_selected(screen) and + key == keys.TRADE_OFFER +end +trade_offer.title = "Confirm offer" +trade_offer.message = "Are you sure you want to offer these goods?\nYou will receive no payment." + +trade_select_all = defconf('trade-select-all') +function trade_select_all.intercept_key(key) + if screen.in_edit_count == 0 and key == keys.SEC_SELECT then + if screen.in_right_pane and broker_goods_selected(screen) and not broker_goods_all_selected(screen) then + return true + elseif not screen.in_right_pane and trader_goods_selected(screen) and not trader_goods_all_selected(screen) then + return true + end + end + return false +end +trade_select_all.title = "Confirm selection" +trade_select_all.message = "Selecting all goods will overwrite your current selection\n" .. + "and cannot be undone. Continue?" + +haul_delete = defconf('haul-delete') +function haul_delete.intercept_key(key) + if ui.main.mode == df.ui_sidebar_mode.Hauling and + #ui.hauling.view_routes > 0 and + not ui.hauling.in_name and + not ui.hauling.in_stop and + not ui.hauling.in_assign_vehicle then + return key == keys.D_HAULING_REMOVE + end + return false +end +haul_delete.title = "Confirm deletion" +function haul_delete.get_message() + local t = ui.hauling.view_stops[ui.hauling.cursor_top] and "stop" or "route" + return "Are you sure you want to delete this " .. + (ui.hauling.view_stops[ui.hauling.cursor_top] and "stop" or "route") .. "?" +end + +depot_remove = defconf('depot-remove') +function depot_remove.intercept_key(key) + if df.building_tradedepotst:is_instance(dfhack.gui.getSelectedBuilding(true)) and + key == keys.DESTROYBUILDING then + for _, caravan in pairs(ui.caravans) do + if caravan.time_remaining > 0 then + return true + end + end + end +end +depot_remove.title = "Confirm depot removal" +depot_remove.message = "Are you sure you want to remove this depot?\n" .. + "Merchants are present and will lose profits." + +squad_disband = defconf('squad-disband') +function squad_disband.intercept_key(key) + return key == keys.D_MILITARY_DISBAND_SQUAD and + screen.page == screen._type.T_page.Positions and + screen.num_squads > 0 and + not screen.in_rename_alert +end +squad_disband.title = "Disband squad" +squad_disband.message = "Are you sure you want to disband this squad?" + +uniform_delete = defconf('uniform-delete') +function uniform_delete.intercept_key(key) + return key == keys.D_MILITARY_DELETE_UNIFORM and + screen.page == screen._type.T_page.Uniforms and + #screen.equip.uniforms > 0 and + not screen.equip.in_name_uniform +end +uniform_delete.title = "Delete uniform" +uniform_delete.message = "Are you sure you want to delete this uniform?" + +note_delete = defconf('note-delete') +function note_delete.intercept_key(key) + return key == keys.D_NOTE_DELETE and + ui.main.mode == df.ui_sidebar_mode.NotesPoints and + not ui.waypoints.in_edit_text_mode +end +note_delete.title = "Delete note" +note_delete.message = "Are you sure you want to delete this note?" + +route_delete = defconf('route-delete') +function route_delete.intercept_key(key) + return key == keys.D_NOTE_ROUTE_DELETE and + ui.main.mode == df.ui_sidebar_mode.NotesRoutes and + not ui.waypoints.in_edit_name_mode +end +route_delete.title = "Delete route" +route_delete.message = "Are you sure you want to delete this route?" + +-- End of confirmation definitions + +function check() + local undefined = {} + for id in pairs(get_ids()) do + if not confs[id] then + table.insert(undefined, id) + end + end + if #undefined > 0 then + error('Confirmation definitions missing: ' .. table.concat(undefined, ', ')) + end +end + +--[[ +The C++ plugin invokes methods of individual confirmations through four +functions (corresponding to method names) which receive the relevant screen, +the confirmation ID, and extra arguments in some cases, but these don't have to +do aything unique. +]] + +function define_wrapper(name) + _ENV[name] = function(scr, id, ...) + _ENV.screen = scr + if not confs[id] then + error('Bad confirmation ID: ' .. id) + end + return confs[id][name](...) + end +end +define_wrapper('intercept_key') +define_wrapper('get_title') +define_wrapper('get_message') +define_wrapper('get_color') +return _ENV From af92b3ae1f8534da4d8a7455c63697493e66ece1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 21 Nov 2015 20:58:49 -0500 Subject: [PATCH 025/222] Fix some confirm plugin issues and add a simple configuration UI - Detect null pointers in trade-related functions - Fix typo/issues pointed out by @dscorbett - Reorder includes --- plugins/confirm.cpp | 167 +++++++++++++++++++++++++---------- plugins/lua/confirm.lua | 4 +- scripts/gui/confirm-opts.lua | 74 ++++++++++++++++ 3 files changed, 196 insertions(+), 49 deletions(-) create mode 100644 scripts/gui/confirm-opts.lua diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index dd951a85c..ec8ee2a73 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -1,15 +1,18 @@ -#include #include +#include +#include + #include "Console.h" #include "Core.h" #include "DataDefs.h" +#include "Error.h" #include "Export.h" -#include "PluginManager.h" -#include "VTableInterpose.h" #include "LuaTools.h" #include "LuaWrapper.h" -#include "uicommon.h" +#include "PluginManager.h" +#include "VTableInterpose.h" #include "modules/Gui.h" +#include "uicommon.h" #include "df/building_tradedepotst.h" #include "df/general_ref.h" @@ -32,7 +35,9 @@ typedef std::set ikey_set; command_result df_confirm (color_ostream &out, vector & parameters); struct conf_wrapper; -static std::map confirmations; +static std::map confirmations; +string active_id; +std::queue cmds; template inline bool in_vector (std::vector &vec, FT item) @@ -50,6 +55,35 @@ string char_replace (string s, char a, char b) return res; } +bool set_conf_state (string name, bool state); + +struct conf_wrapper { +private: + bool enabled; + std::set hooks; +public: + conf_wrapper() + :enabled(false) + {} + void add_hook(VMethodInterposeLinkBase *hook) + { + if (!hooks.count(hook)) + hooks.insert(hook); + } + bool apply (bool state) { + if (state == enabled) + return true; + for (auto h = hooks.begin(); h != hooks.end(); ++h) + { + if (!(**h).apply(state)) + return false; + } + enabled = state; + return true; + } + inline bool is_enabled() { return enabled; } +}; + namespace trade { static bool goods_selected (const std::vector &selected) { @@ -60,10 +94,12 @@ namespace trade { } inline bool trader_goods_selected (df::viewscreen_tradegoodsst *screen) { + CHECK_NULL_POINTER(screen); return goods_selected(screen->trader_selected); } inline bool broker_goods_selected (df::viewscreen_tradegoodsst *screen) { + CHECK_NULL_POINTER(screen); return goods_selected(screen->broker_selected); } @@ -93,10 +129,12 @@ namespace trade { } inline bool trader_goods_all_selected(df::viewscreen_tradegoodsst *screen) { + CHECK_NULL_POINTER(screen); return goods_all_selected(screen->trader_selected, screen->trader_items); } inline bool broker_goods_all_selected(df::viewscreen_tradegoodsst *screen) { + CHECK_NULL_POINTER(screen); return goods_all_selected(screen->broker_selected, screen->broker_items); } } @@ -127,6 +165,11 @@ namespace conf_lua { lua_insert(l_state, lua_gettop(l_state) - nargs); return Lua::SafeCall(*out, l_state, nargs, nres); } + bool simple_call (const char *func) + { + Lua::StackUnwinder top(l_state); + return call(func, 0, 0); + } template void push (T val) { @@ -147,11 +190,34 @@ namespace conf_lua { table_set(L, it->first, true); return 1; } + int get_conf_data (lua_State *L) + { + lua_newtable(L); + int i = 1; + for (auto it = confirmations.begin(); it != confirmations.end(); ++it) + { + Lua::Push(L, i++); + lua_newtable(L); + table_set(L, "id", it->first); + table_set(L, "enabled", it->second->is_enabled()); + lua_settable(L, -3); + } + return 1; + } + int get_active_id (lua_State *L) + { + if (active_id.size()) + Lua::Push(L, active_id); + else + lua_pushnil(L); + return 1; + } } } #define CONF_LUA_FUNC(ns, name) {#name, df::wrap_function(ns::name, true)} DFHACK_PLUGIN_LUA_FUNCTIONS { + CONF_LUA_FUNC( , set_conf_state), CONF_LUA_FUNC(trade, broker_goods_selected), CONF_LUA_FUNC(trade, broker_goods_all_selected), CONF_LUA_FUNC(trade, trader_goods_selected), @@ -162,15 +228,30 @@ DFHACK_PLUGIN_LUA_FUNCTIONS { #define CONF_LUA_CMD(name) {#name, conf_lua::api::name} DFHACK_PLUGIN_LUA_COMMANDS { CONF_LUA_CMD(get_ids), + CONF_LUA_CMD(get_conf_data), + CONF_LUA_CMD(get_active_id), DFHACK_LUA_END }; +void show_options() +{ + cmds.push("gui/confirm-opts"); +} + template class confirmation { public: enum cstate { INACTIVE, ACTIVE, SELECTED }; typedef T screen_type; screen_type *screen; + void set_state (cstate s) + { + state = s; + if (s == INACTIVE) + active_id = ""; + else + active_id = get_id(); + } bool feed (ikey_set *input) { if (state == INACTIVE) { @@ -179,7 +260,7 @@ public: if (intercept_key(*it)) { last_key = *it; - state = ACTIVE; + set_state(ACTIVE); return true; } } @@ -188,9 +269,11 @@ public: else if (state == ACTIVE) { if (input->count(df::interface_key::LEAVESCREEN)) - state = INACTIVE; + set_state(INACTIVE); else if (input->count(df::interface_key::SELECT)) - state = SELECTED; + set_state(SELECTED); + else if (input->count(df::interface_key::CUSTOM_S)) + show_options(); return true; } return false; @@ -212,7 +295,7 @@ public: if (state == ACTIVE) { split_string(&lines, get_message(), "\n"); - size_t max_length = 30; + size_t max_length = 40; for (auto it = lines.begin(); it != lines.end(); ++it) max_length = std::max(max_length, it->size()); int width = max_length + 4; @@ -241,11 +324,15 @@ public: Screen::paintString(Screen::Pen(' ', COLOR_BLACK, COLOR_GREY), (gps->dimx / 2) - (title.size() / 2), y1, title); int x = x1 + 2; - OutputString(COLOR_LIGHTGREEN, x, y2, Screen::getKeyDisplay(df::interface_key::LEAVESCREEN)); - OutputString(COLOR_WHITE, x, y2, ": Cancel"); + int y = y2; + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::LEAVESCREEN)); + OutputString(COLOR_WHITE, x, y, ": Cancel"); + x = (gps->dimx - (Screen::getKeyDisplay(df::interface_key::CUSTOM_S) + ": Settings").size()) / 2 + 1; + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::CUSTOM_S)); + OutputString(COLOR_WHITE, x, y, ": Settings"); x = x2 - 2 - 3 - Screen::getKeyDisplay(df::interface_key::SELECT).size(); - OutputString(COLOR_LIGHTGREEN, x, y2, Screen::getKeyDisplay(df::interface_key::SELECT)); - OutputString(COLOR_WHITE, x, y2, ": Ok"); + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::SELECT)); + OutputString(COLOR_WHITE, x, y, ": Ok"); Screen::fillRect(Screen::Pen(' ', COLOR_BLACK, COLOR_BLACK), x1 + 1, y1 + 1, x2 - 1, y2 - 1); for (size_t i = 0; i < lines.size(); i++) { @@ -257,7 +344,7 @@ public: ikey_set tmp; tmp.insert(last_key); screen->feed(&tmp); - state = INACTIVE; + set_state(INACTIVE); } } virtual string get_id() = 0; @@ -301,37 +388,10 @@ protected: df::interface_key last_key; }; -struct conf_wrapper { -private: - bool enabled; - std::set hooks; -public: - conf_wrapper() - :enabled(false) - {} - void add_hook(VMethodInterposeLinkBase *hook) - { - if (!hooks.count(hook)) - hooks.insert(hook); - } - bool apply (bool state) { - if (state == enabled) - return true; - for (auto h = hooks.begin(); h != hooks.end(); ++h) - { - if (!(**h).apply(state)) - return false; - } - enabled = state; - return true; - } - inline bool is_enabled() { return enabled; } -}; - template int conf_register(confirmation *c, ...) { - conf_wrapper *w = new conf_wrapper; + conf_wrapper *w = new conf_wrapper(); confirmations[c->get_id()] = w; va_list args; va_start(args, c); @@ -423,9 +483,7 @@ DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) } if (is_enabled) { - using namespace conf_lua; - Lua::StackUnwinder unwind(l_state); - call("check"); + conf_lua::simple_call("check"); } return CR_OK; } @@ -438,7 +496,17 @@ DFhackCExport command_result plugin_shutdown (color_ostream &out) return CR_OK; } -void enable_conf (color_ostream &out, string name, bool state) +DFhackCExport command_result plugin_onupdate (color_ostream &out) +{ + while (!cmds.empty()) + { + Core::getInstance().runCommand(out, cmds.front()); + cmds.pop(); + } + return CR_OK; +} + +bool set_conf_state (string name, bool state) { bool found = false; for (auto it = confirmations.begin(); it != confirmations.end(); ++it) @@ -449,7 +517,12 @@ void enable_conf (color_ostream &out, string name, bool state) it->second->apply(state); } } - if (!found) + return found; +} + +void enable_conf (color_ostream &out, string name, bool state) +{ + if (!set_conf_state(name, state)) out.printerr("Unrecognized option: %s\n", name.c_str()); } diff --git a/plugins/lua/confirm.lua b/plugins/lua/confirm.lua index d60d52387..751b1b4da 100644 --- a/plugins/lua/confirm.lua +++ b/plugins/lua/confirm.lua @@ -7,7 +7,7 @@ local confs = {} keys = {} setmetatable(keys, { __index = function(self, k) - return df.interface_key[k] and df.interface_key[k] or error('Invalid key: ' .. tostring(k)) + return df.interface_key[k] or error('Invalid key: ' .. tostring(k)) end, __newindex = function() error('Table is read-only') end }) @@ -95,7 +95,7 @@ function trade_seize.intercept_key(key) key == keys.TRADE_SEIZE end trade_seize.title = "Confirm seize" -trade_seize.message = "Are you sure you want to sieze these goods?" +trade_seize.message = "Are you sure you want to seize these goods?" trade_offer = defconf('trade-offer') function trade_offer.intercept_key(key) diff --git a/scripts/gui/confirm-opts.lua b/scripts/gui/confirm-opts.lua new file mode 100644 index 000000000..d2aba2a94 --- /dev/null +++ b/scripts/gui/confirm-opts.lua @@ -0,0 +1,74 @@ +-- confirm plugin options +--[[=begin + +gui/confirm-opts +================ +A basic configuration interface for the `confirm` plugin. + +=end]] + + +confirm = require 'plugins.confirm' +gui = require 'gui' + +Opts = defclass(Opts, gui.FramedScreen) +Opts.ATTRS = { + frame_style = gui.GREY_LINE_FRAME, + frame_title = 'Confirmation dialogs', + frame_width = 32, + frame_height = 20, + frame_inset = 1, + focus_path = 'confirm/opts', +} + +function Opts:init() + self:refresh() + self.cursor = 1 + local active_id = confirm.get_active_id() + for i, c in pairs(self.data) do + if c.id == active_id then + self.cursor = i + break + end + end +end + +function Opts:refresh() + self.data = confirm.get_conf_data() + self.frame_height = #self.data +end + +function Opts:onRenderBody(p) + for i, c in pairs(self.data) do + local highlight = (i == self.cursor and 8 or 0) + p:pen(COLOR_GREY + highlight) + p:string(c.id .. ': ') + p:pen((c.enabled and COLOR_GREEN or COLOR_RED) + highlight) + p:string(c.enabled and 'Enabled' or 'Disabled') + p:newline() + end +end + +function Opts:onInput(keys) + local conf = self.data[self.cursor] + if keys.LEAVESCREEN then + self:dismiss() + elseif keys.SELECT then + confirm.set_conf_state(conf.id, not conf.enabled) + self:refresh() + elseif keys.SEC_SELECT then + for _, c in pairs(self.data) do + confirm.set_conf_state(c.id, not conf.enabled) + end + self:refresh() + elseif keys.STANDARDSCROLL_UP or keys.STANDARDSCROLL_DOWN then + self.cursor = self.cursor + (keys.STANDARDSCROLL_UP and -1 or 1) + if self.cursor < 1 then + self.cursor = #self.data + elseif self.cursor > #self.data then + self.cursor = 1 + end + end +end + +Opts():show() From 7ed5a810b92f5d78762bbc53af0ce9b3e4209372 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Mon, 23 Nov 2015 17:51:26 +0930 Subject: [PATCH 026/222] Improve fix/dry-buckets checks --- scripts/fix/dry-buckets.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/fix/dry-buckets.lua b/scripts/fix/dry-buckets.lua index 6e5ca24cf..4be4bc3cd 100644 --- a/scripts/fix/dry-buckets.lua +++ b/scripts/fix/dry-buckets.lua @@ -13,9 +13,12 @@ local emptied = 0 local water_type = dfhack.matinfo.find('WATER').type for _,item in ipairs(df.global.world.items.all) do - if item:getMaterial() == water_type - and item:getType() == df.item_types.LIQUID_MISC - and dfhack.items.getContainer ~= nil + container = dfhack.items.getContainer(item) + if container ~= nil + and container:getType() == dfhack.item_type.BUCKET + and not (container.flags.in_job or container.flags.in_building) + and item:getMaterial() == water_type + and item:getType() == dfhack.item_type.LIQUID_MISC and not (item.flags.in_job or item.flags.in_building) then dfhack.items.remove(item) emptied = emptied + 1 From 14cf2790d22dac0bf74da45a1a04a031fc4a4194 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Wed, 25 Nov 2015 17:51:30 -0700 Subject: [PATCH 027/222] Falconne deserves credit for a few great plugins. --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 05997b3d6..8b8013ff8 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -15,6 +15,7 @@ Alexander Gavrilov angavrilov ag AndreasPK AndreasPK Angus Mezick amezick Antalia tamarakorr +Anuradha Dissanayake falconne belal jimhester Ben Lubar BenLubar Caldfir caldfir From df4fb70be2d5b85df052416f0bcdc93f5b4b4dbf Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 20:22:14 -0500 Subject: [PATCH 028/222] Provide more suggestions for unrecognized commands --- library/Core.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index a932e49e7..edb00c45e 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1177,9 +1177,25 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, v else if ( filename != "" && plug_mgr->ruby && plug_mgr->ruby->is_enabled() ) res = runRubyScript(con, plug_mgr, first, parts); else if ( try_autocomplete(con, first, completed) ) - return CR_NOT_IMPLEMENTED; + res = CR_NOT_IMPLEMENTED; else con.printerr("%s is not a recognized command.\n", first.c_str()); + if (res == CR_NOT_IMPLEMENTED) + { + Plugin *p = plug_mgr->getPluginByName(first); + if (p) + { + con.printerr("%s is a plugin ", first.c_str()); + if (p->getState() == Plugin::PS_UNLOADED) + con.printerr("that is not loaded - try \"load %s\" or check stderr.log\n", + first.c_str()); + else if (p->size()) + con.printerr("that implements %i commands - see \"ls %s\" for details\n", + p->size(), first.c_str()); + else + con.printerr("but does not implement any commands\n"); + } + } } else if (res == CR_NEEDS_CONSOLE) con.printerr("%s needs interactive console to work.\n", first.c_str()); @@ -1309,7 +1325,7 @@ void fIOthread(void * iodata) if(clueless_counter == 3) { - con.print("Do 'help' or '?' for the list of available commands.\n"); + con.print("Run 'help' or '?' for the list of available commands.\n"); clueless_counter = 0; } } From 2aeac718ccbea89d383c47e01e10e1c6ca681cc6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 20:33:13 -0500 Subject: [PATCH 029/222] workflow: Account for job postings correctly and fix existing issues Without removing postings correctly, it was possible to end up with multiple workers assigned to a job that workflow had suspended multiple times, which caused crashes if more than one worker was assigned to the same job by DF. This adds an additional command, fix-job-postings, that runs automatically when loading a world and fixes: - Multiple job postings that point to the same job - Job postings that point to a job where posting_index == -1 (i.e. jobs that should have no posting assigned) Fixes #741 --- library/LuaApi.cpp | 1 + library/include/modules/Job.h | 5 +++ library/modules/Job.cpp | 28 +++++++++++++++ library/xml | 2 +- plugins/workflow.cpp | 67 +++++++++++++++++++++++++++++++++-- 5 files changed, 100 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 62f274902..72267a5bf 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1464,6 +1464,7 @@ static const LuaWrapper::FunctionReg dfhack_job_module[] = { WRAPM(Job,isSuitableMaterial), WRAPM(Job,getName), WRAPM(Job,linkIntoWorld), + WRAPM(Job,removePostings), WRAPN(is_equal, jobEqual), WRAPN(is_item_equal, jobItemEqual), { NULL, NULL } diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 4b3950ebd..fbbed9ff3 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -72,6 +72,11 @@ namespace DFHack DFHACK_EXPORT bool linkIntoWorld(df::job *job, bool new_id = true); + // Flag this job's posting as "dead" and set its posting_index to -1 + // If remove_all is true, flag all postings pointing to this job + // Returns true if any postings were removed + DFHACK_EXPORT bool removePostings(df::job *job, bool remove_all = false); + // lists jobs with ids >= *id_var, and sets *id_var = *job_next_id; DFHACK_EXPORT bool listNewlyCreated(std::vector *pvec, int *id_var); diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 1cfc0fa78..af2fcb4e8 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -377,6 +377,34 @@ bool DFHack::Job::linkIntoWorld(df::job *job, bool new_id) } } +bool DFHack::Job::removePostings(df::job *job, bool remove_all) +{ + using df::global::world; + CHECK_NULL_POINTER(job); + bool removed = false; + if (!remove_all) + { + if (job->posting_index >= 0 && job->posting_index < world->job_postings.size()) + { + world->job_postings[job->posting_index]->flags.bits.dead = true; + removed = true; + } + } + else + { + for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) + { + if ((**it).job == job) + { + (**it).flags.bits.dead = true; + removed = true; + } + } + } + job->posting_index = -1; + return removed; +} + bool DFHack::Job::listNewlyCreated(std::vector *pvec, int *id_var) { using df::global::world; diff --git a/library/xml b/library/xml index 378a580f7..bb950d99d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 378a580f7e333607a64a301d598e3885954a5d9d +Subproject commit bb950d99da543f314f3dd9babf1446c8331ff99d diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index 113f4c89d..b2a2d11c4 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -59,10 +59,13 @@ REQUIRE_GLOBAL(job_next_id); /* Plugin registration */ static command_result workflow_cmd(color_ostream &out, vector & parameters); +static command_result fix_job_postings_cmd(color_ostream &out, vector ¶meters); static void init_state(color_ostream &out); static void cleanup_state(color_ostream &out); +static int fix_job_postings(color_ostream *out = NULL, bool dry_run = false); + DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { if (!world || !ui) @@ -142,6 +145,13 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector ¶meters) +{ + bool dry = parameters.size(); + int fixed = fix_job_postings(&out, dry); + out << fixed << " job issue(s) " << (dry ? "detected but not fixed" : "fixed") << endl; + return CR_OK; +} + /****************************** * JOB STATE TRACKING STRUCTS * ******************************/ @@ -274,7 +295,7 @@ public: { if (world->frame_counter >= resume_time && actual_job->flags.bits.suspend) { - actual_job->unk_v4020_1 = -1; + Job::removePostings(actual_job, true); actual_job->flags.bits.suspend = false; } } @@ -287,7 +308,7 @@ public: if (!actual_job->flags.bits.suspend) { actual_job->flags.bits.suspend = true; - actual_job->unk_v4020_1 = -1; + Job::removePostings(actual_job, true); } } @@ -406,6 +427,41 @@ public: } }; +static int fix_job_postings (color_ostream *out, bool dry_run) +{ + int count = 0; + df::job_list_link *link = &world->job_list; + while (link) + { + df::job *job = link->item; + if (job) + { + bool needs_posting = (job->posting_index >= 0); + bool found_posting = false; + for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) + { + df::world::T_job_postings *posting = *it; + if (posting->job == job && !posting->flags.bits.dead) + { + if (!found_posting && needs_posting) + found_posting = true; + else + { + ++count; + if (*out) + *out << "Found extra job posting: Job " << job->id << ": " + << Job::getName(job) << endl; + if (!dry_run) + posting->flags.bits.dead = true; + } + } + } + } + link = link->next; + } + return count; +} + /****************************** * GLOBAL VARIABLES * ******************************/ @@ -1603,6 +1659,12 @@ static int getCountHistory(lua_State *L) return 1; } +static int fixJobPostings(lua_State *L) +{ + bool dry = lua_toboolean(L, 1); + lua_pushinteger(L, fix_job_postings(NULL, dry)); + return 1; +} DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(deleteConstraint), @@ -1614,6 +1676,7 @@ DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_LUA_COMMAND(findConstraint), DFHACK_LUA_COMMAND(setConstraint), DFHACK_LUA_COMMAND(getCountHistory), + DFHACK_LUA_COMMAND(fixJobPostings), DFHACK_LUA_END }; From 597ed1510ea56ff48cd2c0c4ce7d0954efa202af Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 20:56:30 -0500 Subject: [PATCH 030/222] Update documentation Ref #741, #744, #747, #748, #749, #756 --- NEWS.rst | 14 +++++++++++++- docs/Plugins.rst | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 8bec5b809..5af49210f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -34,7 +34,19 @@ DFHack future Fixes ----- -- confirm haul-delete: Fixed issue preventing deletion of stop conditions or using "x" in route names +- Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init +- Script help that doesn't start with a space is now recognized correctly +- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too agressively +- `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses +- `gui/create-item`: Allow exiting quantity prompt +- `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode +- `search`: Fixed a crash on the military screen +- `tweak` max-wheelbarrow: Fixed a minor display issue with large numbers +- `workflow`: Fixed a crash related to job postings (and added a fix for existing, broken jobs) + +Misc Improvements +----------------- +- Unrecognized command feedback now includes more information about plugins DFHack 0.40.24-r4 ================= diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 0cd16a075..4433aa1f3 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1026,6 +1026,13 @@ Maintain 10-100 locally-made crafts of exceptional quality:: workflow count CRAFTS///LOCAL,EXCEPTIONAL 100 90 +.. _fix-job-postings: + +fix-job-postings +---------------- +This command fixes crashes caused by previous versions of workflow, mostly in +DFHack 0.40.24-r4, and should be run automatically when loading a world (but can +also be run manually if desired). .. _clean: From 428a0a4cfe8fa77f39a9db7045b9b7d737129be3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 22:32:54 -0500 Subject: [PATCH 031/222] fix-unit-occupancy: Handle invalid coordinates instead of crashing It appears that positions of caged units brought by traders can be invalid, in particular. --- NEWS.rst | 2 +- plugins/fix-unit-occupancy.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 5af49210f..f9207868e 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,7 +36,7 @@ Fixes ----- - Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init - Script help that doesn't start with a space is now recognized correctly -- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too agressively +- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too aggressively - `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses - `gui/create-item`: Allow exiting quantity prompt - `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode diff --git a/plugins/fix-unit-occupancy.cpp b/plugins/fix-unit-occupancy.cpp index f6a26c669..e83392512 100644 --- a/plugins/fix-unit-occupancy.cpp +++ b/plugins/fix-unit-occupancy.cpp @@ -80,11 +80,16 @@ struct uo_buf { } inline uint8_t get (uint32_t x, uint32_t y, uint32_t z) { - return buf[offset(x, y, z)]; + size_t off = offset(x, y, z); + if (off < size) + return buf[off]; + return 0; } inline void set (uint32_t x, uint32_t y, uint32_t z, uint8_t val) { - buf[offset(x, y, z)] = val; + size_t off = offset(x, y, z); + if (off < size) + buf[off] = val; } inline void get_coords (size_t off, uint32_t &x, uint32_t &y, uint32_t &z) { From 2700b017659c7ffa13a3a63ef42aa2970faca6e0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 25 Nov 2015 23:35:19 -0500 Subject: [PATCH 032/222] Ensure that the correct job posting is kept (if there is one) --- plugins/workflow.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index b2a2d11c4..e35552dd3 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -436,24 +436,17 @@ static int fix_job_postings (color_ostream *out, bool dry_run) df::job *job = link->item; if (job) { - bool needs_posting = (job->posting_index >= 0); - bool found_posting = false; - for (auto it = world->job_postings.begin(); it != world->job_postings.end(); ++it) + for (size_t i = 0; i < world->job_postings.size(); ++i) { - df::world::T_job_postings *posting = *it; - if (posting->job == job && !posting->flags.bits.dead) + df::world::T_job_postings *posting = world->job_postings[i]; + if (posting->job == job && i != job->posting_index) { - if (!found_posting && needs_posting) - found_posting = true; - else - { - ++count; - if (*out) - *out << "Found extra job posting: Job " << job->id << ": " - << Job::getName(job) << endl; - if (!dry_run) - posting->flags.bits.dead = true; - } + ++count; + if (out) + *out << "Found extra job posting: Job " << job->id << ": " + << Job::getName(job) << endl; + if (!dry_run) + posting->flags.bits.dead = true; } } } From 55397425ef7c3125112503c7edc44355c53a1f5b Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 10:34:46 -0500 Subject: [PATCH 033/222] Only call fix-job-postings automatically when workflow is enabled Also, don't consider dead postings problematic --- plugins/workflow.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index e35552dd3..18090afc6 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -172,9 +172,6 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan case SC_MAP_LOADED: cleanup_state(out); init_state(out); - out << "workflow: checking for existing job issues" << endl; - if (fix_job_postings(&out)) - out << "workflow: fixed job issues" << endl; break; case SC_MAP_UNLOADED: cleanup_state(out); @@ -439,7 +436,7 @@ static int fix_job_postings (color_ostream *out, bool dry_run) for (size_t i = 0; i < world->job_postings.size(); ++i) { df::world::T_job_postings *posting = world->job_postings[i]; - if (posting->job == job && i != job->posting_index) + if (posting->job == job && i != job->posting_index && !posting->flags.bits.dead) { ++count; if (out) @@ -551,6 +548,11 @@ static ItemConstraint *get_constraint(color_ostream &out, const std::string &str static void start_protect(color_ostream &out) { + out << "workflow: checking for existing job issues" << endl; + int count = fix_job_postings(&out); + if (count) + out << "workflow: fixed " << count << " job issues" << endl; + check_lost_jobs(out, 0); if (!known_jobs.empty()) From 75f43b9bf67fb6e33678550439b7e495b2df7fbf Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 10:54:35 -0500 Subject: [PATCH 034/222] Add @Enkrod to Authors.rst Ref #743 --- docs/Authors.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Authors.rst b/docs/Authors.rst index 8b8013ff8..13ef59721 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -67,12 +67,12 @@ potato Priit Laes plaes Putnam Putnam3145 Quietust quietust _Q +Raidau Raidau Ramblurr Ramblurr rampaging-poet Raoul van Putten Raoul XQ raoulxq reverb -Raidau Raidau Rinin Rinin Robert Heinrich rh73 rofl0r rofl0r @@ -84,6 +84,7 @@ Rumrusher rumrusher RusAnon RusAnon sami scamtank scamtank +Sebastian Wolfertz Enkrod Seth Woodworth sethwoodworth simon Simon Jackson sizeak From 26abc5e9158519299e82ad98e906fe8edf5a1163 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 13:17:18 -0500 Subject: [PATCH 035/222] Add script to check Authors.rst --- .travis.yml | 1 + travis/authors-rst.py | 67 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 travis/authors-rst.py diff --git a/.travis.yml b/.travis.yml index 4afad1704..6c8457b93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ script: - sh travis/git-info.sh - python travis/pr-check-base.py - python travis/lint.py +- python travis/authors-rst.py - python travis/script-in-readme.py - python travis/script-syntax.py --ext=lua --cmd="luac5.2 -p" - python travis/script-syntax.py --ext=rb --cmd="ruby -c" --path scripts/ diff --git a/travis/authors-rst.py b/travis/authors-rst.py new file mode 100644 index 000000000..2d7274219 --- /dev/null +++ b/travis/authors-rst.py @@ -0,0 +1,67 @@ +""" Overly-complicated script to check formatting/sorting in Authors.rst """ + +import re, sys + +def main(): + success = [True] + def error(line, msg, **kwargs): + info = '' + for k in kwargs: + info += ' %s %s:' % (k, kwargs[k]) + print('line %i:%s %s' % (line, info, msg)) + success[0] = False + with open('docs/Authors.rst', 'rb') as f: + lines = list(map(lambda line: line.decode('utf8').replace('\n', ''), f.readlines())) + + if lines[1].startswith('='): + if len(lines[0]) != len(lines[1]): + error(2, 'Length of header does not match underline') + if lines[1].replace('=', ''): + error(2, 'Invalid header') + + first_div_index = list(filter(lambda pair: pair[1].startswith('==='), enumerate(lines[2:])))[0][0] + 2 + first_div = lines[first_div_index] + div_indices = [] + for i, line in enumerate(lines[first_div_index:]): + line_number = i + first_div_index + 1 + if '\t' in line: + error(line_number, 'contains tabs') + if line.startswith('==='): + div_indices.append(i + first_div_index) + if not re.match(r'^=+( =+)+$', line): + error(line_number, 'bad table divider') + if line != lines[first_div_index]: + error(line_number, 'malformed table divider') + if len(div_indices) < 3: + error(len(lines), 'missing table divider(s)') + for i in div_indices[3:]: + error(i + 1, 'extra table divider') + + col_ranges = [] + i = 0 + while True: + j = first_div.find(' ', i) + col_ranges.append(slice(i, j if j > 0 else None)) + if j == -1: + break + i = j + 1 + + for i, line in enumerate(lines[div_indices[1] + 1:div_indices[2]]): + line_number = i + div_indices[1] + 2 + for c, col in enumerate(col_ranges): + cell = line[col] + if cell.startswith(' '): + error(line_number, 'text does not start in correct location', column=c+1) + # check for text extending into next column if this isn't the last column + if col.stop is not None and col.stop < len(line) and line[col.stop] != ' ': + error(line_number, 'text extends into next column', column=c+1) + if i > 0: + prev_line = lines[div_indices[1] + i] + if line.lower()[col_ranges[0]] < prev_line.lower()[col_ranges[0]]: + error(line_number, 'not sorted: should come before line %i ("%s" before "%s")' % + (line_number - 1, line[col_ranges[0]].rstrip(' '), prev_line[col_ranges[0]].rstrip(' '))) + + return success[0] + +if __name__ == '__main__': + sys.exit(int(not main())) From 3783cbb6724e7ef276490ef770bbb76df976698d Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 16:41:45 -0500 Subject: [PATCH 036/222] feature.lua: Several improvements * List names of features * List some flags (water, magma, layer, etc.) * Detect invalid IDs * Remove =begin/=end from displayed help text --- scripts/feature.lua | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/scripts/feature.lua b/scripts/feature.lua index 0c242ad9f..7c634de6b 100644 --- a/scripts/feature.lua +++ b/scripts/feature.lua @@ -22,15 +22,32 @@ Options: local map_features = df.global.world.features.map_features function toggle_feature(idx, discovered) + idx = tonumber(idx) + if idx < 0 or idx >= #map_features then + qerror('Invalid feature ID') + end map_features[tonumber(idx)].flags.Discovered = discovered end function list_features() + local name = df.new('string') for idx, feat in ipairs(map_features) do - local kind = df.feature_type[feat:getType()]:gsub('_', ' ') - local discovered = feat.flags.Discovered and 'shown. ' or 'hidden.' - print('Feature #'..idx..' is '..discovered..' It is a "'..kind..'".') + local tags = '' + for _, t in pairs({'water', 'magma', 'subterranean', 'chasm', 'layer'}) do + if feat['is' .. t:sub(1, 1):upper() .. t:sub(2)](feat) then + tags = tags .. (' [%s]'):format(t) + end + end + feat:getName(name) + print(('Feature #%i is %s: "%s", type %s%s'):format( + idx, + feat.flags.Discovered and 'shown' or 'hidden', + name.value, + df.feature_type[feat:getType()], + tags + )) end + df.delete(name) end function enable_magma_funaces() @@ -54,5 +71,5 @@ elseif args[1] == 'show' then elseif args[1] == 'hide' then toggle_feature(args[2], false) else - print(help) + print((help:gsub('=[a-z]+', ''))) end From c09eafcaf392fb78952cb7a33863386bb601f6dc Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 16:50:46 -0500 Subject: [PATCH 037/222] Fix fix/dry-buckets --- scripts/fix/dry-buckets.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/fix/dry-buckets.lua b/scripts/fix/dry-buckets.lua index 4be4bc3cd..91cff2cd1 100644 --- a/scripts/fix/dry-buckets.lua +++ b/scripts/fix/dry-buckets.lua @@ -15,10 +15,10 @@ local water_type = dfhack.matinfo.find('WATER').type for _,item in ipairs(df.global.world.items.all) do container = dfhack.items.getContainer(item) if container ~= nil - and container:getType() == dfhack.item_type.BUCKET + and container:getType() == df.item_type.BUCKET and not (container.flags.in_job or container.flags.in_building) and item:getMaterial() == water_type - and item:getType() == dfhack.item_type.LIQUID_MISC + and item:getType() == df.item_type.LIQUID_MISC and not (item.flags.in_job or item.flags.in_building) then dfhack.items.remove(item) emptied = emptied + 1 From 036c30fa6809c28f377f265d6b65d02437c09b42 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 17:09:53 -0500 Subject: [PATCH 038/222] Set BUILD_DOCS to OFF by default See #738 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbbbd9727..326a71ebc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ else(CMAKE_CONFIGURATION_TYPES) endif (NOT CMAKE_BUILD_TYPE) endif(CMAKE_CONFIGURATION_TYPES) -OPTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." ON) +OPTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) ## some generic CMake magic cmake_minimum_required(VERSION 2.8 FATAL_ERROR) From 485eddc54e53ee7b254201370f120263c5f3bd1c Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 26 Nov 2015 20:24:14 -0500 Subject: [PATCH 039/222] JsonEx -> Json --- depends/jsoncpp/jsoncpp-ex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/jsoncpp/jsoncpp-ex.h b/depends/jsoncpp/jsoncpp-ex.h index fc1174133..1a5286dd0 100644 --- a/depends/jsoncpp/jsoncpp-ex.h +++ b/depends/jsoncpp/jsoncpp-ex.h @@ -1,7 +1,7 @@ #include "jsoncpp.h" #pragma once -namespace JsonEx { +namespace Json { template bool is (const Json::Value &val) { return false; } template T as (const Json::Value &val); From 8ec232570be21702344efa1980ee23164e672196 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 27 Nov 2015 16:12:34 -0500 Subject: [PATCH 040/222] Fix some emigration issues See #730 --- scripts/emigration.lua | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/scripts/emigration.lua b/scripts/emigration.lua index d523177bf..aba62fa2b 100644 --- a/scripts/emigration.lua +++ b/scripts/emigration.lua @@ -26,7 +26,7 @@ end function desireToStay(unit,method,civ_id) -- on a percentage scale - value = 100 - unit.status.current_soul.personality.stress_level / 5000 + local value = 100 - unit.status.current_soul.personality.stress_level / 5000 if method == 'merchant' or method == 'diplomat' then if civ_id ~= unit.civ_id then value = value*2 end end if method == 'wild' then @@ -60,12 +60,12 @@ function canLeave(unit) if skill.rating > 14 then return false end end if unit.flags1.caged - or u.race ~= df.global.ui.race_id - or u.civ_id ~= df.global.ui.civ_id - or dfhack.units.isDead(u) - or dfhack.units.isOpposedToLife(u) - or u.flags1.merchant - or u.flags1.diplomat + or unit.race ~= df.global.ui.race_id + or unit.civ_id ~= df.global.ui.civ_id + or dfhack.units.isDead(unit) + or dfhack.units.isOpposedToLife(unit) + or unit.flags1.merchant + or unit.flags1.diplomat or unit.flags1.chained or dfhack.units.getNoblePositions(unit) ~= nil or unit.military.squad_id ~= -1 @@ -109,8 +109,10 @@ function checkmigrationnow() end local function event_loop() - checkmigrationnow() - dfhack.timeout(1, 'months', event_loop) + if enabled then + checkmigrationnow() + dfhack.timeout(1, 'months', event_loop) + end end dfhack.onStateChange.loadEmigration = function(code) From 734d2c03db6cfd0589ad6bd2a4a843ddea53541a Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 27 Nov 2015 16:25:31 -0500 Subject: [PATCH 041/222] Fix several issues with gui/family-affairs * Fix mismatched variable names * Fix help display * Remove redundant write to gamelog.txt * Check for adulthood and fortress mode more reliably See #730 --- scripts/gui/family-affairs.lua | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/scripts/gui/family-affairs.lua b/scripts/gui/family-affairs.lua index 51525f36e..e3806e9f2 100644 --- a/scripts/gui/family-affairs.lua +++ b/scripts/gui/family-affairs.lua @@ -28,6 +28,8 @@ The target/s must be alive, sane, and in fortress mode. =end]] +helpstr = help:gsub('=begin', ''):gsub('=end', '') + local dlg = require ('gui.dialogs') function ErrorPopup (msg,color) @@ -36,14 +38,8 @@ function ErrorPopup (msg,color) dlg.showMessage("Dwarven Family Affairs", msg, color, nil) end -function AnnounceAndGamelog (text,l) - if not l then l = true end - dfhack.gui.showAnnouncement(text, _G["COLOR_LIGHTMAGENTA"]) - if l then - local log = io.open('gamelog.txt', 'a') - log:write(text.."\n") - log:close() - end +function AnnounceAndGamelog(text) + dfhack.gui.showAnnouncement(text, COLOR_LIGHTMAGENTA) end function ListPrompt (msg, choicelist, bool, yes_func) @@ -181,7 +177,7 @@ function ChooseNewSpouse (source) if not source then qerror("no unit") return end - if (source.profession == 103 or source.profession == 104) then + if not dfhack.units.isAdult(source) then ErrorPopup("target is too young") return end if not (source.relations.spouse_id == -1 and source.relations.lover_id == -1) then @@ -199,7 +195,7 @@ function ChooseNewSpouse (source) and v.sex ~= source.sex and v.relations.spouse_id == -1 and v.relations.lover_id == -1 - and not (v.profession == 103 or v.profession == 104) + and dfhack.units.isAdult(v) then table.insert(choicelist,dfhack.TranslateName(v.name)..', '..dfhack.units.getProfessionName(v)) table.insert(targetlist,v) @@ -229,11 +225,11 @@ function MainDialog (source) local choicelist = {} local on_select = {} - local child = (source.profession == 103 or source.profession == 104) - local is_single = source.relations.spouse_id == -1 and source.relations.lover_id == -1 - local ready_for_marriage = single and not child + local adult = dfhack.units.isAdult(source) + local single = source.relations.spouse_id == -1 and source.relations.lover_id == -1 + local ready_for_marriage = single and adult - if not child then + if adult then table.insert(choicelist,"Remove romantic relationships (if any)") table.insert(on_select, Divorce) if ready_for_marriage then @@ -258,8 +254,8 @@ local args = {...} if args[1] == "help" or args[1] == "?" then print(helpstr) return end -if not df.global.gamemode == 0 then - print (helpstr) qerror ("invalid gamemode") return +if not dfhack.world.isFortressMode() then + print (helpstr) qerror ("invalid game mode") return end if args[1] == "divorce" and tonumber(args[2]) then @@ -287,10 +283,10 @@ if selected then if dfhack.units.isCitizen(selected) and dfhack.units.isSane(selected) then MainDialog(selected) else - qerror("You must select sane fortress citizen.") + qerror("You must select a sane fortress citizen.") return end else print (helpstr) - qerror("select a sane fortress dwarf") + qerror("Select a sane fortress dwarf") end From 55c4c8f103709229acc8615381f4028d6a04fe14 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 27 Nov 2015 16:36:44 -0500 Subject: [PATCH 042/222] Update news --- NEWS.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index e41a4c5b3..073d014f3 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -32,24 +32,30 @@ Changelog DFHack future ============= +New Features +------------ +- `confirm`: + + - Added a ``uniform-delete`` option for military uniform deletion + - Added a basic in-game configuration UI + Fixes ----- - Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init - Script help that doesn't start with a space is now recognized correctly - `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too aggressively +- `emigration` should work now - `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses - `gui/create-item`: Allow exiting quantity prompt +- `gui/family-affairs`: Fixed an issue where lack of relationships wasn't recognized and other issues - `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode -- `search`: Fixed a crash on the military screen +- `search-plugin`: Fixed a crash on the military screen - `tweak` max-wheelbarrow: Fixed a minor display issue with large numbers - `workflow`: Fixed a crash related to job postings (and added a fix for existing, broken jobs) Misc Improvements ----------------- - Unrecognized command feedback now includes more information about plugins - -Misc Improvements ------------------ - `fix/dry-buckets`: replaces the ``drybuckets`` plugin - `feature`: now implemented by a script From 80556449a17c40ef096ced29280af835f5d073be Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 27 Nov 2015 16:45:26 -0500 Subject: [PATCH 043/222] Improve Json::get() slightly --- depends/jsoncpp/jsoncpp-ex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/jsoncpp/jsoncpp-ex.h b/depends/jsoncpp/jsoncpp-ex.h index 1a5286dd0..7d621dd72 100644 --- a/depends/jsoncpp/jsoncpp-ex.h +++ b/depends/jsoncpp/jsoncpp-ex.h @@ -11,7 +11,7 @@ namespace Json { template<> inline bool is (const Json::Value &val) { return val.is_func(); } \ template<> inline type as (const Json::Value &val) { return val.as_func(); } \ template<> inline type get (const Json::Value &val, const std::string &key, const type &default_) \ - { Json::Value x = val[key]; return is(x) ? as(x) : default_; } + { const Json::Value &x = val[key]; return is(x) ? as(x) : default_; } define_helpers(bool, isBool, asBool); define_helpers(Json::Int, isInt, asInt); define_helpers(Json::UInt, isUInt, asUInt); From 33302251c343324b0cd17bfb206d16a626093dd7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 27 Nov 2015 16:45:39 -0500 Subject: [PATCH 044/222] Update version to r5 --- CMakeLists.txt | 2 +- NEWS.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 326a71ebc..82ceafd38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,7 +93,7 @@ endif() # set up versioning. set(DF_VERSION "0.40.24") -SET(DFHACK_RELEASE "r4") +SET(DFHACK_RELEASE "r5") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/NEWS.rst b/NEWS.rst index 073d014f3..4ff70f63e 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -29,8 +29,8 @@ Changelog .. contents:: :depth: 2 -DFHack future -============= +DFHack 0.40.24-r5 +================= New Features ------------ From 23a5ce69bf07a13f8cf4f15aa8f8fa1f2291a37d Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 29 Nov 2015 00:03:26 +0530 Subject: [PATCH 045/222] Send unit names over remotefortressreader --- plugins/proto/RemoteFortressReader.proto | 3 +++ plugins/remotefortressreader.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 53dc0144a..aaf78ad91 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -229,6 +229,9 @@ message UnitDefinition optional uint32 flags3 = 10; optional bool is_soldier = 11; optional BodySizeInfo size_info = 12; + optional string name = 13; + optional int32 blood_max = 14; + optional int32 blood_count = 15; } message UnitList diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 6a98bc05b..2c97b35b7 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1343,6 +1343,10 @@ static command_result GetUnitList(color_ostream &stream, const EmptyMessage *in, size_info->set_area_base(unit->body.size_info.area_base); size_info->set_length_cur(unit->body.size_info.length_cur); size_info->set_length_base(unit->body.size_info.length_base); + if (unit->name.has_name) + { + send_unit->set_name(DF2UTF(Translation::TranslateName(Units::getVisibleName(unit)))); + } } return CR_OK; } From d84f5f1e52057dd44d5bc10385e04fc1dc7d0fcc Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sun, 29 Nov 2015 14:26:11 +0000 Subject: [PATCH 046/222] Re-enable GCC 5 compilation for OSX and Linux, passing -D_GLIBCXX_USE_CXX11_ABI=0 to disable new C++11 name mangling and remain compatible with DF. --- CMakeLists.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82ceafd38..fe289a9f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,13 @@ project(dfhack) macro(CHECK_GCC COMPILER_PATH) execute_process(COMMAND ${COMPILER_PATH} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) - if (${GCC_VERSION_OUT} VERSION_LESS "4.5" OR ${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") - message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 through 4.9") + if (${GCC_VERSION_OUT} VERSION_LESS "4.5") + message(SEND_ERROR "${COMPILER_PATH} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.5 or later") + elseif (${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") + # GCC 5 changes ABI name mangling to enable C++11 changes. + # This must be disabled to enable linking against DF. + # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) endif() endmacro() From 7aca0aa7b1436a7d90cff87d5aeed1882f9cfd84 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 29 Nov 2015 18:39:48 -0500 Subject: [PATCH 047/222] Clean up, update .gitignore --- .gitignore | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/.gitignore b/.gitignore index 1c9659b90..5ef3ce759 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,9 @@ # linux backup files *~ -#Kdevelop project file +#Kdevelop project files *.kdev4 - -# compiled binaries -output/* - -# this one is important, track it -!output/Memory.xml - -# a file generated by cmake -dfhack/include/config.h -library/private/config.h +.kdev4 # any build folders build*/ @@ -20,13 +11,13 @@ nix buntu build/VC2010 +#except for the real one +!build/ + # Sphinx generated documentation docs/_* docs/html/ -#except for the real one -!build/ - # in-place build build/Makefile build/CMakeCache.txt @@ -35,27 +26,17 @@ build/CMakeFiles build/doc build/lua build/bin +build/depends build/library -build/tools build/plugins -build/depends +build/scripts build/install_manifest.txt -build/README.html -build/LUA_API.html -build/COMPILE.html - -#ignore Kdevelop stuff -.kdev4 - -#fake curses header -examples/fake-curses.h +build/_CPack_Packages +build/dfhack-*.zip +build/dfhack-*.bz2 # Python binding binaries *.pyc -dfhack/python/pydfhack/_pydfhack.so -dfhack/python/PyDFHack.egg-info -dfhack/python/build -dfhack/python/dist # CPack stuff build/CPack*Config.cmake @@ -71,6 +52,3 @@ tags # Mac OS X .DS_Store files .DS_Store - -# autogenerated include-all.rst files -**include-all.rst From 8b406cc0b3148e2e232d5e7df9b70915b3619353 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Dec 2015 17:32:59 -0500 Subject: [PATCH 048/222] Make a separate copy of DF's SDL library to link against on OS X Linking to any library with ".framework" in its path on OS X causes that directory to be included in the include path (with -F), which causes all of the DFHack core to be rebuilt unnecessarily when changing DF folders. --- library/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 206badeb0..827a4eacd 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -304,10 +304,12 @@ ENDIF() SET_TARGET_PROPERTIES(dfhack PROPERTIES DEBUG_POSTFIX "-debug" ) IF(APPLE) - SET(SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework) - IF(NOT EXISTS ${SDL_LIBRARY}) + SET(DF_SDL_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/SDL.framework/Versions/A/SDL) + IF(NOT EXISTS ${DF_SDL_LIBRARY}) MESSAGE(SEND_ERROR "SDL framework not found. Make sure CMAKE_INSTALL_PREFIX is specified and correct.") ENDIF() + SET(SDL_LIBRARY ${CMAKE_BINARY_DIR}/SDL) + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DF_SDL_LIBRARY} ${SDL_LIBRARY}) SET(CXX_LIBRARY ${CMAKE_INSTALL_PREFIX}/libs/libstdc++.6.dylib) SET(ZIP_LIBRARY /usr/lib/libz.dylib) TARGET_LINK_LIBRARIES(dfhack ${SDL_LIBRARY}) From f9af5a71d6a22df976ca186b8a1a68a99d6dbe6c Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Dec 2015 17:36:44 -0500 Subject: [PATCH 049/222] Bump to 0.42.01-r0 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe289a9f4..19174ca37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,8 +97,8 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.40.24") -SET(DFHACK_RELEASE "r5") +set(DF_VERSION "0.42.01") +SET(DFHACK_RELEASE "r0") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 7a69b9027760b922c8ca1477ad0a74b0248a637e Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 2 Dec 2015 16:27:51 -0500 Subject: [PATCH 050/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index bb950d99d..2bf67a677 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bb950d99da543f314f3dd9babf1446c8331ff99d +Subproject commit 2bf67a6776cd62986a8a3a83cbe75a11cd9418a6 From 1668984585acd3304de11bd8c07b908f54a779ab Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Dec 2015 23:12:37 -0500 Subject: [PATCH 051/222] UNITJOB_VIEW -> UNITJOB_VIEW_UNIT --- plugins/manipulator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index c2f6759a5..ab790c7a0 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -1592,7 +1592,7 @@ void viewscreen_unitlaborsst::feed(set *events) if (enabler->mouse_lbut) { input_row = click_unit; - events->insert(interface_key::UNITJOB_VIEW); + events->insert(interface_key::UNITJOB_VIEW_UNIT); } if (enabler->mouse_rbut) { @@ -1804,7 +1804,7 @@ void viewscreen_unitlaborsst::feed(set *events) if (VIRTUAL_CAST_VAR(unitlist, df::viewscreen_unitlistst, parent)) { - if (events->count(interface_key::UNITJOB_VIEW) || events->count(interface_key::UNITJOB_ZOOM_CRE)) + if (events->count(interface_key::UNITJOB_VIEW_UNIT) || events->count(interface_key::UNITJOB_ZOOM_CRE)) { for (int i = 0; i < unitlist->units[unitlist->page].size(); i++) { @@ -2057,7 +2057,7 @@ void viewscreen_unitlaborsst::render() OutputString(10, x, y, Screen::getKeyDisplay(interface_key::SELECT_ALL)); OutputString(canToggle ? 15 : 8, x, y, ": Toggle Group, "); - OutputString(10, x, y, Screen::getKeyDisplay(interface_key::UNITJOB_VIEW)); + OutputString(10, x, y, Screen::getKeyDisplay(interface_key::UNITJOB_VIEW_UNIT)); OutputString(15, x, y, ": ViewCre, "); OutputString(10, x, y, Screen::getKeyDisplay(interface_key::UNITJOB_ZOOM_CRE)); From b63270162d4b777c458e7d4b82ec4fbee3d46235 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Dec 2015 23:12:49 -0500 Subject: [PATCH 052/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 2bf67a677..3a8a1966c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 2bf67a6776cd62986a8a3a83cbe75a11cd9418a6 +Subproject commit 3a8a1966c8d09111f9a4a6f0290f462823459b4d From 28336d43469d9983d7fded203829e352a0a5c771 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Dec 2015 23:13:12 -0500 Subject: [PATCH 053/222] Disable stockflow and show warning in example init --- dfhack.init-example | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dfhack.init-example b/dfhack.init-example index 578161c3f..db2bf1129 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -249,3 +249,10 @@ gui/load-screen enable ####################################################### # Apply binary patches at runtime # ####################################################### + +####################################################### +# Disable broken tools for v0.42.01 # +####################################################### + +disable stockflow +:lua dfhack.printerr("Some tools incompatible with v0.42.01 have been disabled") From e720c498c93b32b7e946110fc60f11c0e6e2bd73 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 5 Dec 2015 17:57:52 -0500 Subject: [PATCH 054/222] Bump to 0.42.02 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19174ca37..d85b97076 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.42.01") +set(DF_VERSION "0.42.02") SET(DFHACK_RELEASE "r0") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 3b2ace95f893d503db9c6753327fee4e53de7ea6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 5 Dec 2015 20:07:54 -0500 Subject: [PATCH 055/222] Make SDL_UpperBlit hook check core status first --- library/Hooks-darwin.cpp | 4 ++-- library/Hooks-windows.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Hooks-darwin.cpp b/library/Hooks-darwin.cpp index e72372fd4..3e020f9be 100644 --- a/library/Hooks-darwin.cpp +++ b/library/Hooks-darwin.cpp @@ -226,9 +226,9 @@ DFhackCExport void * SDL_GetVideoSurface(void) static int (*_SDL_UpperBlit)(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) = 0; DFhackCExport int SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) { - if ( dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) + DFHack::Core & c = DFHack::Core::getInstance(); + if ( c.isValid() && dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) { - DFHack::Core & c = DFHack::Core::getInstance(); DFHack::Graphic* g = c.getGraphic(); DFHack::DFTileSurface* ov = g->Call(dstrect->x/dstrect->w, dstrect->y/dstrect->h); diff --git a/library/Hooks-windows.cpp b/library/Hooks-windows.cpp index 552d9c186..7ea1385a7 100644 --- a/library/Hooks-windows.cpp +++ b/library/Hooks-windows.cpp @@ -271,9 +271,9 @@ DFhackCExport vPtr SDL_SetVideoMode(int width, int height, int bpp, uint32_t fla static int (*_SDL_UpperBlit)(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) = 0; DFhackCExport int SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) { - if ( dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) + DFHack::Core & c = DFHack::Core::getInstance(); + if ( c.isValid() && dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) { - DFHack::Core & c = DFHack::Core::getInstance(); DFHack::Graphic* g = c.getGraphic(); DFHack::DFTileSurface* ov = g->Call(dstrect->x/dstrect->w, dstrect->y/dstrect->h); From 49ad153d4b070157b89491d62853091b5ac4a1c1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 6 Dec 2015 17:12:46 -0500 Subject: [PATCH 056/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 3a8a1966c..0ab889184 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3a8a1966c8d09111f9a4a6f0290f462823459b4d +Subproject commit 0ab889184e9cddd7fd412e96a19e940df090d7ab From 02d2405d1f9f1c233f974eaab04a04017b3d42d8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 7 Dec 2015 16:34:47 -0500 Subject: [PATCH 057/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 0ab889184..0b1dc62cd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0ab889184e9cddd7fd412e96a19e940df090d7ab +Subproject commit 0b1dc62cd849b98946f619a9da857c17070afc50 From a3d6d1675792a18dd11d0212ab7827ef4b285f7e Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 7 Dec 2015 17:14:46 -0500 Subject: [PATCH 058/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 0b1dc62cd..be9fc3a2a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0b1dc62cd849b98946f619a9da857c17070afc50 +Subproject commit be9fc3a2ac98f5dd85a2765e5e9b9db95611e27d From 448e367d4db35de125440f28cd05cf8e848a692d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 8 Dec 2015 17:32:13 -0500 Subject: [PATCH 059/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index be9fc3a2a..48937985d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit be9fc3a2ac98f5dd85a2765e5e9b9db95611e27d +Subproject commit 48937985d4054fd4c5e7ea144a540b84546682e5 From 7e9d6fba86c08dba44318923cc876c654bc2cf9f Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 9 Dec 2015 20:03:14 -0500 Subject: [PATCH 060/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 48937985d..14ea03baa 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 48937985d4054fd4c5e7ea144a540b84546682e5 +Subproject commit 14ea03baa97c9c519e62087e1b9eec28f0476eb7 From 817ea5e01c297d04f9172b72d4dfd18d7584c34e Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 9 Dec 2015 20:03:35 -0500 Subject: [PATCH 061/222] Add new labors to autohauler/autolabor --- plugins/autohauler.cpp | 4 +++- plugins/autolabor.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/autohauler.cpp b/plugins/autohauler.cpp index 9814b678e..a7a35797c 100644 --- a/plugins/autohauler.cpp +++ b/plugins/autohauler.cpp @@ -521,7 +521,9 @@ static const struct labor_default default_labor_infos[] = { /* HAUL_WATER */ {HAULERS, 0}, /* GELD */ {ALLOW, 0}, /* BUILD_ROAD */ {HAULERS, 0}, - /* BUILD_CONSTRUCTION */ {HAULERS, 0} + /* BUILD_CONSTRUCTION */ {HAULERS, 0}, + /* PAPERMAKING */ {ALLOW, 0}, + /* BOOKBINDING */ {ALLOW, 0} }; /** diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index 21b979416..87b14729a 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -489,7 +489,9 @@ static const struct labor_default default_labor_infos[] = { /* HAUL_WATER */ {HAULERS, false, 1, 200, 0}, /* GELD */ {AUTOMATIC, false, 1, 200, 0}, /* BUILD_ROAD */ {AUTOMATIC, false, 1, 200, 0}, - /* BUILD_CONSTRUCTION */ {AUTOMATIC, false, 1, 200, 0} + /* BUILD_CONSTRUCTION */ {AUTOMATIC, false, 1, 200, 0}, + /* PAPERMAKING */ {AUTOMATIC, false, 1, 200, 0}, + /* BOOKBINDING */ {AUTOMATIC, false, 1, 200, 0} }; static const int responsibility_penalties[] = { From 571df39878ea21150ea76f408b25deb982f083cf Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Dec 2015 16:35:42 -0500 Subject: [PATCH 062/222] Update submodules --- library/xml | 2 +- scripts/3rdparty/lethosor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 14ea03baa..027b3fa01 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 14ea03baa97c9c519e62087e1b9eec28f0476eb7 +Subproject commit 027b3fa0130712697d5563ab704b4c8e458cd029 diff --git a/scripts/3rdparty/lethosor b/scripts/3rdparty/lethosor index 0b8303f6b..01b594027 160000 --- a/scripts/3rdparty/lethosor +++ b/scripts/3rdparty/lethosor @@ -1 +1 @@ -Subproject commit 0b8303f6b03d574e3a0b3fd8b17b7ff0014af47f +Subproject commit 01b594027a84c6b732f7639870538f138483a78c From a73110f7f0807c801b111f639e586ac28690cd7a Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Dec 2015 16:36:09 -0500 Subject: [PATCH 063/222] startdwarf: Provide feedback if offset is missing --- scripts/startdwarf.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/startdwarf.rb b/scripts/startdwarf.rb index 4e7d01c07..a592d5391 100644 --- a/scripts/startdwarf.rb +++ b/scripts/startdwarf.rb @@ -15,5 +15,6 @@ nr = $script_args[0].to_i raise 'too low' if nr < 7 addr = df.get_global_address('start_dwarf_count') +raise 'patch address not available' if addr == 0 df.memory_patch(addr, [nr].pack('L')) From 83603fcf45f96215d6896da2e9b9a9ba2f5bd42f Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Dec 2015 20:27:46 -0500 Subject: [PATCH 064/222] Add prerelease build flag and warning script --- CMakeLists.txt | 1 + library/CMakeLists.txt | 5 +++++ library/Core.cpp | 6 +++++ library/DFHackVersion.cpp | 9 ++++++++ library/LuaApi.cpp | 1 + library/include/DFHackVersion.h | 2 ++ scripts/gui/prerelease-warning.lua | 36 ++++++++++++++++++++++++++++++ 7 files changed, 60 insertions(+) create mode 100644 scripts/gui/prerelease-warning.lua diff --git a/CMakeLists.txt b/CMakeLists.txt index d85b97076..274b58fce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ endif() # set up versioning. set(DF_VERSION "0.42.02") SET(DFHACK_RELEASE "r0") +SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 827a4eacd..5071d9e71 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -263,6 +263,11 @@ SET_PROPERTY(TARGET dfhack-version APPEND PROPERTY COMPILE_DEFINITIONS DF_VERSION="${DF_VERSION}" DFHACK_RELEASE="${DFHACK_RELEASE}" ) +IF(DFHACK_PRERELEASE) + SET_PROPERTY(TARGET dfhack-version APPEND PROPERTY COMPILE_DEFINITIONS + DFHACK_PRERELEASE=1 + ) +ENDIF() ADD_CUSTOM_TARGET(git-describe COMMAND ${CMAKE_COMMAND} diff --git a/library/Core.cpp b/library/Core.cpp index edb00c45e..bdbb5c3b2 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2057,6 +2057,12 @@ void Core::onStateChange(color_ostream &out, state_change_event event) break; } + if (event == SC_MAP_LOADED && Version::is_prerelease()) + { + runCommand(out, "gui/prerelease-warning"); + std::cerr << "loaded map in prerelease build" << std::endl; + } + EventManager::onStateChange(out, event); buildings_onStateChange(out, event); diff --git a/library/DFHackVersion.cpp b/library/DFHackVersion.cpp index d3200a42f..744f3183b 100644 --- a/library/DFHackVersion.cpp +++ b/library/DFHackVersion.cpp @@ -33,5 +33,14 @@ namespace DFHack { return false; #endif } + + bool is_prerelease() + { + #ifdef DFHACK_PRERELEASE + return true; + #else + return false; + #endif + } } } diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 72267a5bf..a3a9eb070 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1418,6 +1418,7 @@ static const LuaWrapper::FunctionReg dfhack_module[] = { WRAP_VERSION_FUNC(getGitDescription, git_description), WRAP_VERSION_FUNC(getGitCommit, git_commit), WRAP_VERSION_FUNC(isRelease, is_release), + WRAP_VERSION_FUNC(isPrerelease, is_prerelease), { NULL, NULL } }; diff --git a/library/include/DFHackVersion.h b/library/include/DFHackVersion.h index f035e616a..67bf35df1 100644 --- a/library/include/DFHackVersion.h +++ b/library/include/DFHackVersion.h @@ -7,6 +7,7 @@ namespace DFHack { const char *git_description(); const char *git_commit(); bool is_release(); + bool is_prerelease(); } } @@ -17,4 +18,5 @@ namespace DFHack { #define DFHACK_GIT_DESCRIPTION (DFHack::Version::git_description()) #define DFHACK_GIT_COMMIT (DFHack::Version::git_commit()) #define DFHACK_IS_RELEASE (DFHack::Version::is_release()) + #define DFHACK_IS_PRERELEASE (DFHack::Version::is_prerelease()) #endif diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua new file mode 100644 index 000000000..53d612d41 --- /dev/null +++ b/scripts/gui/prerelease-warning.lua @@ -0,0 +1,36 @@ +-- Shows the warning about missing configuration file. +--[[=begin + +gui/prerelease-warning +====================== +Shows a warning on world load for pre-release builds. + +=end]] + +if not dfhack.isPrerelease() then qerror('not a prerelease build') end + +local gui = require 'gui' +local dlg = require 'gui.dialogs' + +local message = { + 'This is a prerelease build of DFHack. Some structures are likely', NEWLINE, + 'to be incorrect, resulting in crashes or save corruption', NEWLINE, + {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'} +} + +dfhack.print('\n') + +for k,v in ipairs(message) do + if type(v) == 'table' then + dfhack.color(v.pen) + dfhack.print(v.text) + else + dfhack.color(COLOR_YELLOW) + dfhack.print(v) + end +end + +dfhack.color(COLOR_RESET) +dfhack.print('\n\n') + +dlg.showMessage('Warning', message, COLOR_YELLOW) From 1329acc51602d3df677c93a115500d112e0cfd8e Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Dec 2015 20:34:48 -0500 Subject: [PATCH 065/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 027b3fa01..309c801b6 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 027b3fa0130712697d5563ab704b4c8e458cd029 +Subproject commit 309c801b63825f955eff628a35ca09ba46fff065 From 78d6b921270f55170a8a1ded4a97691cd3d3c4b9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Dec 2015 11:17:00 -0500 Subject: [PATCH 066/222] Change strangemood permitted skill checks to job checks permitted_skills was removed in 0.42 (dfhack/df-structures@6e2e8731) --- library/xml | 2 +- plugins/strangemood.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/xml b/library/xml index 309c801b6..6e2e8731d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 309c801b63825f955eff628a35ca09ba46fff065 +Subproject commit 6e2e8731d2c10a4a5394046ae48cc0cd16e9a049 diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index 8ad245c7c..382c03358 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -104,11 +104,11 @@ df::job_skill getMoodSkill (df::unit *unit) } if (!skills.size() && civ) { - if (civ->entity_raw->jobs.permitted_skill[job_skill::WOODCRAFT]) + if (civ->entity_raw->jobs.permitted_job[profession::WOODCRAFTER]) skills.push_back(job_skill::WOODCRAFT); - if (civ->entity_raw->jobs.permitted_skill[job_skill::STONECRAFT]) + if (civ->entity_raw->jobs.permitted_job[profession::STONECRAFTER]) skills.push_back(job_skill::STONECRAFT); - if (civ->entity_raw->jobs.permitted_skill[job_skill::BONECARVE]) + if (civ->entity_raw->jobs.permitted_job[profession::BONE_CARVER]) skills.push_back(job_skill::BONECARVE); } if (!skills.size()) From 3083b015254f9618a98546e279f83178a5a5aaf0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Dec 2015 11:26:45 -0500 Subject: [PATCH 067/222] Add new labors to manipulator --- plugins/manipulator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index ab790c7a0..a3f0f8ef8 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -170,6 +170,8 @@ const SkillColumn columns[] = { {9, 9, profession::POTTER, unit_labor::POTTERY, job_skill::POTTERY, "Po"}, {9, 9, profession::GLAZER, unit_labor::GLAZING, job_skill::GLAZING, "Gl"}, {9, 9, profession::WAX_WORKER, unit_labor::WAX_WORKING, job_skill::WAX_WORKING, "Wx"}, + {9, 9, profession::PAPERMAKER, unit_labor::PAPERMAKING, job_skill::PAPERMAKING, "Pa"}, + {9, 9, profession::BOOKBINDER, unit_labor::BOOKBINDING, job_skill::BOOKBINDING, "Bk"}, // Engineering {10, 12, profession::SIEGE_ENGINEER, unit_labor::SIEGECRAFT, job_skill::SIEGECRAFT, "En"}, {10, 12, profession::SIEGE_OPERATOR, unit_labor::SIEGEOPERATE, job_skill::SIEGEOPERATE, "Op"}, From eb1092da6ec4177786077d13b4f75da1215b37eb Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 12 Dec 2015 13:46:35 -0600 Subject: [PATCH 068/222] Update strangemood plugin according to actual game code --- library/xml | 2 +- plugins/strangemood.cpp | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/library/xml b/library/xml index 6e2e8731d..739101518 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6e2e8731d2c10a4a5394046ae48cc0cd16e9a049 +Subproject commit 739101518a8d9bb676851de3a07ff82f4cc26832 diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index 382c03358..f60c726df 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -56,6 +56,8 @@ bool isUnitMoodable (df::unit *unit) return false; if (!ENUM_ATTR(profession,moodable,unit->profession)) return false; + if (!Units::casteFlagSet(unit->race, unit->caste, caste_raw_flags::STRANGE_MOODS)) + return false; return true; } @@ -104,11 +106,11 @@ df::job_skill getMoodSkill (df::unit *unit) } if (!skills.size() && civ) { - if (civ->entity_raw->jobs.permitted_job[profession::WOODCRAFTER]) + if (civ->resources.permitted_skill[job_skill::WOODCRAFT]) skills.push_back(job_skill::WOODCRAFT); - if (civ->entity_raw->jobs.permitted_job[profession::STONECRAFTER]) + if (civ->resources.permitted_skill[job_skill::STONECRAFT]) skills.push_back(job_skill::STONECRAFT); - if (civ->entity_raw->jobs.permitted_job[profession::BONE_CARVER]) + if (civ->resources.permitted_skill[job_skill::BONECARVE]) skills.push_back(job_skill::BONECARVE); } if (!skills.size()) @@ -728,6 +730,8 @@ command_result df_strangemood (color_ostream &out, vector & parameters) case job_skill::WOODCRAFT: case job_skill::STONECRAFT: case job_skill::BONECARVE: + case job_skill::PAPERMAKING: // These aren't actually moodable skills + case job_skill::BOOKBINDING: // but the game still checks for them anyways job->job_type = job_type::StrangeMoodCrafter; break; case job_skill::TANNER: @@ -861,6 +865,8 @@ command_result df_strangemood (color_ostream &out, vector & parameters) case job_skill::CARPENTRY: case job_skill::WOODCRAFT: case job_skill::BOWYER: + case job_skill::PAPERMAKING: + case job_skill::BOOKBINDING: job->job_items.push_back(item = new df::job_item()); item->item_type = item_type::WOOD; item->quantity = base_item_count; @@ -960,6 +966,7 @@ command_result df_strangemood (color_ostream &out, vector & parameters) case job_skill::FORGE_WEAPON: case job_skill::FORGE_ARMOR: + // there are actually 2 distinct cases here, but they're identical case job_skill::FORGE_FURNITURE: case job_skill::METALCRAFT: filter = NULL; @@ -990,7 +997,7 @@ command_result df_strangemood (color_ostream &out, vector & parameters) item->item_type = item_type::BAR; item->mat_type = filter->getMaterial(); item->mat_index = filter->getMaterialIndex(); - item->quantity = base_item_count * 150; + item->quantity = base_item_count * 150; // BUGFIX - the game does not adjust here! item->min_dimension = 150; } else @@ -1012,7 +1019,7 @@ command_result df_strangemood (color_ostream &out, vector & parameters) } if (mats.size()) item->mat_index = mats[rng.df_trandom(mats.size())]; - item->quantity = base_item_count * 150; + item->quantity = base_item_count * 150; // BUGFIX - the game does not adjust here! item->min_dimension = 150; } break; @@ -1264,12 +1271,12 @@ command_result df_strangemood (color_ostream &out, vector & parameters) item->quantity = 1; if (item_type == item_type::BAR) { - item->quantity *= 150; + item->quantity *= 150; // BUGFIX - the game does not adjust here! item->min_dimension = 150; } if (item_type == item_type::CLOTH) { - item->quantity *= 10000; + item->quantity *= 10000; // BUGFIX - the game does not adjust here! item->min_dimension = 10000; } } From 7ef815afa8d450f97e61c99cfd8481c80b57613b Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 12 Dec 2015 17:58:58 -0600 Subject: [PATCH 069/222] apparently, casteFlagSet is a static function, despite its usefulness... --- plugins/strangemood.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index f60c726df..cc00535a8 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -26,6 +26,9 @@ #include "df/entity_raw.h" #include "df/builtin_mats.h" #include "df/general_ref_unit_workerst.h" +#include "df/creature_raw.h" +#include "df/caste_raw.h" +#include "df/caste_raw_flags.h" using std::string; using std::vector; @@ -46,6 +49,17 @@ using df::global::debug_nomoods; Random::MersenneRNG rng; +static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag) +{ + auto creature = df::creature_raw::find(race); + if (!creature) + return false; + auto craw = vector_get(creature->caste, caste); + if (!craw) + return false; + return craw->flags.is_set(flag); +} + bool isUnitMoodable (df::unit *unit) { if (!Units::isCitizen(unit)) @@ -56,7 +70,7 @@ bool isUnitMoodable (df::unit *unit) return false; if (!ENUM_ATTR(profession,moodable,unit->profession)) return false; - if (!Units::casteFlagSet(unit->race, unit->caste, caste_raw_flags::STRANGE_MOODS)) + if (!casteFlagSet(unit->race, unit->caste, caste_raw_flags::STRANGE_MOODS)) return false; return true; } From 270ff61fbd82f3f97bf6f9cf950271993ded2d7b Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sun, 13 Dec 2015 12:23:56 -0600 Subject: [PATCH 070/222] add parentheses around || that should be inside && --- plugins/autohauler.cpp | 2 +- plugins/autolabor.cpp | 2 +- plugins/rendermax/renderer_light.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/autohauler.cpp b/plugins/autohauler.cpp index a7a35797c..d7b233195 100644 --- a/plugins/autohauler.cpp +++ b/plugins/autohauler.cpp @@ -1136,7 +1136,7 @@ command_result autohauler (color_ostream &out, std::vector & param out << "All labors reset." << endl; return CR_OK; } - else if (parameters.size() == 1 && parameters[0] == "list" || parameters[0] == "status") + else if (parameters.size() == 1 && (parameters[0] == "list" || parameters[0] == "status")) { if (!enable_autohauler) { diff --git a/plugins/autolabor.cpp b/plugins/autolabor.cpp index 87b14729a..070744de0 100644 --- a/plugins/autolabor.cpp +++ b/plugins/autolabor.cpp @@ -1511,7 +1511,7 @@ command_result autolabor (color_ostream &out, std::vector & parame out << "All labors reset." << endl; return CR_OK; } - else if (parameters.size() == 1 && parameters[0] == "list" || parameters[0] == "status") + else if (parameters.size() == 1 && (parameters[0] == "list" || parameters[0] == "status")) { if (!enable_autolabor) { diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index 7dd6d46bc..5e6f2e2de 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -724,7 +724,7 @@ void lightingEngineViewscreen::doOcupancyAndLights() for(int i=0;iflows.size();i++) { df::flow_info* f=block->flows[i]; - if(f && f->density>0 && f->type==df::flow_type::Dragonfire || f->type==df::flow_type::Fire) + if(f && f->density>0 && (f->type==df::flow_type::Dragonfire || f->type==df::flow_type::Fire)) { df::coord2d pos=f->pos; pos=worldToViewportCoord(pos,vp,window2d); From 80ec5ab043828e1a237e488a0ad6b372ccf496b0 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sun, 13 Dec 2015 14:03:25 -0600 Subject: [PATCH 071/222] vim-style +-args. for example, "./dfhack +echo foo" would be equivalent to running ./dfhack and then typing "echo foo" into the console. uses shell argument splitting, so "./dfhack +somecommand 'foo bar' baz" does the right thing. See DFHack#755. --- library/Core.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/library/Core.cpp b/library/Core.cpp index bdbb5c3b2..283fca927 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -62,6 +62,7 @@ using namespace std; using namespace DFHack; #include "df/ui.h" +#include "df/ui_sidebar_menus.h" #include "df/world.h" #include "df/world_data.h" #include "df/interfacest.h" @@ -1549,6 +1550,39 @@ bool Core::Init() if (!server->listen(RemoteClient::GetDefaultPort())) cerr << "TCP listen failed.\n"; + vector & args = df::global::ui_sidebar_menus->unk.anon_2; + for (auto it = args.begin(); it != args.end(); ) + { + const string & first = **it; + if (first.length() > 0 && first[0] == '+') + { + vector cmd; + for (it++; it != args.end(); it++) { + const string & arg = **it; + if (arg.length() > 0 && arg[0] == '+') + { + break; + } + cmd.push_back(arg); + } + + color_ostream_proxy out(getConsole()); + if (runCommand(out, first.substr(1), cmd) != CR_OK) + { + cerr << "Error running command: " << first.substr(1); + for (auto it2 = cmd.begin(); it2 != cmd.end(); it2++) + { + cerr << " " << *it2; + } + cerr << "\n"; + } + } + else + { + it++; + } + } + cerr << "DFHack is running.\n"; return true; } From 21631b3712a919b6b2cbb25945306d2732d6fd5c Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 03:30:08 +0000 Subject: [PATCH 072/222] Compile.rst: major updates to Windows and OSX sections; minor to Linux; new section re compiling documentation; many small fixes. Introduction.rst: fix typo and remove erroneous end version for OSX. --- docs/Compile.rst | 327 +++++++++++++++++++++++++++++++++++++----- docs/Introduction.rst | 4 +- 2 files changed, 297 insertions(+), 34 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 6b0cf6857..fe5c73652 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -10,6 +10,7 @@ and `install the latest release instead `. .. contents:: :depth: 2 +.. _compile-how-to-get-the-code: How to get the code =================== @@ -17,7 +18,7 @@ DFHack doesn't have any kind of system of code snapshots in place, so you will h get code from the github repository using git. How to get git is described under the instructions for each platform. -To get the code:: +To get the latest release code (master branch):: git clone --recursive https://github.com/DFHack/dfhack cd dfhack @@ -25,9 +26,26 @@ To get the code:: If your version of git does not support the ``--recursive`` flag, you will need to omit it and run ``git submodule update --init`` after entering the dfhack directory. +To get the latest development code (develop branch):: + + git clone --recursive https://github.com/DFHack/dfhack + cd dfhack + git checkout develop + git submodule update + +**Important note on submodule update**: + +It is necessary to run ``git submodule update`` every time you change Git branch, +for example when switching between master and develop branches and back. + + +Contributing to DFHack +====================== If you want to get involved with the development, create an account on Github, make a clone there and then use that as your remote repository instead. -We'd love that; join us on IRC (#dfhack channel on freenode) if you need help. + +We'd love that; join us on IRC (#dfhack channel on freenode) for discussion, +and whenever you need help. Build types @@ -40,7 +58,8 @@ Without specifying a build type or 'None', cmake uses the ``CMAKE_CXX_FLAGS`` variable for building. Valid and useful build types include 'Release', 'Debug' and -'RelWithDebInfo'. 'Debug' is not available on Windows. +'RelWithDebInfo'. +'Debug' is not available on Windows. Linux @@ -55,11 +74,14 @@ We assume that any Linux platform will have ``git`` available. To build DFHack you need a version of GCC 4.x capable of compiling for 32-bit (i386) targets. GCC 4.5 is easiest to work with due to avoiding libstdc++ issues -(see below), but any later 4.x version should work as well. GCC 5.x will not -work due to ABI changes (the entire plugin loading system won't work, for -example). On 64-bit distributions, you'll need the multilib development tools -and libraries (``gcc-multilib`` or ``gcc-4.x-multilib`` on Debian). Note that -installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will +(see below), but any version from 4.5 onwards (including 5.x) will work. + +On 64-bit distributions, you'll need the multilib development tools and libraries: + +* ``gcc-multilib`` and ``g++-multilib`` +* On Debian: ``gcc-4.x-multilib`` / ``g++-4.x-multilib`` + +Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will typically *not* work, as it depends on several other 32-bit libraries that conflict with system libraries. Alternatively, you might be able to use ``lxc`` to @@ -71,13 +93,24 @@ Before you can build anything, you'll also need ``cmake``. It is advisable to al You also need perl and the XML::LibXML and XML::LibXSLT perl packages (for the code generation parts). You should be able to find them in your distro repositories. -* On Arch linux, ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) -* On 64-bit Ubuntu, ``apt-get install zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl``. -* On 32-bit Ubuntu, ``apt-get install gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. -* Debian-derived distros should have similar requirements. - To build Stonesense, you'll also need OpenGL headers. +Here are some package install commands that should give you everything you need: + +* On Arch linux: + + * ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) + +* On 64-bit Ubuntu: + + * ``apt-get install zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl gcc-multilib g++-multilib``. + +* On 32-bit Ubuntu: + + * ``apt-get install gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. + +* Debian-derived distros should have similar requirements. + Build ----- @@ -85,11 +118,12 @@ Building is fairly straightforward. Enter the ``build`` folder (or create an empty folder in the DFHack directory to use instead) and start the build like this:: cd build - cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/home/user/DF + cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= make install -Obviously, replace the install path with path to your DF. This will build the library -along with the normal set of plugins and install them into your DF folder. + should be a path to a copy of Dwarf Fortress, of the appropriate +version for the DFHack you are building. This will build the library along +with the normal set of plugins and install them into your DF folder. Alternatively, you can use ccmake instead of cmake:: @@ -101,7 +135,6 @@ This will show a curses-based interface that lets you set all of the extra options. You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui program. - Incompatible libstdc++ ~~~~~~~~~~~~~~~~~~~~~~ When compiling dfhack yourself, it builds against your system libstdc++. @@ -136,10 +169,14 @@ following environment variable:: #. Download and unpack a copy of the latest DF #. Install Xcode from Mac App Store -#. Open Xcode, go to Preferences > Downloads, and install the Command Line Tools. + +#. Install the XCode Command Line Tools by running the following command:: + + xcode-select --install + #. Install dependencies - Using `Homebrew `_:: + Using `Homebrew `_ (recommended):: brew tap homebrew/versions brew install git @@ -153,6 +190,31 @@ following environment variable:: Macports will take some time - maybe hours. At some point it may ask you to install a Java environment; let it do so. + Note that it is recommended to use Homebrew instead of MacPorts, + as it is generally cleaner, quicker, and smarter. It also doesn't + require constant use of sudo. + +#. Additional notes for El Capitan (OSX 10.11) users: + + #. You will probably find that gcc45 will fail to install on OSX 10.11, + due to the presence of XCode 7. + #. There are two workarounds: + + #. Install GCC 5.x instead (``brew install gcc5``), and then after compile + replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 + version of this file:: + + cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && + ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . + + #. Install XCode 6, which is available as a free download from the Apple + Developer Center. + + #. Either install this as your only XCode, or install it additionally + to XCode 7 and then switch between them using ``xcode-select`` + #. Ensure XCode 6 is active before attempting to install GCC 4.5 and + whenever you are compiling DFHack with GCC 4.5. + #. Install perl dependencies 1. ``sudo cpan`` @@ -168,10 +230,7 @@ following environment variable:: 2. ``install XML::LibXML`` 3. ``install XML::LibXSLT`` -#. Get the dfhack source:: - - git clone --recursive https://github.com/DFHack/dfhack.git - cd dfhack +#. Get the DFHack source as per section `compile-how-to-get-the-code`, above. #. Set environment variables: @@ -193,6 +252,7 @@ following environment variable:: make make install +.. _compile-windows: Windows ======= @@ -200,27 +260,118 @@ On Windows, DFHack replaces the SDL library distributed with DF. Dependencies ------------ -You will need some sort of Windows port of git, or a GUI. Some examples: +You will need the following: + +* Microsoft Visual Studio 2010 SP1, with the C++ language +* Git +* CMake +* Perl with XML::LibXML and XML::LibXSLT + + * It is recommended to install StrawberryPerl, which includes both. + +Microsoft Visual Studio 2010 SP1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The Express version is sufficient. + +You can grab it from `Microsoft's site `_. + +You'll also need the Visual Studio 2010 SP1 update, which is obtained from +Windows Update. After installing Visual Studio, be sure to go to Windows Update +and check for and install the SP1 update. If no update is found, check that +your Windows Update settings include "Updates from all Microsoft products". + +You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE +and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* +at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* + +It is vital that you do use SP1 as, while building with the original release +of Visual Studio 2010 (RTM) may succeed, it will result in non-working DFHack +binaries that crash when connecting to Dwarf Fortress. + +Additional dependencies: installing with the Chocolatey Package Manager +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The remainder of dependencies - git, cmake and StrawberryPerl - can be most +easily installed using the Chocolatey Package Manger. This is a system that +attempts to bring a Linux-like package manager to Windows. + +Think "apt-get for Windows." + +Chocolatey is the recommended way of installing the required dependencies +on Windows, as it's less work and installs known-good utilities with the +correct setup (especially PATH). + +To install Chocolatey and the required dependencies: + +* Go to https://chocolatey.org in a web browser +* At the top of the page it will give you the install command to copy + + * Copy the first one, that starts ``@powershell ...`` + * It won't be repeated here in case it changes in future Chocolatey releases. + +* Open an elevated (Admin) cmd.exe window + + * On Windows 8 and later this can be easily achieved by: + + * right-clicking on the Start Menu, or pressing Win+X. + * choosing "Command Prompt (Admin)" + + * On earlier Windows: find cmd.exe in Start Menu, right click + and choose Open As Administrator. + +* Paste in the Chocolatey install command, hit enter, and follow all prompts +* Close your Admin cmd.exe window, and open another Admin cmd.exe window +* Run the following command:: + + choco install git cmake strawberryperl -y + +* Close the Admin cmd.exe window; you're done! + +You can now use all of the above commands from any future cmd.exe window, +and it does not need to be elevated (Admin). + +**NOTE**: the above assumes you have none of Git, cmake and StrawberryPerl +already installed. If you do have one, you may want to remove that entry +from the install command listed above. + +Additional dependencies: installing manually +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is no longer generally recommended, as Chocolatey makes life a lot easier. +Use only if you have special requirements - or to check that your +already-installed versions of the below programs are as required for DFHack. + +Git +^^^ +Some examples: * `Git for Windows `_ (command-line and GUI) * `tortoisegit `_ (GUI and File Explorer integration) -You need ``cmake``. Get the win32 installer version from +CMake +^^^^^ +You can get the win32 installer version from `the official site `_. It has the usual installer wizard. Make sure you let it add its binary folder to your binary search PATH so the tool can be later run from anywhere. -You'll need a copy of Microsoft Visual C++ 2010. The Express version is sufficient. -Grab it from `Microsoft's site `_. -You'll also need the Visual Studio 2010 SP1 update. +Perl / Strawberry Perl +^^^^^^^^^^^^^^^^^^^^^^ For the code generation parts, you'll need perl with XML::LibXML and XML::LibXSLT. `Strawberry Perl `_ works nicely for this and includes all of the required packages. +After install, ensure Perl is in your user's PATH directory. This can be edited +from ``Control Panel -> System -> Advanced System Settings -> Environment Variables``. + +Be sure that all of the following three directories are present, in this order: + +* ``\c\bin`` +* ``\perl\site\bin`` +* ``\perl\bin`` + If you already have a different version of perl (for example the one from cygwin), you can run into some trouble. Either remove the other perl install from PATH, or -install libxml and libxslt for it instead. +install XML::LibXML and XML::LibXSLT for it using CPAN. Build ----- @@ -229,6 +380,7 @@ with a script that's used for picking the DF path. First, run ``set_df_path.vbs`` and point the dialog that pops up at your DF folder that you want to use for development. + Next, run one of the scripts with ``generate`` prefix. These create the MSVC solution file(s): * ``all`` will create a solution with everything enabled (and the kitchen sink). @@ -240,12 +392,123 @@ Next, run one of the scripts with ``generate`` prefix. These create the MSVC sol Then you can either open the solution with MSVC or use one of the msbuild scripts: +Building/installing from the command line: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Scripts with ``build`` prefix will only build DFHack. * Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. * Scripts with ``package`` prefix will build and create a .zip package of DFHack. -When you open the solution in MSVC, make sure you never use the Debug builds. Those aren't -binary-compatible with DF. If you try to use a debug build with DF, you'll only get crashes. +Building/installing from the Visual Studio IDE: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +After running the generate script as above, you will have a new folder called VC2010. +Open the file ``dfhack.sln`` from that folder - and if you have multiple versions of VS +installed, make sure you choose Visual Studio 2010. + +The first thing you must then do is change the build type. It defaults to Debug, +but this cannot be used on Windows. Debug is not binary-compatible with DF. +If you try to use a debug build with DF, you'll only get crashes. For this reason the Windows "debug" scripts actually do RelWithDebInfo builds, -so pick either Release or RelWithDebInfo build and build the INSTALL target. +so after loading the Solution, change the Build Type to either either Release +or RelWithDebInfo build. + +Then build the ``INSTALL`` target listed under ``CMakePredefinedTargets``. + + +########################## +Building the documentation +########################## + +DFHack documentation, like the file you are reading now, is created as .rst files, +which are in `reStructuredText (reST) `_ format. +This is a documenation format that has come from the Python community. It is very +similar in concept - and in syntax - to Markdown, as found on Github and many other places. +However it is more advanced than Markdown, and can be compiled to sophisticated HTML files +with tables of contents, cross-linking, references and more. + +The documentation can be built during the standard DFHack compilation procedure, +but this has been disabled by default. You only need to build the docs if you're changing +them, or perhaps if you want a local HTML copy; otherwise, read them easily online at +`ReadTheDoc's DFHack hosted documentation `_. + +(Note that even if you do want a local copy, it is certainly not necesesary to compile the +documentation in order to read it. Like Markdown, reST documents are designed to be just as +readable in a plain-text editor as they are in HTML format. The main thing you lose in plain +text format is links.) + + +Enabling documentation building +=============================== +First, make sure you have followed all the necessary steps for your platform as outlined +in the rest of this document. + +#. Edit ``CMakeLists.txt`` in the root folder of your dfhack directory. +#. Find the line:: + + OPTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) + +#. Change ``OFF`` to ``ON`` and save. +#. Now compile as normal, and the .rst documents will be compiled to HTML in + ``/docs/html/docs/`` under your dfhack directory. +#. If you are committing to DFHack, be sure not to add your changed ``CMakeLists.txt`` to any commit. + + +Required dependencies +===================== +In order to build the documentation, you must have Python with Sphinx +version 1.3.1 or later. Both Python 2.x and 3.x are supported. + +When installing Sphinx from OS package managers, be aware that there is +another program called Sphinx, completely unrelated to documentation management. +Be sure you are installing the right Sphinx! + + +Linux +-----PTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." ON) +Most Linux distributions will include Python as standard, including the pip +package manager. + +Check your package manager to see if Sphinx 1.3.1 or later is available, +but at the time of writing Ubuntu for example only has 1.2.x. + +You can instead install the Python module with:: + + pip install sphinx + +If you run this as a normal user it will install a local copy for your user only. +Run it with sudo if you want a system-wide install. + + +Mac OS X +-------- +OS X has Python 2.7 installed by default, but it does not have the pip package manager. + +You can install Homebrew's Python 3, which includes pip, and then install the +latest Sphinx using pip:: + + brew install python3 + pip3 install sphinx + +Alternatively, you can simply install Sphinx 1.3.x directly from Homebrew:: + + brew install sphinx-doc + +This will directly install Sphinx for OS X's system Python 2.7, without needing pip. + +Either method works; if you plan to use Python for other purposes, it might best +to install Homebrew's Python 3 so that you have the latest Python as well as pip. +If not, just installing sphinx-doc into OS X's system Python 2.7 is fine. + + +Windows +------- +Use the Chocolatey package manager to install Python and pip, +then use pip to install Sphinx. + +Run the following commands from an elevated (Admin) cmd.exe, after installing +Chocolatey as outlined in the `Windows section `:: + + choco install python pip -y + +Then close that Admin cmd.exe, re-open another Admin cmd.exe, and run:: + pip install sphinx diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 8a82e0f10..64b6b36a5 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -37,8 +37,8 @@ allows easier development of new tools. As an open-source project under Installing DFHack ================= -DFHack is available for the SDL version of Dwarf Frtress on Windows, -any modern Linux distribution, and OS X (10.6.8 to 10.9). +DFHack is available for the SDL version of Dwarf Fortress on Windows, +any modern Linux distribution, and Mac OS X (10.6.8 and later). It is possible to use Windows DF+DFHack under Wine on Linux or OS X. Most releases only support the version of DF mentioned in their title - for From 5aae535394b9227cd5617dee24f77331e07923b5 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 04:10:00 +0000 Subject: [PATCH 073/222] Building documentation section: now with a non-stupid way of doing it! And other minor fixes. --- docs/Compile.rst | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index fe5c73652..49bad1502 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -441,15 +441,10 @@ Enabling documentation building First, make sure you have followed all the necessary steps for your platform as outlined in the rest of this document. -#. Edit ``CMakeLists.txt`` in the root folder of your dfhack directory. -#. Find the line:: +Then, to compile documentation with DFHack, pass the flag ``-DBUILD_DOCS:bool=ON`` to cmake. +For example:: - OPTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) - -#. Change ``OFF`` to ``ON`` and save. -#. Now compile as normal, and the .rst documents will be compiled to HTML in - ``/docs/html/docs/`` under your dfhack directory. -#. If you are committing to DFHack, be sure not to add your changed ``CMakeLists.txt`` to any commit. + cmake .. -DCMAKE_BUILD_TYPE:string=Release -DBUILD_DOCS:bool=ON -DCMAKE_INSTALL_PREFIX= Required dependencies From f26982f1e999b8f1f8fe6e67a04e0be49338d7e7 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 04:11:39 +0000 Subject: [PATCH 074/222] And other minor fixes (actually in this commit this time.) --- docs/Compile.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 49bad1502..93d7c5d23 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -26,16 +26,14 @@ To get the latest release code (master branch):: If your version of git does not support the ``--recursive`` flag, you will need to omit it and run ``git submodule update --init`` after entering the dfhack directory. -To get the latest development code (develop branch):: +To get the latest development code (develop branch), clone as above and then:: - git clone --recursive https://github.com/DFHack/dfhack - cd dfhack git checkout develop git submodule update **Important note on submodule update**: -It is necessary to run ``git submodule update`` every time you change Git branch, +You must run ``git submodule update`` every time you change Git branch, for example when switching between master and develop branches and back. @@ -454,11 +452,12 @@ version 1.3.1 or later. Both Python 2.x and 3.x are supported. When installing Sphinx from OS package managers, be aware that there is another program called Sphinx, completely unrelated to documentation management. -Be sure you are installing the right Sphinx! +Be sure you are installing the right Sphinx; it may be called ``python-sphinx``, +for example. To avoid doubt, pip can be used instead as detailed below. Linux ------PTION(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." ON) +----- Most Linux distributions will include Python as standard, including the pip package manager. From 1afc0afb9ce865179c4e71d2b6c2134651427e73 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 06:08:25 +0000 Subject: [PATCH 075/222] Some further fixes, updates and elaborations. Had to convert the Mac list to bullet rather than numbered, as HTML numbering keeps breaking (resets to 1 in the middle of the list in several places) for reasons I can't figure out. --- docs/Compile.rst | 174 +++++++++++++++++++++++++++--------------- docs/Contributing.rst | 2 + 2 files changed, 113 insertions(+), 63 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 93d7c5d23..a7286a382 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -15,7 +15,7 @@ and `install the latest release instead `. How to get the code =================== DFHack doesn't have any kind of system of code snapshots in place, so you will have to -get code from the github repository using git. How to get git is described under +get code from the Github repository using git. How to get git is described under the instructions for each platform. To get the latest release code (master branch):: @@ -31,7 +31,7 @@ To get the latest development code (develop branch), clone as above and then:: git checkout develop git submodule update -**Important note on submodule update**: +**Important note regarding submodule update and changing branches**: You must run ``git submodule update`` every time you change Git branch, for example when switching between master and develop branches and back. @@ -45,6 +45,9 @@ Github, make a clone there and then use that as your remote repository instead. We'd love that; join us on IRC (#dfhack channel on freenode) for discussion, and whenever you need help. +For lots more details on contributing to DFHack, including pull requests, code format, +and more, please see `contributing-code`. + Build types =========== @@ -57,7 +60,7 @@ Without specifying a build type or 'None', cmake uses the Valid and useful build types include 'Release', 'Debug' and 'RelWithDebInfo'. -'Debug' is not available on Windows. +'Debug' is not available on Windows, use 'RelWithDebInfo' instead. Linux @@ -68,16 +71,17 @@ Dependencies ------------ DFHack is meant to be installed into an existing DF folder, so get one ready. -We assume that any Linux platform will have ``git`` available. +We assume that any Linux platform will have ``git`` available (though it may +require installing from your package manager.) -To build DFHack you need a version of GCC 4.x capable of compiling for 32-bit +To build DFHack you need GCC version 4.5 or later, capable of compiling for 32-bit (i386) targets. GCC 4.5 is easiest to work with due to avoiding libstdc++ issues (see below), but any version from 4.5 onwards (including 5.x) will work. On 64-bit distributions, you'll need the multilib development tools and libraries: * ``gcc-multilib`` and ``g++-multilib`` -* On Debian: ``gcc-4.x-multilib`` / ``g++-4.x-multilib`` +* On Debian: ``gcc-4.x-multilib`` and ``g++-4.x-multilib`` Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will typically *not* work, as it depends on several other 32-bit libraries that @@ -93,19 +97,19 @@ You should be able to find them in your distro repositories. To build Stonesense, you'll also need OpenGL headers. -Here are some package install commands that should give you everything you need: +Here are some package install commands for various platforms: * On Arch linux: - * ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) + * For the required Perl modules: ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) * On 64-bit Ubuntu: - * ``apt-get install zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl gcc-multilib g++-multilib``. + * ``apt-get install gcc cmake git gcc-multilib g++-multilib zlib1g-dev:i386 libxml-libxml-perl libxml-libxslt-perl``. * On 32-bit Ubuntu: - * ``apt-get install gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. + * ``apt-get install gcc cmake git gcc-multilib g++-multilib zlib1g-dev libxml-libxml-perl libxml-libxslt-perl``. * Debian-derived distros should have similar requirements. @@ -130,7 +134,7 @@ Alternatively, you can use ccmake instead of cmake:: make install This will show a curses-based interface that lets you set all of the -extra options. You can also use a cmake-friendly IDE like KDevelop 4 +extra options. You can also use a cmake-friendly IDE like KDevelop 4 or the cmake-gui program. Incompatible libstdc++ @@ -138,12 +142,12 @@ Incompatible libstdc++ When compiling dfhack yourself, it builds against your system libstdc++. When Dwarf Fortress runs, it uses a libstdc++ shipped with the binary, which comes from GCC 4.5 and is incompatible with code compiled with newer GCC versions. -This manifests itself with the error message:: +This manifests itself with an error message such as:: ./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by ./hack/libdfhack.so) -To fix this, you can compile with GCC 4.5 or remove the libstdc++ shipped with +To fix this you can compile with GCC 4.5 or remove the libstdc++ shipped with DF, which causes DF to use your system libstdc++ instead:: cd /path/to/DF/ @@ -152,7 +156,9 @@ DF, which causes DF to use your system libstdc++ instead:: Note that distributing binaries compiled with newer GCC versions requires end- users to delete libstdc++ themselves and have a libstdc++ on their system from the same GCC version or newer. For this reason, distributing anything compiled -with GCC versions newer than 4.8 is discouraged. +with GCC versions newer than 4.5 is discouraged. In the future we may start +bundling a later libstdc++ as part of the DFHack package, so as to enable +compilation-for-distribution with a GCC newer than 4.5. Mac OS X ======== @@ -165,14 +171,14 @@ following environment variable:: export MACOSX_DEPLOYMENT_TARGET=10.9 -#. Download and unpack a copy of the latest DF -#. Install Xcode from Mac App Store +* Download and unpack a copy of the latest DF +* Install Xcode from Mac App Store -#. Install the XCode Command Line Tools by running the following command:: +* Install the XCode Command Line Tools by running the following command:: xcode-select --install -#. Install dependencies +* Install dependencies Using `Homebrew `_ (recommended):: @@ -188,66 +194,92 @@ following environment variable:: Macports will take some time - maybe hours. At some point it may ask you to install a Java environment; let it do so. - Note that it is recommended to use Homebrew instead of MacPorts, - as it is generally cleaner, quicker, and smarter. It also doesn't - require constant use of sudo. + It is recommended to use Homebrew instead of MacPorts, as it is generally + cleaner, quicker, and smarter. For example, installing + MacPort's GCC 4.5 will install more than twice as many dependencies + as Homebrew's will, and all in both 32bit and 64bit variants. + Homebrew also doesn't require constant use of sudo. -#. Additional notes for El Capitan (OSX 10.11) users: +* Additional notes for El Capitan (OSX 10.11) and XCode 7.x users - #. You will probably find that gcc45 will fail to install on OSX 10.11, - due to the presence of XCode 7. - #. There are two workarounds: + * You will probably find that gcc45 will fail to install on OSX 10.11, + or any older OSX that is using XCode 7. + * There are two workarounds: - #. Install GCC 5.x instead (``brew install gcc5``), and then after compile + * Install GCC 5.x instead (``brew install gcc5``), and then after compile replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 version of this file:: cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . - #. Install XCode 6, which is available as a free download from the Apple + * Install XCode 6, which is available as a free download from the Apple Developer Center. - #. Either install this as your only XCode, or install it additionally + * Either install this as your only XCode, or install it additionally to XCode 7 and then switch between them using ``xcode-select`` - #. Ensure XCode 6 is active before attempting to install GCC 4.5 and + * Ensure XCode 6 is active before attempting to install GCC 4.5 and whenever you are compiling DFHack with GCC 4.5. -#. Install perl dependencies +* Install Perl dependencies + + * Using system Perl + + * ``sudo cpan`` + + If this is the first time you've run cpan, you will need to go through the setup + process. Just stick with the defaults for everything and you'll be fine. + + If you are running OS X 10.6 (Snow Leopard) or earlier, good luck! + You'll need to open a separate Terminal window and run:: + + sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml - 1. ``sudo cpan`` + * ``install XML::LibXML`` + * ``install XML::LibXSLT`` - If this is the first time you've run cpan, you will need to go through the setup - process. Just stick with the defaults for everything and you'll be fine. + * In a separate, local Perl install - If you are running OS X 10.6 (Snow Leopard) or earlier, good luck! - You'll need to open a separate Terminal window and run:: + This method gives you a cleaner, local Perl 5 setup. - sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml + * Visit http://perlbrew.pl/ in a browser + * Copy and run the first listed command, that begins ``\curl -L ...`` + * Re-login to your shell - 2. ``install XML::LibXML`` - 3. ``install XML::LibXSLT`` + You now have a new, local copy of the latest version of Perl installed in ``~/perl5``. -#. Get the DFHack source as per section `compile-how-to-get-the-code`, above. + It will now be the default perl for your user as perlbrew adds appropriate shell + commands to your current shell's .profile (or equivalent file.) -#. Set environment variables: + You can now run ``cpan`` and the install commands shown above. You do not need + to prefix it with ``sudo`` (and should not do so.) The resulting CPAN setup + will be much quicker than with system Perl. - Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: + This also means you can migrate your + current Perl setup - including CPAN setup/modules - by migrating your home directory, + and it is also immune to changes from OS updates. + +* Get the DFHack source as per section `compile-how-to-get-the-code`, above. + +* Set environment variables + + Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: export CC=/usr/local/bin/gcc-4.5 export CXX=/usr/local/bin/g++-4.5 - Macports:: + Macports:: export CC=/opt/local/bin/gcc-mp-4.5 export CXX=/opt/local/bin/g++-mp-4.5 -#. Build dfhack:: + Change the version numbers appropriately if you installed a different version of GCC. + +* Build dfhack:: mkdir build-osx cd build-osx cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory - make make install .. _compile-windows: @@ -269,20 +301,20 @@ You will need the following: Microsoft Visual Studio 2010 SP1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The Express version is sufficient. +The free Express version is sufficient. You can grab it from `Microsoft's site `_. You'll also need the Visual Studio 2010 SP1 update, which is obtained from Windows Update. After installing Visual Studio, be sure to go to Windows Update -and check for and install the SP1 update. If no update is found, check that +and check for and install the SP1 update. If no update is found, check that your Windows Update settings include "Updates from all Microsoft products". You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* -It is vital that you do use SP1 as, while building with the original release +It is vital that you use SP1 as, while building with the original release of Visual Studio 2010 (RTM) may succeed, it will result in non-working DFHack binaries that crash when connecting to Dwarf Fortress. @@ -295,15 +327,15 @@ attempts to bring a Linux-like package manager to Windows. Think "apt-get for Windows." Chocolatey is the recommended way of installing the required dependencies -on Windows, as it's less work and installs known-good utilities with the -correct setup (especially PATH). +as it's less work and installs known-good utilities with the correct setup +(especially PATH). To install Chocolatey and the required dependencies: * Go to https://chocolatey.org in a web browser * At the top of the page it will give you the install command to copy - * Copy the first one, that starts ``@powershell ...`` + * Copy the first one, which starts ``@powershell ...`` * It won't be repeated here in case it changes in future Chocolatey releases. * Open an elevated (Admin) cmd.exe window @@ -317,19 +349,23 @@ To install Chocolatey and the required dependencies: and choose Open As Administrator. * Paste in the Chocolatey install command, hit enter, and follow all prompts -* Close your Admin cmd.exe window, and open another Admin cmd.exe window +* Close this cmd.exe window and open another Admin cmd.exe in the same way * Run the following command:: choco install git cmake strawberryperl -y * Close the Admin cmd.exe window; you're done! -You can now use all of the above commands from any future cmd.exe window, -and it does not need to be elevated (Admin). +You can now use all of the above commands from any future cmd.exe window. +You only need Admin/elevated cmd.exe for running choco install commands; +for all other purposes, including compiling DFHack, you should use +a normal cmd.exe. **NOTE**: the above assumes you have none of Git, cmake and StrawberryPerl already installed. If you do have one, you may want to remove that entry -from the install command listed above. +from the install command listed above - or, better, uninstall the copy you +have now and re-install via Chocolatey, so that it can manage that program +in future. Additional dependencies: installing manually ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -367,7 +403,7 @@ Be sure that all of the following three directories are present, in this order: * ``\perl\site\bin`` * ``\perl\bin`` -If you already have a different version of perl (for example the one from cygwin), +If you already have a different version of Perl (for example the one from Cygwin), you can run into some trouble. Either remove the other perl install from PATH, or install XML::LibXML and XML::LibXSLT for it using CPAN. @@ -376,8 +412,9 @@ Build There are several different batch files in the ``build`` folder along with a script that's used for picking the DF path. -First, run ``set_df_path.vbs`` and point the dialog that pops up at your -DF folder that you want to use for development. +First, run ``set_df_path.vbs`` and point the dialog that pops up at +a suitable DF installation which is of the appropriate version for the DFHack +you are compiling. Next, run one of the scripts with ``generate`` prefix. These create the MSVC solution file(s): @@ -396,18 +433,29 @@ Building/installing from the command line: * Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. * Scripts with ``package`` prefix will build and create a .zip package of DFHack. +Compiling from the command line is generally the quickest and easiest option. +However be aware that due to the limitations of cmd.exe - especially in versions of +Windows prior to Windows 10 - it can be very hard to see what happens during a build. +If you get a failure, you may miss important errors or warnings due to the tiny window size +and extremely limieted scrollback. For that reason you may prefer to compile +in the IDE which will show all build output. + +Alternatively (or additionally), consider installing an improved Windows terminal +such as `Cmder `_. Easily installed through Chocolatey with: +``choco install cmder``. + Building/installing from the Visual Studio IDE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After running the generate script as above, you will have a new folder called VC2010. -Open the file ``dfhack.sln`` from that folder - and if you have multiple versions of VS -installed, make sure you choose Visual Studio 2010. +Open the file ``dfhack.sln`` inside that folder. If you have multiple versions of +Visual Studio installed, make sure you open with Visual Studio 2010. The first thing you must then do is change the build type. It defaults to Debug, but this cannot be used on Windows. Debug is not binary-compatible with DF. -If you try to use a debug build with DF, you'll only get crashes. -For this reason the Windows "debug" scripts actually do RelWithDebInfo builds, -so after loading the Solution, change the Build Type to either either Release -or RelWithDebInfo build. +If you try to use a debug build with DF, you'll only get crashes and for this +reason the Windows "debug" scripts actually do RelWithDebInfo builds. +After loading the Solution, change the Build Type to either ``Release`` +or ``RelWithDebInfo``. Then build the ``INSTALL`` target listed under ``CMakePredefinedTargets``. diff --git a/docs/Contributing.rst b/docs/Contributing.rst index cd2495922..085949700 100644 --- a/docs/Contributing.rst +++ b/docs/Contributing.rst @@ -5,6 +5,8 @@ How to contribute to DFHack .. contents:: +.. _contributing-code: + Contributing Code ================= Several things should be kept in mind when contributing code to DFHack. From 1f928a82922aab4cafc0ae508718b68f5f84d6fc Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 06:16:48 +0000 Subject: [PATCH 076/222] Typo --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index a7286a382..b2c73b413 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -437,7 +437,7 @@ Compiling from the command line is generally the quickest and easiest option. However be aware that due to the limitations of cmd.exe - especially in versions of Windows prior to Windows 10 - it can be very hard to see what happens during a build. If you get a failure, you may miss important errors or warnings due to the tiny window size -and extremely limieted scrollback. For that reason you may prefer to compile +and extremely limited scrollback. For that reason you may prefer to compile in the IDE which will show all build output. Alternatively (or additionally), consider installing an improved Windows terminal From 417f9a26aa48e8dd708d5b4059bf395e9ab41173 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 07:06:23 +0000 Subject: [PATCH 077/222] Minor bullet point fixes in Mac list --- docs/Compile.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index b2c73b413..03742dcb1 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -203,23 +203,23 @@ following environment variable:: * Additional notes for El Capitan (OSX 10.11) and XCode 7.x users * You will probably find that gcc45 will fail to install on OSX 10.11, - or any older OSX that is using XCode 7. + or any older OSX that is using XCode 7. * There are two workarounds: * Install GCC 5.x instead (``brew install gcc5``), and then after compile - replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 - version of this file:: + replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 + version of this file:: cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . * Install XCode 6, which is available as a free download from the Apple - Developer Center. + Developer Center. * Either install this as your only XCode, or install it additionally - to XCode 7 and then switch between them using ``xcode-select`` + to XCode 7 and then switch between them using ``xcode-select`` * Ensure XCode 6 is active before attempting to install GCC 4.5 and - whenever you are compiling DFHack with GCC 4.5. + whenever you are compiling DFHack with GCC 4.5. * Install Perl dependencies @@ -260,7 +260,6 @@ following environment variable:: and it is also immune to changes from OS updates. * Get the DFHack source as per section `compile-how-to-get-the-code`, above. - * Set environment variables Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: From e1777fcc6becb608113dc497a556a715f06ad4ad Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 14:16:51 +0000 Subject: [PATCH 078/222] OSX: Simplify the new local Perl section, just mention what perlbrew as it's obvious enough how to use it from the webpage and most people probably won't be interested anyway. --- docs/Compile.rst | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 03742dcb1..be076fd81 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -240,24 +240,14 @@ following environment variable:: * In a separate, local Perl install - This method gives you a cleaner, local Perl 5 setup. + Rather than using system Perl, you might also want to consider + the Perl manager, `Perlbrew `_. - * Visit http://perlbrew.pl/ in a browser - * Copy and run the first listed command, that begins ``\curl -L ...`` - * Re-login to your shell + This installs Perl 5 locally in ``~/perl5/`` and provides an easy + way to install the latest Perl 5 and run CPAN against it, without + ``sudo``. - You now have a new, local copy of the latest version of Perl installed in ``~/perl5``. - - It will now be the default perl for your user as perlbrew adds appropriate shell - commands to your current shell's .profile (or equivalent file.) - - You can now run ``cpan`` and the install commands shown above. You do not need - to prefix it with ``sudo`` (and should not do so.) The resulting CPAN setup - will be much quicker than with system Perl. - - This also means you can migrate your - current Perl setup - including CPAN setup/modules - by migrating your home directory, - and it is also immune to changes from OS updates. + See http://perlbrew.pl/ for more details. * Get the DFHack source as per section `compile-how-to-get-the-code`, above. * Set environment variables From 2ded0e5ea98e3770f357444b1b11c3a90b2aad61 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 18:50:59 +0000 Subject: [PATCH 079/222] Github->GitHub; git->Git (where not a command); one more change to Perlbrew section --- docs/Compile.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index be076fd81..6b34aaa47 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -15,7 +15,7 @@ and `install the latest release instead `. How to get the code =================== DFHack doesn't have any kind of system of code snapshots in place, so you will have to -get code from the Github repository using git. How to get git is described under +get code from the GitHub repository using Git. How to get Git is described under the instructions for each platform. To get the latest release code (master branch):: @@ -23,7 +23,7 @@ To get the latest release code (master branch):: git clone --recursive https://github.com/DFHack/dfhack cd dfhack -If your version of git does not support the ``--recursive`` flag, you will need to omit it and run +If your version of Git does not support the ``--recursive`` flag, you will need to omit it and run ``git submodule update --init`` after entering the dfhack directory. To get the latest development code (develop branch), clone as above and then:: @@ -40,7 +40,7 @@ for example when switching between master and develop branches and back. Contributing to DFHack ====================== If you want to get involved with the development, create an account on -Github, make a clone there and then use that as your remote repository instead. +GitHub, make a clone there and then use that as your remote repository instead. We'd love that; join us on IRC (#dfhack channel on freenode) for discussion, and whenever you need help. @@ -243,9 +243,10 @@ following environment variable:: Rather than using system Perl, you might also want to consider the Perl manager, `Perlbrew `_. - This installs Perl 5 locally in ``~/perl5/`` and provides an easy - way to install the latest Perl 5 and run CPAN against it, without - ``sudo``. + This manages Perl 5 locally under ``~/perl5/``, providing an easy + way to install Perl and run CPAN against it without ``sudo``. + It can maintain multiple Perl installs, and being local has the + benefit of easy migration and insulation from OS upgrades. See http://perlbrew.pl/ for more details. @@ -309,7 +310,7 @@ binaries that crash when connecting to Dwarf Fortress. Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The remainder of dependencies - git, cmake and StrawberryPerl - can be most +The remainder of dependencies - Git, CMake and StrawberryPerl - can be most easily installed using the Chocolatey Package Manger. This is a system that attempts to bring a Linux-like package manager to Windows. @@ -350,7 +351,7 @@ You only need Admin/elevated cmd.exe for running choco install commands; for all other purposes, including compiling DFHack, you should use a normal cmd.exe. -**NOTE**: the above assumes you have none of Git, cmake and StrawberryPerl +**NOTE**: the above assumes you have none of Git, CMake and StrawberryPerl already installed. If you do have one, you may want to remove that entry from the install command listed above - or, better, uninstall the copy you have now and re-install via Chocolatey, so that it can manage that program @@ -456,7 +457,7 @@ Building the documentation DFHack documentation, like the file you are reading now, is created as .rst files, which are in `reStructuredText (reST) `_ format. This is a documenation format that has come from the Python community. It is very -similar in concept - and in syntax - to Markdown, as found on Github and many other places. +similar in concept - and in syntax - to Markdown, as found on GitHub and many other places. However it is more advanced than Markdown, and can be compiled to sophisticated HTML files with tables of contents, cross-linking, references and more. From 196aec4cb4fe2eafbdfe8d7f5a11bc9778f66a7c Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 18:51:37 +0000 Subject: [PATCH 080/222] + again --- docs/Compile.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 6b34aaa47..50ffd15cd 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -245,8 +245,8 @@ following environment variable:: This manages Perl 5 locally under ``~/perl5/``, providing an easy way to install Perl and run CPAN against it without ``sudo``. - It can maintain multiple Perl installs, and being local has the - benefit of easy migration and insulation from OS upgrades. + It can maintain multiple Perl installs and being local has the + benefit of easy migration and insulation from OS issues and upgrades. See http://perlbrew.pl/ for more details. From 6c7e5c9428f4c17223dc6b0f784a594d83ad3b61 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 20:21:22 +0000 Subject: [PATCH 081/222] A few additions to the Windows section; more formatting changes including command highlighting; misc other tweaks. --- docs/Compile.rst | 88 +++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 50ffd15cd..63f84345e 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -311,10 +311,8 @@ binaries that crash when connecting to Dwarf Fortress. Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The remainder of dependencies - Git, CMake and StrawberryPerl - can be most -easily installed using the Chocolatey Package Manger. This is a system that -attempts to bring a Linux-like package manager to Windows. - -Think "apt-get for Windows." +easily installed using the Chocolatey Package Manger. Chocolatey is a +\*nix-style package manager for Windows. Think "``apt-get`` for Windows." Chocolatey is the recommended way of installing the required dependencies as it's less work and installs known-good utilities with the correct setup @@ -328,39 +326,39 @@ To install Chocolatey and the required dependencies: * Copy the first one, which starts ``@powershell ...`` * It won't be repeated here in case it changes in future Chocolatey releases. -* Open an elevated (Admin) cmd.exe window +* Open an elevated (Admin) ``cmd.exe`` window * On Windows 8 and later this can be easily achieved by: * right-clicking on the Start Menu, or pressing Win+X. * choosing "Command Prompt (Admin)" - * On earlier Windows: find cmd.exe in Start Menu, right click + * On earlier Windows: find ``cmd.exe`` in Start Menu, right click and choose Open As Administrator. * Paste in the Chocolatey install command, hit enter, and follow all prompts -* Close this cmd.exe window and open another Admin cmd.exe in the same way +* Close this ``cmd.exe`` window and open another Admin ``cmd.exe`` in the same way * Run the following command:: choco install git cmake strawberryperl -y -* Close the Admin cmd.exe window; you're done! +* Close the Admin ``cmd.exe`` window; you're done! -You can now use all of the above commands from any future cmd.exe window. -You only need Admin/elevated cmd.exe for running choco install commands; +You can now use all of these utilities from any normal ``cmd.exe`` window. +You only need Admin/elevated ``cmd.exe`` for running ``choco install`` commands; for all other purposes, including compiling DFHack, you should use -a normal cmd.exe. +a normal ``cmd.exe``. **NOTE**: the above assumes you have none of Git, CMake and StrawberryPerl already installed. If you do have one, you may want to remove that entry -from the install command listed above - or, better, uninstall the copy you -have now and re-install via Chocolatey, so that it can manage that program -in future. +from the install command listed above. Or, better, uninstall the copy you +have now and re-install via Chocolatey, to ensure you have PATH set up right +and so that Chocolatey can manage that program for you in future. Additional dependencies: installing manually ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is no longer generally recommended, as Chocolatey makes life a lot easier. -Use only if you have special requirements - or to check that your +Use only if you have special requirements, or to check that your already-installed versions of the below programs are as required for DFHack. Git @@ -380,21 +378,24 @@ to your binary search PATH so the tool can be later run from anywhere. Perl / Strawberry Perl ^^^^^^^^^^^^^^^^^^^^^^ -For the code generation parts, you'll need perl with XML::LibXML and XML::LibXSLT. -`Strawberry Perl `_ works nicely for this and includes -all of the required packages. +For the code generation parts you'll need Perl 5 with XML::LibXML and XML::LibXSLT. +`Strawberry Perl `_ is recommended as it includes +all of the required packages in a single, easy install. -After install, ensure Perl is in your user's PATH directory. This can be edited -from ``Control Panel -> System -> Advanced System Settings -> Environment Variables``. +After install, ensure Perl is in your user's PATH. This can be edited from +``Control Panel -> System -> Advanced System Settings -> Environment Variables``. -Be sure that all of the following three directories are present, in this order: +The following three directories must be in PATH, in this order: * ``\c\bin`` * ``\perl\site\bin`` * ``\perl\bin`` +Be sure to close and re-open any existing ``cmd.exe`` windows after updating +your PATH. + If you already have a different version of Perl (for example the one from Cygwin), -you can run into some trouble. Either remove the other perl install from PATH, or +you can run into some trouble. Either remove the other Perl install from PATH, or install XML::LibXML and XML::LibXSLT for it using CPAN. Build @@ -404,12 +405,16 @@ with a script that's used for picking the DF path. First, run ``set_df_path.vbs`` and point the dialog that pops up at a suitable DF installation which is of the appropriate version for the DFHack -you are compiling. +you are compiling. The result is the creation of the file ``DF_PATH.txt`` in +the build directory. It contains the full path to the destination directory. +You could therefore also create this file manually - or copy in a pre-prepared +version - if you prefer. -Next, run one of the scripts with ``generate`` prefix. These create the MSVC solution file(s): +Next, run one of the scripts with ``generate`` prefix. These create the MSVC +solution file(s): * ``all`` will create a solution with everything enabled (and the kitchen sink). -* ``gui`` will pop up the cmake gui and let you pick and choose what to build. +* ``gui`` will pop up the CMake GUI and let you choose what to build. This is probably what you want most of the time. Set the options you are interested in, then hit configure, then generate. More options can appear after the configure step. * ``minimal`` will create a minimal solution with just the bare necessities - @@ -419,16 +424,18 @@ Then you can either open the solution with MSVC or use one of the msbuild script Building/installing from the command line: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In the build directory you will find several ``.bat`` files: + * Scripts with ``build`` prefix will only build DFHack. * Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. * Scripts with ``package`` prefix will build and create a .zip package of DFHack. Compiling from the command line is generally the quickest and easiest option. -However be aware that due to the limitations of cmd.exe - especially in versions of -Windows prior to Windows 10 - it can be very hard to see what happens during a build. -If you get a failure, you may miss important errors or warnings due to the tiny window size -and extremely limited scrollback. For that reason you may prefer to compile -in the IDE which will show all build output. +However be aware that due to the limitations of ``cmd.exe`` - especially in +versions of Windows prior to Windows 10 - it can be very hard to see what happens +during a build. If you get a failure, you may miss important errors or warnings +due to the tiny window size and extremely limited scrollback. For that reason you +may prefer to compile in the IDE which will always show all build output. Alternatively (or additionally), consider installing an improved Windows terminal such as `Cmder `_. Easily installed through Chocolatey with: @@ -436,7 +443,7 @@ such as `Cmder `_. Easily installed through Chocolatey with: Building/installing from the Visual Studio IDE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -After running the generate script as above, you will have a new folder called VC2010. +After running the CMake generate script you will have a new folder called VC2010. Open the file ``dfhack.sln`` inside that folder. If you have multiple versions of Visual Studio installed, make sure you open with Visual Studio 2010. @@ -477,11 +484,16 @@ Enabling documentation building First, make sure you have followed all the necessary steps for your platform as outlined in the rest of this document. -Then, to compile documentation with DFHack, pass the flag ``-DBUILD_DOCS:bool=ON`` to cmake. +To compile documentation with DFHack, add the following flag to your ``cmake`` command:: + + -DBUILD_DOCS:bool=ON + For example:: cmake .. -DCMAKE_BUILD_TYPE:string=Release -DBUILD_DOCS:bool=ON -DCMAKE_INSTALL_PREFIX= +On Windows this will require that you edit the appropriate ``generate-msvc-*.bat`` file, +or that you run CMake manually rather than using the batch files. Required dependencies ===================== @@ -491,7 +503,7 @@ version 1.3.1 or later. Both Python 2.x and 3.x are supported. When installing Sphinx from OS package managers, be aware that there is another program called Sphinx, completely unrelated to documentation management. Be sure you are installing the right Sphinx; it may be called ``python-sphinx``, -for example. To avoid doubt, pip can be used instead as detailed below. +for example. To avoid doubt, ``pip`` can be used instead as detailed below. Linux @@ -507,7 +519,7 @@ You can instead install the Python module with:: pip install sphinx If you run this as a normal user it will install a local copy for your user only. -Run it with sudo if you want a system-wide install. +Run it with sudo if you want a system-wide install. Either is fine for DFHack. Mac OS X @@ -524,11 +536,11 @@ Alternatively, you can simply install Sphinx 1.3.x directly from Homebrew:: brew install sphinx-doc -This will directly install Sphinx for OS X's system Python 2.7, without needing pip. +This will install Sphinx for OS X's system Python 2.7, without needing pip. Either method works; if you plan to use Python for other purposes, it might best to install Homebrew's Python 3 so that you have the latest Python as well as pip. -If not, just installing sphinx-doc into OS X's system Python 2.7 is fine. +If not, just installing sphinx-doc for OS X's system Python 2.7 is fine. Windows @@ -536,11 +548,11 @@ Windows Use the Chocolatey package manager to install Python and pip, then use pip to install Sphinx. -Run the following commands from an elevated (Admin) cmd.exe, after installing +Run the following commands from an elevated (Admin) ``cmd.exe``, after installing Chocolatey as outlined in the `Windows section `:: choco install python pip -y -Then close that Admin cmd.exe, re-open another Admin cmd.exe, and run:: +Then close that Admin ``cmd.exe``, re-open another Admin ``cmd.exe``, and run:: pip install sphinx From 9bc8368d294468fd0eb9345757fa29cce9868bd1 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 20:30:11 +0000 Subject: [PATCH 082/222] Further tweak to Enable documentation build re setting CMAke flag: mention GUI, update Windows advice. --- docs/Compile.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 63f84345e..cab426e23 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -492,8 +492,12 @@ For example:: cmake .. -DCMAKE_BUILD_TYPE:string=Release -DBUILD_DOCS:bool=ON -DCMAKE_INSTALL_PREFIX= -On Windows this will require that you edit the appropriate ``generate-msvc-*.bat`` file, -or that you run CMake manually rather than using the batch files. +Alternatively you can use the CMake GUI which allows options to be easily changed. + +On Windows you should either use ``generate-msvc-gui.bat`` and set the option through the +GUI, or else if you want to use an alternate file, such as ``generate-msvc-all.bat``, you +will need to edit it to add the flag. Or you could just run ``cmake`` on the command line +like in other platforms. Required dependencies ===================== From e3b7cace6053edd50b03f71baef6f6e327575b87 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 15 Dec 2015 22:04:10 +0000 Subject: [PATCH 083/222] Some re-wording in Building The Documentation, including some 80-char width (approx) re-formatting. --- docs/Compile.rst | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index cab426e23..7cd304b37 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -464,25 +464,27 @@ Building the documentation DFHack documentation, like the file you are reading now, is created as .rst files, which are in `reStructuredText (reST) `_ format. This is a documenation format that has come from the Python community. It is very -similar in concept - and in syntax - to Markdown, as found on GitHub and many other places. -However it is more advanced than Markdown, and can be compiled to sophisticated HTML files -with tables of contents, cross-linking, references and more. - -The documentation can be built during the standard DFHack compilation procedure, -but this has been disabled by default. You only need to build the docs if you're changing -them, or perhaps if you want a local HTML copy; otherwise, read them easily online at +similar in concept - and in syntax - to Markdown, as found on GitHub and many other +places. However it is more advanced than Markdown, with more features available when +compiled to HTML, such as automatic tables of contents, cross-linking, special +external links (forum, wiki, etc) and more. The documentation is compiled by a +Python tool, `Sphinx `_. + +The DFHack build process will compile the documentation but this has been disabled +by default. You only need to build the docs if you're changing them, or perhaps +if you want a local HTML copy; otherwise, read them easily online at `ReadTheDoc's DFHack hosted documentation `_. -(Note that even if you do want a local copy, it is certainly not necesesary to compile the -documentation in order to read it. Like Markdown, reST documents are designed to be just as -readable in a plain-text editor as they are in HTML format. The main thing you lose in plain -text format is links.) +(Note that even if you do want a local copy, it is certainly not necesesary to +compile the documentation in order to read it. Like Markdown, reST documents are +designed to be just as readable in a plain-text editor as they are in HTML format. +The main thing you lose in plain text format is hyperlinking.) Enabling documentation building =============================== -First, make sure you have followed all the necessary steps for your platform as outlined -in the rest of this document. +First, make sure you have followed all the necessary steps for your platform as +outlined in the rest of this document. To compile documentation with DFHack, add the following flag to your ``cmake`` command:: @@ -492,12 +494,12 @@ For example:: cmake .. -DCMAKE_BUILD_TYPE:string=Release -DBUILD_DOCS:bool=ON -DCMAKE_INSTALL_PREFIX= -Alternatively you can use the CMake GUI which allows options to be easily changed. +Alternatively you can use the CMake GUI which allows options to be changed easily. -On Windows you should either use ``generate-msvc-gui.bat`` and set the option through the -GUI, or else if you want to use an alternate file, such as ``generate-msvc-all.bat``, you -will need to edit it to add the flag. Or you could just run ``cmake`` on the command line -like in other platforms. +On Windows you should either use ``generate-msvc-gui.bat`` and set the option +through the GUI, or else if you want to use an alternate file, such as +``generate-msvc-all.bat``, you will need to edit it to add the flag. +Or you could just run ``cmake`` on the command line like in other platforms. Required dependencies ===================== From 9bccf457c5d7ef8fc1628dbe78d997e4d9f43637 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Thu, 17 Dec 2015 10:54:19 -0600 Subject: [PATCH 084/222] Check for ui_sidebar_menus being null before using it. --- library/Core.cpp | 49 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 283fca927..0da2d2b28 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1550,36 +1550,39 @@ bool Core::Init() if (!server->listen(RemoteClient::GetDefaultPort())) cerr << "TCP listen failed.\n"; - vector & args = df::global::ui_sidebar_menus->unk.anon_2; - for (auto it = args.begin(); it != args.end(); ) + if (df::global::ui_sidebar_menus) { - const string & first = **it; - if (first.length() > 0 && first[0] == '+') + vector & args = df::global::ui_sidebar_menus->unk.anon_2; + for (auto it = args.begin(); it != args.end(); ) { - vector cmd; - for (it++; it != args.end(); it++) { - const string & arg = **it; - if (arg.length() > 0 && arg[0] == '+') - { - break; + const string & first = **it; + if (first.length() > 0 && first[0] == '+') + { + vector cmd; + for (it++; it != args.end(); it++) { + const string & arg = **it; + if (arg.length() > 0 && arg[0] == '+') + { + break; + } + cmd.push_back(arg); } - cmd.push_back(arg); - } - color_ostream_proxy out(getConsole()); - if (runCommand(out, first.substr(1), cmd) != CR_OK) - { - cerr << "Error running command: " << first.substr(1); - for (auto it2 = cmd.begin(); it2 != cmd.end(); it2++) + color_ostream_proxy out(getConsole()); + if (runCommand(out, first.substr(1), cmd) != CR_OK) { - cerr << " " << *it2; + cerr << "Error running command: " << first.substr(1); + for (auto it2 = cmd.begin(); it2 != cmd.end(); it2++) + { + cerr << " " << *it2; + } + cerr << "\n"; } - cerr << "\n"; } - } - else - { - it++; + else + { + it++; + } } } From e4de3411682f85ae6b2fb2f5faa787d3b3248247 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Thu, 17 Dec 2015 21:45:43 -0700 Subject: [PATCH 085/222] Preparing for MakeInstrument elimination. Instruments are now made individually, so this type of job no longer happens. Therefore, it will probably be removed from the job_type enum. --- plugins/devel/autolabor2.cpp | 1 - plugins/dwarfmonitor.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/devel/autolabor2.cpp b/plugins/devel/autolabor2.cpp index aca30ad3e..62bcc98d0 100644 --- a/plugins/devel/autolabor2.cpp +++ b/plugins/devel/autolabor2.cpp @@ -1222,7 +1222,6 @@ public: job_to_labor_table[df::job_type::MakeChain] = jlf_make_object; job_to_labor_table[df::job_type::MakeFlask] = jlf_make_object; job_to_labor_table[df::job_type::MakeGoblet] = jlf_make_object; - job_to_labor_table[df::job_type::MakeInstrument] = jlf_make_object; job_to_labor_table[df::job_type::MakeToy] = jlf_make_object; job_to_labor_table[df::job_type::MakeAnimalTrap] = jlf_const(df::unit_labor::TRAPPER); job_to_labor_table[df::job_type::MakeBarrel] = jlf_make_furniture; diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index ca61ddb2e..787c97fc0 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -706,7 +706,6 @@ public: case job_type::MakeChain: case job_type::MakeFlask: case job_type::MakeGoblet: - case job_type::MakeInstrument: case job_type::MakeToy: case job_type::MakeAnimalTrap: case job_type::MakeBarrel: From 45625318bb32896560d13c9e68df7ae753e7c382 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Thu, 17 Dec 2015 22:02:30 -0700 Subject: [PATCH 086/222] Stockflow reaction list repairs. Mostly, instruments and their pieces are made through generated custom reactions, instead of as tools. Depends on df-structures commit e551233 for full potency. --- plugins/lua/stockflow.lua | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index 745427656..5a92666e5 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -127,8 +127,9 @@ function collect_orders() entry = entry, } else - -- It might be worth searching reaction_list for the name. - -- Then again, this should only happen in unusual situations. + -- Todo: Search reaction_list for the name. + -- This can happen when loading an old save in a new version. + -- It's even possible that the reaction has been removed. print("Mismatched stockflow entry for stockpile #"..stockpile.stockpile_number..": "..entry.value.." ("..order_number..")") end else @@ -398,6 +399,14 @@ function collect_reactions() local name = string.gsub(reaction.name, "^.", string.upper) reaction_entry(result, job_types.CustomReaction, {reaction_name = reaction.code}, name) end + + -- Reactions generated by the game. + for _, reaction in ipairs(df.global.world.raws.reactions) do + if reaction.source_enid == entity.id then + local name = string.gsub(reaction.name, "^.", string.upper) + reaction_entry(result, job_types.CustomReaction, {reaction_name = reaction.code}, name) + end + end -- Metal forging local itemdefs = df.global.world.raws.itemdefs @@ -465,19 +474,10 @@ function collect_reactions() clothing_reactions(result, mat_flags, metalclothing) end - if material.flags.ITEMS_HARD then - resource_reactions(result, job_types.MakeTool, mat_flags, entity.resources.tool_type, itemdefs.tools, { - permissible = (function(itemdef) return itemdef.flags.HARD_MAT end), - capitalize = true, - }) - end - - if material.flags.ITEMS_METAL then - resource_reactions(result, job_types.MakeTool, mat_flags, entity.resources.tool_type, itemdefs.tools, { - permissible = (function(itemdef) return itemdef.flags.METAL_MAT end), - capitalize = true, - }) - end + resource_reactions(result, job_types.MakeTool, mat_flags, entity.resources.tool_type, itemdefs.tools, { + permissible = (function(itemdef) return ((material.flags.ITEMS_HARD and itemdef.flags.HARD_MAT) or (material.flags.ITEMS_METAL and itemdef.flags.METAL_MAT)) and not itemdef.flags.NO_DEFAULT_JOB end), + capitalize = true, + }) if material.flags.ITEMS_HARD then material_reactions(result, { @@ -560,7 +560,8 @@ function collect_reactions() }, materials.wood) resource_reactions(result, job_types.MakeTool, materials.wood, entity.resources.tool_type, itemdefs.tools, { - -- permissible = (function(itemdef) return itemdef.flags.WOOD_MAT end), + -- permissible = (function(itemdef) return itemdef.flags.WOOD_MAT and not itemdef.flags.NO_DEFAULT_JOB end), + permissible = (function(itemdef) return not itemdef.flags.NO_DEFAULT_JOB end), capitalize = true, }) From 3c4bb6c7e3e29986d02fb823ef9ea04b31b93817 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Thu, 17 Dec 2015 22:13:09 -0700 Subject: [PATCH 087/222] Stockflow no longer needs to be singled out in the init file. --- dfhack.init-example | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/dfhack.init-example b/dfhack.init-example index db2bf1129..080bb1488 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -216,15 +216,13 @@ enable \ zone \ stocks \ autochop \ + stockflow \ stockpiles #end a line with a backslash to make it continue to the next line. The \ is deleted for the final command. # Multiline commands are ONLY supported for scripts like dfhack.init. You cannot do multiline command manually on the DFHack console. # You cannot extend a commented line. # You can comment out the extension of a line. -# allow the fortress bookkeeper to queue jobs through the manager -enable stockflow - # enable mouse controls and sand indicator in embark screen embark-tools enable sand mouse @@ -249,10 +247,3 @@ gui/load-screen enable ####################################################### # Apply binary patches at runtime # ####################################################### - -####################################################### -# Disable broken tools for v0.42.01 # -####################################################### - -disable stockflow -:lua dfhack.printerr("Some tools incompatible with v0.42.01 have been disabled") From 4dc94a565f8660b11b559a377f9c65908c9060cf Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Fri, 18 Dec 2015 07:02:29 -0700 Subject: [PATCH 088/222] Adjusting stockflow order numbers where possible. Loading 0.40 saves in 0.42 results in a different list of reactions. Fortunately, all but the instruments should still work. --- plugins/lua/stockflow.lua | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/plugins/lua/stockflow.lua b/plugins/lua/stockflow.lua index 5a92666e5..6d3b3ba15 100644 --- a/plugins/lua/stockflow.lua +++ b/plugins/lua/stockflow.lua @@ -130,7 +130,25 @@ function collect_orders() -- Todo: Search reaction_list for the name. -- This can happen when loading an old save in a new version. -- It's even possible that the reaction has been removed. - print("Mismatched stockflow entry for stockpile #"..stockpile.stockpile_number..": "..entry.value.." ("..order_number..")") + local found = false + for number, reaction in ipairs(reaction_list) do + if reaction.name == entry.value then + print("Adjusting stockflow entry for stockpile #"..stockpile.stockpile_number..": "..entry.value.." ("..order_number.." => "..number..")") + entry.ints[entry_ints.order_number] = number + entry:save() + result[spid] = { + stockpile = stockpile, + entry = entry, + } + + found = true + break + end + end + + if not found then + print("Unmatched stockflow entry for stockpile #"..stockpile.stockpile_number..": "..entry.value.." ("..order_number..")") + end end else -- The stockpile no longer exists. From 347a112aa1e279eed88883f2c2b9e3ad41c9d6d1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 18 Dec 2015 17:45:23 -0500 Subject: [PATCH 089/222] Add support for 11-argument function wrappers Needed by item::addImprovementFromJob() as of 0.42: dfhack/df-structures@f6361e2 --- library/include/DataFuncs.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h index f34b9cc73..cd178263c 100644 --- a/library/include/DataFuncs.h +++ b/library/include/DataFuncs.h @@ -197,6 +197,13 @@ INSTANTIATE_WRAPPERS(10, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10), #define FW_TARGS class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11 INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11)) +INSTANTIATE_WRAPPERS(11, (A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11), + (OSTREAM_ARG,A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11), + (vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11), + (out,vA1,vA2,vA3,vA4,vA5,vA6,vA7,vA8,vA9,vA10,vA11), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4); + LOAD_ARG(A5); LOAD_ARG(A6); LOAD_ARG(A7); LOAD_ARG(A8); + LOAD_ARG(A9); LOAD_ARG(A10); LOAD_ARG(A11);) #undef FW_TARGS #undef FW_TARGSC @@ -227,4 +234,4 @@ INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11)) // bah, but didn't have any idea how to allocate statically return new function_identity(ptr, vararg); } -} \ No newline at end of file +} From 55d5706a21c3808108fde36a675e458a988927d0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 18 Dec 2015 18:40:11 -0500 Subject: [PATCH 090/222] Update structures and fix various issues with plugins producing items reaction_product::produce() takes a new unidentified vector*. Passing a reference to an empty vector appears to work. --- library/modules/Items.cpp | 3 ++- library/xml | 2 +- plugins/add-spatter.cpp | 6 ++++-- plugins/createitem.cpp | 3 ++- plugins/diggingInvaders/assignJob.cpp | 3 ++- plugins/eventful.cpp | 8 +++++--- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 0c29d851b..fe7eb6942 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1369,9 +1369,10 @@ int32_t Items::createItem(df::item_type item_type, int16_t item_subtype, int16_t vector out_items; vector in_reag; vector in_items; + vector unk; df::enums::game_type::game_type type = *df::global::gametype; - prod->produce(unit, &out_items, &in_reag, &in_items, 1, job_skill::NONE, + prod->produce(unit, &unk, &out_items, &in_reag, &in_items, 1, job_skill::NONE, df::historical_entity::find(unit->civ_id), ((type == df::enums::game_type::DWARF_MAIN) || (type == df::enums::game_type::DWARF_RECLAIM)) ? df::world_site::find(df::global::ui->site_id) : NULL); if ( out_items.size() != 1 ) diff --git a/library/xml b/library/xml index 6e2e8731d..36f94c0fc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6e2e8731d2c10a4a5394046ae48cc0cd16e9a049 +Subproject commit 36f94c0fcf09f0985595c7b9c9ad0c7170beed2d diff --git a/plugins/add-spatter.cpp b/plugins/add-spatter.cpp index cb2858d06..60bcce38f 100644 --- a/plugins/add-spatter.cpp +++ b/plugins/add-spatter.cpp @@ -243,7 +243,9 @@ struct product_hook : improvement_product { DEFINE_VMETHOD_INTERPOSE( void, produce, - (df::unit *unit, std::vector *out_items, + (df::unit *unit, + std::vector *unk, + std::vector *out_items, std::vector *in_reag, std::vector *in_items, int32_t quantity, df::job_skill skill, @@ -293,7 +295,7 @@ struct product_hook : improvement_product { return; } - INTERPOSE_NEXT(produce)(unit, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); } }; diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index da793ac0d..8c71dda40 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -73,6 +73,7 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it vector out_items; vector in_reag; vector in_items; + vector unk; bool is_gloves = (prod->item_type == item_type::GLOVES); bool is_shoes = (prod->item_type == item_type::SHOES); @@ -83,7 +84,7 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it if (dest_building != -1) building = df::building::find(dest_building); - prod->produce(unit, &out_items, &in_reag, &in_items, 1, job_skill::NONE, + prod->produce(unit, &unk, &out_items, &in_reag, &in_items, 1, job_skill::NONE, df::historical_entity::find(unit->civ_id), (World::isFortressMode()) ? df::world_site::find(ui->site_id) : NULL); if (!out_items.size()) diff --git a/plugins/diggingInvaders/assignJob.cpp b/plugins/diggingInvaders/assignJob.cpp index 57aa6ed6f..94acbd988 100644 --- a/plugins/diggingInvaders/assignJob.cpp +++ b/plugins/diggingInvaders/assignJob.cpp @@ -255,7 +255,8 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_map out_items; vector in_reag; vector in_items; - prod->produce(firstInvader, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE, + vector unk; + prod->produce(firstInvader, &unk, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE, df::historical_entity::find(firstInvader->civ_id), df::world_site::find(df::global::ui->site_id)); diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 1b9d228bc..01537f57e 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -309,7 +309,9 @@ struct product_hook : item_product { DEFINE_VMETHOD_INTERPOSE( void, produce, - (df::unit *unit, std::vector *out_items, + (df::unit *unit, + std::vector *unk, + std::vector *out_items, std::vector *in_reag, std::vector *in_items, int32_t quantity, df::job_skill skill, @@ -318,7 +320,7 @@ struct product_hook : item_product { color_ostream_proxy out(Core::getInstance().getConsole()); auto product = products[this]; if ( !product ) { - INTERPOSE_NEXT(produce)(unit, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); return; } df::reaction* this_reaction=product->react; @@ -329,7 +331,7 @@ struct product_hook : item_product { return; size_t out_item_count = out_items->size(); - INTERPOSE_NEXT(produce)(unit, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); if ( out_items->size() == out_item_count ) return; //if it produced something, call the scripts From 895d5a534e0f093469dde0d97b22b0f0a4d0551d Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sat, 19 Dec 2015 01:59:23 +0000 Subject: [PATCH 091/222] Fixes to: Linux: gcc-multilib; OSX: 10.11 notes higher/more emphasised; Windows: reason for why SP1 is required (currently unknown, so downgraded to 'we do not support' rather than a specific reason why it won't work. --- docs/Compile.rst | 86 +++++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 7cd304b37..681182851 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -81,7 +81,13 @@ To build DFHack you need GCC version 4.5 or later, capable of compiling for 32-b On 64-bit distributions, you'll need the multilib development tools and libraries: * ``gcc-multilib`` and ``g++-multilib`` -* On Debian: ``gcc-4.x-multilib`` and ``g++-4.x-multilib`` +* If you have installed a non-default version of GCC - for example, GCC 4.5 on a + distribution that defaults to 5.x - you may need to add the version number to + the multilib packages. + + * For example, ``gcc-4.5-multilib`` and ``g++-4.5-multilib`` if installing for GCC 4.5 + on a system that uses a later GCC version. + * This is definitely required on Ubuntu/Debian, check if using a different distribution. Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on Debian) will typically *not* work, as it depends on several other 32-bit libraries that @@ -121,7 +127,7 @@ empty folder in the DFHack directory to use instead) and start the build like th cd build cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= - make install + make install # or make -jX install on multi-core systems to compile with X parallel processes should be a path to a copy of Dwarf Fortress, of the appropriate version for the DFHack you are building. This will build the library along @@ -171,14 +177,42 @@ following environment variable:: export MACOSX_DEPLOYMENT_TARGET=10.9 -* Download and unpack a copy of the latest DF -* Install Xcode from Mac App Store +If you're on El Capitan (OSX 10.11), and/or you have XCode 7.x installed, you will +have issues - please see the Additional Notes below. + +Note for El Capitan (OSX 10.11) and XCode 7.x users +--------------------------------------------------- + +* You will probably find when following the instructions below that GCC 4.5 will + fail to install on OSX 10.11, or any older OSX that is using XCode 7. +* There are two workarounds: + + * Install GCC 5.x instead (``brew install gcc5``), and then after compile + replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 + version of this file:: + + cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && + ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . -* Install the XCode Command Line Tools by running the following command:: + * Install XCode 6, which is available as a free download from the Apple + Developer Center. + + * Either install this as your only XCode, or install it additionally + to XCode 7 and then switch between them using ``xcode-select`` + * Ensure XCode 6 is active before attempting to install GCC 4.5 and + whenever you are compiling DFHack with GCC 4.5. + +Dependencies and system set-up +------------------------------ + +#. Download and unpack a copy of the latest DF +#. Install Xcode from Mac App Store + +#. Install the XCode Command Line Tools by running the following command:: xcode-select --install -* Install dependencies +#. Install dependencies Using `Homebrew `_ (recommended):: @@ -200,28 +234,7 @@ following environment variable:: as Homebrew's will, and all in both 32bit and 64bit variants. Homebrew also doesn't require constant use of sudo. -* Additional notes for El Capitan (OSX 10.11) and XCode 7.x users - - * You will probably find that gcc45 will fail to install on OSX 10.11, - or any older OSX that is using XCode 7. - * There are two workarounds: - - * Install GCC 5.x instead (``brew install gcc5``), and then after compile - replace ``hack/libstdc++.6.dylib`` with a symlink to GCC 5's i386 - version of this file:: - - cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && - ln -s /usr/local/Cellar/gcc5/5.2.0/lib/gcc/5/i386/libstdc++.6.dylib . - - * Install XCode 6, which is available as a free download from the Apple - Developer Center. - - * Either install this as your only XCode, or install it additionally - to XCode 7 and then switch between them using ``xcode-select`` - * Ensure XCode 6 is active before attempting to install GCC 4.5 and - whenever you are compiling DFHack with GCC 4.5. - -* Install Perl dependencies +#. Install Perl dependencies * Using system Perl @@ -250,6 +263,9 @@ following environment variable:: See http://perlbrew.pl/ for more details. +Building +-------- + * Get the DFHack source as per section `compile-how-to-get-the-code`, above. * Set environment variables @@ -269,8 +285,11 @@ following environment variable:: mkdir build-osx cd build-osx - cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX=/path/to/DF/directory - make install + cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= + make install # or make -j X install on multi-core systems to compile with X parallel processes + + Replacing with a path to a copy of Dwarf Fortress of a version appropriate + for the version of DFHack you are compiling. .. _compile-windows: @@ -295,7 +314,7 @@ The free Express version is sufficient. You can grab it from `Microsoft's site `_. -You'll also need the Visual Studio 2010 SP1 update, which is obtained from +You should also install the Visual Studio 2010 SP1 update, which is obtained from Windows Update. After installing Visual Studio, be sure to go to Windows Update and check for and install the SP1 update. If no update is found, check that your Windows Update settings include "Updates from all Microsoft products". @@ -304,9 +323,8 @@ You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* -It is vital that you use SP1 as, while building with the original release -of Visual Studio 2010 (RTM) may succeed, it will result in non-working DFHack -binaries that crash when connecting to Dwarf Fortress. +Use of pre-SP1 releases is not supported by DFHack and has been reported to +cause issues. Please ensure you are using SP1 before raising any Issues. Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 7bfeb7cb2b874f545c3fc0f82993b4bebf1eacb3 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sat, 19 Dec 2015 02:37:31 +0000 Subject: [PATCH 092/222] OSX: Removed dupe statement --- docs/Compile.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 681182851..5ed827d91 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -177,9 +177,6 @@ following environment variable:: export MACOSX_DEPLOYMENT_TARGET=10.9 -If you're on El Capitan (OSX 10.11), and/or you have XCode 7.x installed, you will -have issues - please see the Additional Notes below. - Note for El Capitan (OSX 10.11) and XCode 7.x users --------------------------------------------------- From 03ec7741421adbcd7dc134010720fb8f1915b4eb Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sat, 19 Dec 2015 02:39:03 +0000 Subject: [PATCH 093/222] OSX: fixed wording on DF path --- docs/Compile.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 5ed827d91..bd1a50f5a 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -285,8 +285,8 @@ Building cmake .. -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= make install # or make -j X install on multi-core systems to compile with X parallel processes - Replacing with a path to a copy of Dwarf Fortress of a version appropriate - for the version of DFHack you are compiling. + should be a path to a copy of Dwarf Fortress, of the appropriate + version for the DFHack you are building. .. _compile-windows: From ca29f60518cb7ad8e54e0deb8e1bbd70f2230e15 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 18 Dec 2015 23:09:27 -0500 Subject: [PATCH 094/222] update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 36f94c0fc..3223ccd28 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 36f94c0fcf09f0985595c7b9c9ad0c7170beed2d +Subproject commit 3223ccd285ea139ba2e7c7815dfaba451ff029bf From 5b1e2ff01f1200291738ba182418b6c992373e65 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sat, 19 Dec 2015 14:17:39 +0000 Subject: [PATCH 095/222] Windows: soften the recommendation on Chocolatey to a 'preferred', also some improvements on the Chocolatey description re behaviour when software is already installed. And an update to the Manual Dependencies section. --- docs/Compile.rst | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index bd1a50f5a..e22e99556 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -320,18 +320,19 @@ You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* -Use of pre-SP1 releases is not supported by DFHack and has been reported to -cause issues. Please ensure you are using SP1 before raising any Issues. +Use of pre-SP1 releases has been reported to cause issues and is therefore not +supported by DFHack. Please ensure you are using SP1 before raising any Issues. Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The remainder of dependencies - Git, CMake and StrawberryPerl - can be most easily installed using the Chocolatey Package Manger. Chocolatey is a -\*nix-style package manager for Windows. Think "``apt-get`` for Windows." +\*nix-style package manager for Windows. It's fast, small (8-20MB on disk) +and very capable. Think "``apt-get`` for Windows." -Chocolatey is the recommended way of installing the required dependencies -as it's less work and installs known-good utilities with the correct setup -(especially PATH). +Chocolatey is a preferred way of installing the required dependencies +as it's quicker, less effort and will install known-good utilities +guaranteed to have the correct setup (especially PATH). To install Chocolatey and the required dependencies: @@ -351,7 +352,7 @@ To install Chocolatey and the required dependencies: * On earlier Windows: find ``cmd.exe`` in Start Menu, right click and choose Open As Administrator. -* Paste in the Chocolatey install command, hit enter, and follow all prompts +* Paste in the Chocolatey install command and hit enter * Close this ``cmd.exe`` window and open another Admin ``cmd.exe`` in the same way * Run the following command:: @@ -362,19 +363,22 @@ To install Chocolatey and the required dependencies: You can now use all of these utilities from any normal ``cmd.exe`` window. You only need Admin/elevated ``cmd.exe`` for running ``choco install`` commands; for all other purposes, including compiling DFHack, you should use -a normal ``cmd.exe``. +a normal ``cmd.exe`` (or, better, an improved terminal like `Cmder `_; +details below, under Build.) -**NOTE**: the above assumes you have none of Git, CMake and StrawberryPerl -already installed. If you do have one, you may want to remove that entry -from the install command listed above. Or, better, uninstall the copy you -have now and re-install via Chocolatey, to ensure you have PATH set up right -and so that Chocolatey can manage that program for you in future. +**NOTE**: you can run the above ``choco install`` command even if you already have +Git, CMake or StrawberryPerl installed. Chocolatey will inform you if any software +is already installed and won't re-install it. In that case, please check the PATHs +are correct for that utility as listed in the manual instructions below. Or, better, +manually uninstall the version you have already and re-install via Chocolatey, +which will ensure the PATH are set up right and will allow Chocolatey to manage +that program for you in future. Additional dependencies: installing manually ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This is no longer generally recommended, as Chocolatey makes life a lot easier. -Use only if you have special requirements, or to check that your -already-installed versions of the below programs are as required for DFHack. +If you prefer to install manually rather than using Chocolatey, details and +requirements are as below. If you do install manually, please ensure you +have all PATHs set up correctly. Git ^^^ @@ -390,7 +394,6 @@ You can get the win32 installer version from It has the usual installer wizard. Make sure you let it add its binary folder to your binary search PATH so the tool can be later run from anywhere. - Perl / Strawberry Perl ^^^^^^^^^^^^^^^^^^^^^^ For the code generation parts you'll need Perl 5 with XML::LibXML and XML::LibXSLT. @@ -454,7 +457,7 @@ may prefer to compile in the IDE which will always show all build output. Alternatively (or additionally), consider installing an improved Windows terminal such as `Cmder `_. Easily installed through Chocolatey with: -``choco install cmder``. +``choco install cmder -y``. Building/installing from the Visual Studio IDE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From dec1d95cb623e0bfc0fc99d64026cbd18e102c63 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 10:55:35 -0500 Subject: [PATCH 096/222] travis: build docs --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6c8457b93..da2c36a43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ script: - python travis/script-syntax.py --ext=rb --cmd="ruby -c" --path scripts/ - mkdir build-travis - cd build-travis -- cmake .. && make -j3 +- cmake .. -DBUILD_DOCS:BOOL=ON +- make -j3 notifications: email: false From 5a1e5e1464eed1c8d2e16c75ea4624e7d346b9d2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 11:07:35 -0500 Subject: [PATCH 097/222] Expose Units::casteFlagSet() --- library/include/modules/Units.h | 9 ++++++--- library/modules/Units.cpp | 2 +- plugins/strangemood.cpp | 13 +------------ 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index d706778b6..e5210013b 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -31,11 +31,13 @@ distribution. #include "Export.h" #include "modules/Items.h" #include "DataDefs.h" -#include "df/unit.h" + +#include "df/caste_raw_flags.h" +#include "df/job_skill.h" +#include "df/mental_attribute_type.h" #include "df/misc_trait_type.h" #include "df/physical_attribute_type.h" -#include "df/mental_attribute_type.h" -#include "df/job_skill.h" +#include "df/unit.h" namespace df { @@ -219,6 +221,7 @@ DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit); DFHACK_EXPORT bool isHidingCurse(df::unit *unit); DFHACK_EXPORT int getPhysicalAttrValue(df::unit *unit, df::physical_attribute_type attr); DFHACK_EXPORT int getMentalAttrValue(df::unit *unit, df::mental_attribute_type attr); +DFHACK_EXPORT bool casteFlagSet(int race, int caste, df::caste_raw_flags flag); DFHACK_EXPORT bool isCrazed(df::unit *unit); DFHACK_EXPORT bool isOpposedToLife(df::unit *unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 4bd2b49aa..08c2191ec 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -680,7 +680,7 @@ int Units::getMentalAttrValue(df::unit *unit, df::mental_attribute_type attr) return std::max(0, value); } -static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag) +bool Units::casteFlagSet(int race, int caste, df::caste_raw_flags flag) { auto creature = df::creature_raw::find(race); if (!creature) diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index cc00535a8..27bb8b072 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -49,17 +49,6 @@ using df::global::debug_nomoods; Random::MersenneRNG rng; -static bool casteFlagSet(int race, int caste, df::caste_raw_flags flag) -{ - auto creature = df::creature_raw::find(race); - if (!creature) - return false; - auto craw = vector_get(creature->caste, caste); - if (!craw) - return false; - return craw->flags.is_set(flag); -} - bool isUnitMoodable (df::unit *unit) { if (!Units::isCitizen(unit)) @@ -70,7 +59,7 @@ bool isUnitMoodable (df::unit *unit) return false; if (!ENUM_ATTR(profession,moodable,unit->profession)) return false; - if (!casteFlagSet(unit->race, unit->caste, caste_raw_flags::STRANGE_MOODS)) + if (!Units::casteFlagSet(unit->race, unit->caste, caste_raw_flags::STRANGE_MOODS)) return false; return true; } From ea79fc692a2030c3cb55b2dc94ad7bb6ffb3c878 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 11:07:42 -0500 Subject: [PATCH 098/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 3223ccd28..9105ebc0c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3223ccd285ea139ba2e7c7815dfaba451ff029bf +Subproject commit 9105ebc0cdb12667683426d7e57d9d4f79dc689b From f0013ced567c1680f44b74f2be5ddddd89a8433a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 11:16:43 -0500 Subject: [PATCH 099/222] tabs to spaces --- plugins/strangemood.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index 27bb8b072..c10566d33 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -733,8 +733,8 @@ command_result df_strangemood (color_ostream &out, vector & parameters) case job_skill::WOODCRAFT: case job_skill::STONECRAFT: case job_skill::BONECARVE: - case job_skill::PAPERMAKING: // These aren't actually moodable skills - case job_skill::BOOKBINDING: // but the game still checks for them anyways + case job_skill::PAPERMAKING: // These aren't actually moodable skills + case job_skill::BOOKBINDING: // but the game still checks for them anyways job->job_type = job_type::StrangeMoodCrafter; break; case job_skill::TANNER: From 5eccb1ed1c484011cd4c9945c309672bd04178c3 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 19 Dec 2015 23:03:40 +0300 Subject: [PATCH 100/222] Fix find-offsets for cur_year_tick on windows. The old reference moved far away, so switch to a new one. --- scripts/devel/find-offsets.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index 17bc4f6f9..eb00c9d4a 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -1327,7 +1327,7 @@ end local function find_cur_year_tick() local zone if os_type == 'windows' then - zone = zoomed_searcher('artifact_next_id', -32) + zone = zoomed_searcher('ui_unit_view_mode', 0x200) else zone = zoomed_searcher('cur_year', 128) end From eb1ae54d63b167a86f6a1a851716b7c8b5d194ba Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 17:09:29 -0500 Subject: [PATCH 101/222] Add ui_lever_target_type scan to find-offsets --- library/xml | 2 +- scripts/devel/find-offsets.lua | 55 +++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 9105ebc0c..4ad540bba 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9105ebc0cdb12667683426d7e57d9d4f79dc689b +Subproject commit 4ad540bbae076d574ebc8795242bd89da4b15811 diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index 17bc4f6f9..2c3df0f34 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -259,9 +259,19 @@ local function dwarfmode_to_top() return true end -local function feed_menu_choice(catnames,catkeys,enum) +local function feed_menu_choice(catnames,catkeys,enum,enter_seq,exit_seq,prompt) + local entered = false return function (idx) + if idx == 0 and prompt and not utils.prompt_yes_no(' Proceed?', true) then + return false + end idx = idx % #catnames + 1 + if not entered then + entered = true + else + dwarfmode_feed_input(table.unpack(exit_seq or {})) + end + dwarfmode_feed_input(table.unpack(enter_seq or {})) dwarfmode_feed_input(catkeys[idx]) if enum then return true, enum[catnames[idx]] @@ -1155,6 +1165,48 @@ NOTE: If not done after first 3-4 steps, resize the game window.]], ms.found_offset('ui_building_in_resize', addr) end +-- +-- ui_lever_target_type +-- +local function find_ui_lever_target_type() + local catnames = { + 'Bridge', 'Door', 'Floodgate', + 'Cage', 'Chain', 'TrackStop', + 'GearAssembly', + } + local catkeys = { + 'HOTKEY_TRAP_BRIDGE', 'HOTKEY_TRAP_DOOR', 'HOTKEY_TRAP_FLOODGATE', + 'HOTKEY_TRAP_CAGE', 'HOTKEY_TRAP_CHAIN', 'HOTKEY_TRAP_TRACK_STOP', + 'HOTKEY_TRAP_GEAR_ASSEMBLY', + } + local addr + + if dwarfmode_to_top() then + dwarfmode_feed_input('D_BUILDJOB') + + addr = searcher:find_interactive( + 'Auto-searching for ui_lever_target_type. Please select a lever:', + 'int8_t', + feed_menu_choice(catnames, catkeys, df.lever_target_type, + {'BUILDJOB_ADD'}, + {'LEAVESCREEN', 'LEAVESCREEN'}, + true -- prompt + ), + 20 + ) + end + + if not addr then + addr = searcher:find_menu_cursor([[ +Searching for ui_lever_target_type. Please select a lever with +'q' and enter the "add task" menu with 'a':]], + 'int8_t', catnames, df.lever_target_type + ) + end + + ms.found_offset('ui_lever_target_type', addr) +end + -- -- window_x -- @@ -1568,6 +1620,7 @@ exec_finder(find_ui_workshop_in_add, 'ui_workshop_in_add') exec_finder(find_ui_workshop_job_cursor, 'ui_workshop_job_cursor') exec_finder(find_ui_building_in_assign, 'ui_building_in_assign') exec_finder(find_ui_building_in_resize, 'ui_building_in_resize') +exec_finder(find_ui_lever_target_type, 'ui_lever_target_type') exec_finder(find_window_x, 'window_x') exec_finder(find_window_y, 'window_y') exec_finder(find_window_z, 'window_z') From eeb0fc7a0f7689910915f4943b7f3126f67c780f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 19 Dec 2015 23:12:26 -0500 Subject: [PATCH 102/222] update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 4ad540bba..a95e6d71f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 4ad540bbae076d574ebc8795242bd89da4b15811 +Subproject commit a95e6d71fd565b5a12f1357bbe337fe12bfdfb54 From ef27018545a8cd5c55423d41aba93c4045b6eea3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 20 Dec 2015 15:19:32 -0500 Subject: [PATCH 103/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index a95e6d71f..cc16113bc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a95e6d71fd565b5a12f1357bbe337fe12bfdfb54 +Subproject commit cc16113bcb4479ba792952f55d75cc369fabdb01 From 219a6c7a26101cc04f5af041dd85a62dbe6adffd Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sun, 20 Dec 2015 21:25:25 +0000 Subject: [PATCH 104/222] Compile docs: Windows: Add direct download link for MSVC 2010 SP1 --- docs/Compile.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index e22e99556..0c5b019ae 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -311,10 +311,7 @@ The free Express version is sufficient. You can grab it from `Microsoft's site `_. -You should also install the Visual Studio 2010 SP1 update, which is obtained from -Windows Update. After installing Visual Studio, be sure to go to Windows Update -and check for and install the SP1 update. If no update is found, check that -your Windows Update settings include "Updates from all Microsoft products". +You should also install the Visual Studio 2010 SP1 update You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* @@ -323,6 +320,12 @@ at the end of the version number, for example: *Version 10.0.40219.1 SP1Rel* Use of pre-SP1 releases has been reported to cause issues and is therefore not supported by DFHack. Please ensure you are using SP1 before raising any Issues. +If your Windows Update is configured to receive updates for all Microsoft +Products, not just Windows, you will receive the SP1 update automatically +through Windows Update (you will probably need to trigger a manual check.) + +If not, you can download it directly `from this Microsoft Download link `_. + Additional dependencies: installing with the Chocolatey Package Manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The remainder of dependencies - Git, CMake and StrawberryPerl - can be most From b5e91d78aa74ba1b30961c325f06a585390b6768 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Sun, 20 Dec 2015 21:33:02 +0000 Subject: [PATCH 105/222] Typo --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 0c5b019ae..dcbd3315c 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -311,7 +311,7 @@ The free Express version is sufficient. You can grab it from `Microsoft's site `_. -You should also install the Visual Studio 2010 SP1 update +You should also install the Visual Studio 2010 SP1 update. You can confirm whether you have SP1 by opening the Visual Studio 2010 IDE and selecting About from the Help menu. If you have SP1 it will have *SP1Rel* From 114c217d52b226f9de69f706dfc5a37c204855e6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 21 Dec 2015 20:38:15 -0500 Subject: [PATCH 106/222] Remove createitem deprecation notice --- docs/Plugins.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index f12108dde..677d75c82 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2148,8 +2148,6 @@ twice. createitem ========== -Use `modtools/create-item` - this plugin is deprecated and will be removed soon. - Allows creating new items of arbitrary types and made of arbitrary materials. By default, items created are spawned at the feet of the selected unit. From 5648adbc2cbcb1d36c13e447d508864d212c6f80 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 22 Dec 2015 01:39:39 +0000 Subject: [PATCH 107/222] Linux: Building docs: Some clarification on pip and sphinx-build --- docs/Compile.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index e22e99556..106a5cbc9 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -532,18 +532,26 @@ for example. To avoid doubt, ``pip`` can be used instead as detailed below. Linux ----- -Most Linux distributions will include Python as standard, including the pip -package manager. +Most Linux distributions will include Python as standard. Check your package manager to see if Sphinx 1.3.1 or later is available, but at the time of writing Ubuntu for example only has 1.2.x. -You can instead install the Python module with:: +You can instead install Sphinx with the pip package manager. This may need +to be installed from your OS package manager; this is the case on Ubuntu. +On Ubuntu/Debian, use the following to first install pip:: + + sudo apt-get install python-pip + +Once pip is available, you can then install the Python Sphinx module with:: pip install sphinx If you run this as a normal user it will install a local copy for your user only. -Run it with sudo if you want a system-wide install. Either is fine for DFHack. +Run it with sudo if you want a system-wide install. Either is fine for DFHack, +however if installing locally do check that ``sphinx-build`` is in your path. +It may be installed in a directory such as ``~/.local/bin/``, so after pip +install, find ``sphinx-build`` and ensure its directory is in your local ``$PATH``. Mac OS X From df7edaf37dcf8cac170e1ff7e821ca7b2eb4365c Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 22 Dec 2015 01:43:38 +0000 Subject: [PATCH 108/222] Windows: clarification on requirement of MSVC vs Visual Studio and basic explanation why --- docs/Compile.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 106a5cbc9..18d62ea8c 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -307,7 +307,11 @@ You will need the following: Microsoft Visual Studio 2010 SP1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The free Express version is sufficient. +DFHack has to be compiled with the Microsoft Visual C++ 2010 SP1 toolchain; later +versions won't work against Dwarf Fortress due to ABI and STL incompatibilities. + +At present, the only way to obtain the MSVC 2010 C++ toolchain is to install a +full copy of Microsoft Visual Studio 2010 SP1. The free Express version is sufficient. You can grab it from `Microsoft's site `_. From 017afec271b2f44e114b5921c3224d0715eb20f9 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 22 Dec 2015 01:44:49 +0000 Subject: [PATCH 109/222] Word order --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index 18d62ea8c..0140f39f5 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -310,7 +310,7 @@ Microsoft Visual Studio 2010 SP1 DFHack has to be compiled with the Microsoft Visual C++ 2010 SP1 toolchain; later versions won't work against Dwarf Fortress due to ABI and STL incompatibilities. -At present, the only way to obtain the MSVC 2010 C++ toolchain is to install a +At present, the only way to obtain the MSVC C++ 2010 toolchain is to install a full copy of Microsoft Visual Studio 2010 SP1. The free Express version is sufficient. You can grab it from `Microsoft's site `_. From 203b6b967d1e675b5caf9900dbe07278cf38a8f8 Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 22 Dec 2015 01:57:39 +0000 Subject: [PATCH 110/222] Windows: new section on using Bash to compile on command line under Windows --- docs/Compile.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/Compile.rst b/docs/Compile.rst index 0140f39f5..cba26daf9 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -463,6 +463,29 @@ Alternatively (or additionally), consider installing an improved Windows termina such as `Cmder `_. Easily installed through Chocolatey with: ``choco install cmder -y``. +**Note for Cygwin/msysgit users**: It is also possible to compile DFHack from a +Bash command line. This has three benefits: + +* When you've installed Git and are using its Bash, but haven't added Git to your path: + + * You can load Git's Bash and as long as it can access Perl and CMake, you can + use it for compile without adding Git to your system path. + +* When you've installed Cygwin and its SSH server: + + * You can now SSH in to your Windows install and compile from a remote terminal; + very useful if your Windows installation is a local VM on a \*nix host OS. + +* In general: you can use Bash as your compilation terminal, meaning you have a decent + sized window, scrollback, etc. + + * Whether you're accessing it locally as with Git's Bash, or remotely through + Cygwin's SSH server, this is far superior to using ``cmd.exe``. + +You don't need to do anything special to compile from Bash. As long as your PATHs +are set up correctly, you can run the same generate- and build/install/package- bat +files as detailed above. + Building/installing from the Visual Studio IDE: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After running the CMake generate script you will have a new folder called VC2010. From ce0322e8fd2bbf620ab2a9fd862be52e6161874b Mon Sep 17 00:00:00 2001 From: TheBloke Date: Tue, 22 Dec 2015 02:02:12 +0000 Subject: [PATCH 111/222] Word addition --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index cba26daf9..d8c308c81 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -464,7 +464,7 @@ such as `Cmder `_. Easily installed through Chocolatey with: ``choco install cmder -y``. **Note for Cygwin/msysgit users**: It is also possible to compile DFHack from a -Bash command line. This has three benefits: +Bash command line. This has three potential benefits: * When you've installed Git and are using its Bash, but haven't added Git to your path: From e4ff4fe64ce4b6b03140fa39daf653602a1d28b3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 09:43:17 -0500 Subject: [PATCH 112/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index cc16113bc..9e8fa01ee 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit cc16113bcb4479ba792952f55d75cc369fabdb01 +Subproject commit 9e8fa01ee53857b29b6b55f39597bc6176f4ba07 From 10c72a3d5daebe7fb1658ad9371648831affffbf Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 09:46:01 -0500 Subject: [PATCH 113/222] Fix produce() call in modules/Items.cpp --- library/modules/Items.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index fe7eb6942..b4539abdd 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1366,13 +1366,13 @@ int32_t Items::createItem(df::item_type item_type, int16_t item_subtype, int16_t } //makeItem + vector out_products; vector out_items; vector in_reag; vector in_items; - vector unk; df::enums::game_type::game_type type = *df::global::gametype; - prod->produce(unit, &unk, &out_items, &in_reag, &in_items, 1, job_skill::NONE, + prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE, df::historical_entity::find(unit->civ_id), ((type == df::enums::game_type::DWARF_MAIN) || (type == df::enums::game_type::DWARF_RECLAIM)) ? df::world_site::find(df::global::ui->site_id) : NULL); if ( out_items.size() != 1 ) From c9eab65c965dae4ccadaa36803332de0740e48f5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 09:54:00 -0500 Subject: [PATCH 114/222] Fix more produce() calls --- plugins/add-spatter.cpp | 4 ++-- plugins/createitem.cpp | 4 ++-- plugins/diggingInvaders/assignJob.cpp | 4 ++-- plugins/eventful.cpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/add-spatter.cpp b/plugins/add-spatter.cpp index 60bcce38f..45d636d7c 100644 --- a/plugins/add-spatter.cpp +++ b/plugins/add-spatter.cpp @@ -244,7 +244,7 @@ struct product_hook : improvement_product { DEFINE_VMETHOD_INTERPOSE( void, produce, (df::unit *unit, - std::vector *unk, + std::vector *out_products, std::vector *out_items, std::vector *in_reag, std::vector *in_items, @@ -295,7 +295,7 @@ struct product_hook : improvement_product { return; } - INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, out_products, out_items, in_reag, in_items, quantity, skill, entity, site); } }; diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index 8c71dda40..33cd05f70 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -70,10 +70,10 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_item = false) { + vector out_products; vector out_items; vector in_reag; vector in_items; - vector unk; bool is_gloves = (prod->item_type == item_type::GLOVES); bool is_shoes = (prod->item_type == item_type::SHOES); @@ -84,7 +84,7 @@ bool makeItem (df::reaction_product_itemst *prod, df::unit *unit, bool second_it if (dest_building != -1) building = df::building::find(dest_building); - prod->produce(unit, &unk, &out_items, &in_reag, &in_items, 1, job_skill::NONE, + prod->produce(unit, &out_products, &out_items, &in_reag, &in_items, 1, job_skill::NONE, df::historical_entity::find(unit->civ_id), (World::isFortressMode()) ? df::world_site::find(ui->site_id) : NULL); if (!out_items.size()) diff --git a/plugins/diggingInvaders/assignJob.cpp b/plugins/diggingInvaders/assignJob.cpp index 94acbd988..b7ca6f161 100644 --- a/plugins/diggingInvaders/assignJob.cpp +++ b/plugins/diggingInvaders/assignJob.cpp @@ -252,11 +252,11 @@ int32_t assignJob(color_ostream& out, Edge firstImportantEdge, unordered_mapcount = 1; prod->product_dimension = 1; + vector out_products; vector out_items; vector in_reag; vector in_items; - vector unk; - prod->produce(firstInvader, &unk, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE, + prod->produce(firstInvader, &out_products, &out_items, &in_reag, &in_items, 1, df::job_skill::NONE, df::historical_entity::find(firstInvader->civ_id), df::world_site::find(df::global::ui->site_id)); diff --git a/plugins/eventful.cpp b/plugins/eventful.cpp index 01537f57e..7ad10a3ba 100644 --- a/plugins/eventful.cpp +++ b/plugins/eventful.cpp @@ -310,7 +310,7 @@ struct product_hook : item_product { DEFINE_VMETHOD_INTERPOSE( void, produce, (df::unit *unit, - std::vector *unk, + std::vector *out_products, std::vector *out_items, std::vector *in_reag, std::vector *in_items, @@ -320,7 +320,7 @@ struct product_hook : item_product { color_ostream_proxy out(Core::getInstance().getConsole()); auto product = products[this]; if ( !product ) { - INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, out_products, out_items, in_reag, in_items, quantity, skill, entity, site); return; } df::reaction* this_reaction=product->react; @@ -331,7 +331,7 @@ struct product_hook : item_product { return; size_t out_item_count = out_items->size(); - INTERPOSE_NEXT(produce)(unit, unk, out_items, in_reag, in_items, quantity, skill, entity, site); + INTERPOSE_NEXT(produce)(unit, out_products, out_items, in_reag, in_items, quantity, skill, entity, site); if ( out_items->size() == out_item_count ) return; //if it produced something, call the scripts From 2a2ab00ca99c58ce9beddb05c1598a4283813218 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 11:42:51 -0500 Subject: [PATCH 115/222] Add "map" parameter to a lot of drawing functions Ref #746 --- library/include/modules/Gui.h | 1 + library/include/modules/Screen.h | 38 ++++++++++----------- library/modules/Screen.cpp | 16 ++++----- plugins/devel/color-dfhack-text.cpp | 15 +++++++-- plugins/mousequery.cpp | 2 +- plugins/uicommon.h | 52 +++++++++++++++++------------ 6 files changed, 71 insertions(+), 53 deletions(-) diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index effa7347e..ae53e7603 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -131,6 +131,7 @@ namespace DFHack struct DwarfmodeDims { int map_x1, map_x2, menu_x1, menu_x2, area_x1, area_x2; int y1, y2; + int map_y1, map_y2; bool menu_on, area_on, menu_forced; rect2d map() { return mkrect_xy(map_x1, y1, map_x2, y2); } diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 389becbfe..37dc9808c 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -184,16 +184,16 @@ namespace DFHack DFHACK_EXPORT bool inGraphicsMode(); /// Paint one screen tile with the given pen - DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y); + DFHACK_EXPORT bool paintTile(const Pen &pen, int x, int y, bool map = false); /// Retrieves one screen tile from the buffer DFHACK_EXPORT Pen readTile(int x, int y); /// Paint a string onto the screen. Ignores ch and tile of pen. - DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text); + DFHACK_EXPORT bool paintString(const Pen &pen, int x, int y, const std::string &text, bool map = false); /// Fills a rectangle with one pen. Possibly more efficient than a loop over paintTile. - DFHACK_EXPORT bool fillRect(const Pen &pen, int x1, int y1, int x2, int y2); + DFHACK_EXPORT bool fillRect(const Pen &pen, int x1, int y1, int x2, int y2, bool map = false); /// Draws a standard dark gray window border with a title string DFHACK_EXPORT bool drawBorder(const std::string &title); @@ -261,34 +261,34 @@ namespace DFHack return *this; } - Painter &fill(const rect2d &area, const Pen &pen) { + Painter &fill(const rect2d &area, const Pen &pen, bool map = false) { rect2d irect = intersect(area, clip); - fillRect(pen, irect.first.x, irect.first.y, irect.second.x, irect.second.y); + fillRect(pen, irect.first.x, irect.first.y, irect.second.x, irect.second.y, map); return *this; } - Painter &fill(const rect2d &area) { return fill(area, cur_pen); } + Painter &fill(const rect2d &area, bool map = false) { return fill(area, cur_pen, map); } - Painter &tile(const Pen &pen) { - if (isValidPos()) paintTile(pen, gcursor.x, gcursor.y); + Painter &tile(const Pen &pen, bool map = false) { + if (isValidPos()) paintTile(pen, gcursor.x, gcursor.y, map); return advance(1); } - Painter &tile() { return tile(cur_pen); } - Painter &tile(char ch) { return tile(cur_pen.chtile(ch)); } - Painter &tile(char ch, int tileid) { return tile(cur_pen.chtile(ch, tileid)); } + Painter &tile(bool map = false) { return tile(cur_pen, map); } + Painter &tile(char ch, bool map = false) { return tile(cur_pen.chtile(ch), map); } + Painter &tile(char ch, int tileid, bool map = false) { return tile(cur_pen.chtile(ch, tileid), map); } - Painter &string(const std::string &str, const Pen &pen) { - do_paint_string(str, pen); return advance(str.size()); + Painter &string(const std::string &str, const Pen &pen, bool map = false) { + do_paint_string(str, pen, map); return advance(str.size()); } - Painter &string(const std::string &str) { return string(str, cur_pen); } - Painter &string(const std::string &str, int8_t fg) { return string(str, cur_pen.color(fg)); } + Painter &string(const std::string &str, bool map = false) { return string(str, cur_pen, map); } + Painter &string(const std::string &str, int8_t fg, bool map = false) { return string(str, cur_pen.color(fg), map); } - Painter &key(df::interface_key kc, const Pen &pen) { - return string(getKeyDisplay(kc), pen); + Painter &key(df::interface_key kc, const Pen &pen, bool map = false) { + return string(getKeyDisplay(kc), pen, map); } - Painter &key(df::interface_key kc) { return key(kc, cur_key_pen); } + Painter &key(df::interface_key kc, bool map = false) { return key(kc, cur_key_pen, map); } private: - void do_paint_string(const std::string &str, const Pen &pen); + void do_paint_string(const std::string &str, const Pen &pen, bool map = false); }; namespace Hooks { diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index c0ced42a2..0f79e1a46 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -115,14 +115,14 @@ static void doSetTile(const Pen &pen, int x, int y, bool map) GUI_HOOK_TOP(Screen::Hooks::set_tile)(pen, x, y, map); } -bool Screen::paintTile(const Pen &pen, int x, int y) +bool Screen::paintTile(const Pen &pen, int x, int y, bool map) { if (!gps || !pen.valid()) return false; auto dim = getWindowSize(); if (x < 0 || x >= dim.x || y < 0 || y >= dim.y) return false; - doSetTile(pen, x, y, false); + doSetTile(pen, x, y, map); return true; } @@ -161,7 +161,7 @@ Pen Screen::readTile(int x, int y) return pen; } -bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text) +bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text, bool map) { auto dim = getWindowSize(); if (!gps || y < 0 || y >= dim.y) return false; @@ -176,14 +176,14 @@ bool Screen::paintString(const Pen &pen, int x, int y, const std::string &text) tmp.ch = text[i]; tmp.tile = (pen.tile ? pen.tile + uint8_t(text[i]) : 0); - paintTile(tmp, x+i, y); + paintTile(tmp, x+i, y, map); ok = true; } return ok; } -bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2) +bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2, bool map) { auto dim = getWindowSize(); if (!gps || !pen.valid()) return false; @@ -197,7 +197,7 @@ bool Screen::fillRect(const Pen &pen, int x1, int y1, int x2, int y2) for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) - doSetTile(pen, x, y, false); + doSetTile(pen, x, y, map); } return true; @@ -247,7 +247,7 @@ bool Screen::invalidate() const Pen Screen::Painter::default_pen(0,COLOR_GREY,0); const Pen Screen::Painter::default_key_pen(0,COLOR_LIGHTGREEN,0); -void Screen::Painter::do_paint_string(const std::string &str, const Pen &pen) +void Screen::Painter::do_paint_string(const std::string &str, const Pen &pen, bool map) { if (gcursor.y < clip.first.y || gcursor.y > clip.second.y) return; @@ -256,7 +256,7 @@ void Screen::Painter::do_paint_string(const std::string &str, const Pen &pen) int len = std::min((int)str.size(), int(clip.second.x - gcursor.x + 1)); if (len > dx) - paintString(pen, gcursor.x + dx, gcursor.y, str.substr(dx, len-dx)); + paintString(pen, gcursor.x + dx, gcursor.y, str.substr(dx, len-dx), map); } bool Screen::findGraphicsTile(const std::string &pagename, int x, int y, int *ptile, int *pgs) diff --git a/plugins/devel/color-dfhack-text.cpp b/plugins/devel/color-dfhack-text.cpp index 761782303..eb5e9c659 100644 --- a/plugins/devel/color-dfhack-text.cpp +++ b/plugins/devel/color-dfhack-text.cpp @@ -25,9 +25,18 @@ void color_text_tile(const Screen::Pen &pen, int x, int y, bool map) { Screen::Pen pen2 = pen; uint8_t color = config.flicker ? config.tick % 8 : config.color; - pen2.fg = color; - pen2.bg = color; - pen2.bold = true; + if (map) + { + pen2.fg = color % 8; + pen2.bg = (color % 8) + 8; + pen2.bold = false; + } + else + { + pen2.fg = color; + pen2.bg = color; + pen2.bold = true; + } return color_text_hook.next()(pen2, x, y, map); } diff --git a/plugins/mousequery.cpp b/plugins/mousequery.cpp index 389d443cf..3731d96c0 100644 --- a/plugins/mousequery.cpp +++ b/plugins/mousequery.cpp @@ -674,7 +674,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest } } - OutputString(color, mx, my, "X"); + OutputString(color, mx, my, "X", false, 0, 0, true); return; } diff --git a/plugins/uicommon.h b/plugins/uicommon.h index 7182ee2f2..156552504 100644 --- a/plugins/uicommon.h +++ b/plugins/uicommon.h @@ -91,9 +91,9 @@ static void transform_(vector &src, vector &dst, Fn func) typedef int8_t UIColor; static void OutputString(UIColor color, int &x, int &y, const std::string &text, - bool newline = false, int left_margin = 0, const UIColor bg_color = 0) + bool newline = false, int left_margin = 0, const UIColor bg_color = 0, bool map = false) { - Screen::paintString(Screen::Pen(' ', color, bg_color), x, y, text); + Screen::paintString(Screen::Pen(' ', color, bg_color), x, y, text, map); if (newline) { ++y; @@ -104,54 +104,62 @@ static void OutputString(UIColor color, int &x, int &y, const std::string &text, } static void OutputHotkeyString(int &x, int &y, const char *text, const char *hotkey, bool newline = false, - int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN) + int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) { - OutputString(hotkey_color, x, y, hotkey); + OutputString(hotkey_color, x, y, hotkey, false, 0, 0, map); string display(": "); display.append(text); - OutputString(text_color, x, y, display, newline, left_margin); + OutputString(text_color, x, y, display, newline, left_margin, 0, map); } static void OutputHotkeyString(int &x, int &y, const char *text, df::interface_key hotkey, - bool newline = false, int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN) + bool newline = false, int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, + bool map = false) { - OutputHotkeyString(x, y, text, DFHack::Screen::getKeyDisplay(hotkey).c_str(), newline, left_margin, text_color, hotkey_color); + OutputHotkeyString(x, y, text, DFHack::Screen::getKeyDisplay(hotkey).c_str(), newline, left_margin, text_color, hotkey_color, map); } static void OutputLabelString(int &x, int &y, const char *text, const char *hotkey, const string &label, bool newline = false, - int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN) + int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) { - OutputString(hotkey_color, x, y, hotkey); + OutputString(hotkey_color, x, y, hotkey, false, 0, 0, map); string display(": "); display.append(text); display.append(": "); - OutputString(text_color, x, y, display); - OutputString(hotkey_color, x, y, label, newline, left_margin); + OutputString(text_color, x, y, display, false, 0, 0, map); + OutputString(hotkey_color, x, y, label, newline, left_margin, 0, map); +} + +static void OutputLabelString(int &x, int &y, const char *text, df::interface_key hotkey, const string &label, bool newline = false, + int left_margin = 0, int8_t text_color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) +{ + OutputLabelString(x, y, text, DFHack::Screen::getKeyDisplay(hotkey).c_str(), label, newline, + left_margin, text_color, hotkey_color, map); } static void OutputFilterString(int &x, int &y, const char *text, const char *hotkey, bool state, bool newline = false, - int left_margin = 0, int8_t hotkey_color = COLOR_LIGHTGREEN) + int left_margin = 0, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) { - OutputString(hotkey_color, x, y, hotkey); - OutputString(COLOR_WHITE, x, y, ": "); - OutputString((state) ? COLOR_WHITE : COLOR_GREY, x, y, text, newline, left_margin); + OutputString(hotkey_color, x, y, hotkey, false, 0, 0, map); + OutputString(COLOR_WHITE, x, y, ": ", false, 0, 0, map); + OutputString((state) ? COLOR_WHITE : COLOR_GREY, x, y, text, newline, left_margin, 0, map); } static void OutputToggleString(int &x, int &y, const char *text, const char *hotkey, bool state, bool newline = true, - int left_margin = 0, int8_t color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN) + int left_margin = 0, int8_t color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) { - OutputHotkeyString(x, y, text, hotkey, false, 0, color, hotkey_color); - OutputString(color, x, y, ": "); + OutputHotkeyString(x, y, text, hotkey, false, 0, color, hotkey_color, map); + OutputString(color, x, y, ": ", false, 0, 0, map); if (state) - OutputString(COLOR_GREEN, x, y, "On", newline, left_margin); + OutputString(COLOR_GREEN, x, y, "On", newline, left_margin, 0, map); else - OutputString(COLOR_GREY, x, y, "Off", newline, left_margin); + OutputString(COLOR_GREY, x, y, "Off", newline, left_margin, 0, map); } static void OutputToggleString(int &x, int &y, const char *text, df::interface_key hotkey, bool state, bool newline = true, - int left_margin = 0, int8_t color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN) + int left_margin = 0, int8_t color = COLOR_WHITE, int8_t hotkey_color = COLOR_LIGHTGREEN, bool map = false) { - OutputToggleString(x, y, text, DFHack::Screen::getKeyDisplay(hotkey).c_str(), state, newline, left_margin, color, hotkey_color); + OutputToggleString(x, y, text, DFHack::Screen::getKeyDisplay(hotkey).c_str(), state, newline, left_margin, color, hotkey_color, map); } inline string int_to_string(const int n) From 07e59139fdb62bd9aadb9cee578353eabfbc4ec1 Mon Sep 17 00:00:00 2001 From: txtsd Date: Wed, 23 Dec 2015 00:38:03 +0530 Subject: [PATCH 116/222] Use distro_fixes.sh from LNP if it exists --- package/linux/dfhack | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package/linux/dfhack b/package/linux/dfhack index 09fc52c15..c75620077 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -34,6 +34,12 @@ fi # Save current terminal settings old_tty_settings=$(stty -g) +# Use distro_fixes.sh from LNP if it exists +DISTROFIXES="distro_fixes.sh" +if [ -r "$DISTROFIXES" ]; then + . "./$DISTROFIXES" +fi + # Now run export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./hack/libs":"./hack" From 14f1e6b06c8e74d6314ed55d39ccc9235e599245 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 19:34:54 -0500 Subject: [PATCH 117/222] Improve prerelease warning somewhat --- library/Core.cpp | 2 +- scripts/gui/prerelease-warning.lua | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index bdbb5c3b2..e58db7755 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2057,7 +2057,7 @@ void Core::onStateChange(color_ostream &out, state_change_event event) break; } - if (event == SC_MAP_LOADED && Version::is_prerelease()) + if (event == SC_WORLD_LOADED && Version::is_prerelease()) { runCommand(out, "gui/prerelease-warning"); std::cerr << "loaded map in prerelease build" << std::endl; diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua index 53d612d41..a065e5224 100644 --- a/scripts/gui/prerelease-warning.lua +++ b/scripts/gui/prerelease-warning.lua @@ -11,13 +11,26 @@ if not dfhack.isPrerelease() then qerror('not a prerelease build') end local gui = require 'gui' local dlg = require 'gui.dialogs' +local utils = require 'utils' local message = { 'This is a prerelease build of DFHack. Some structures are likely', NEWLINE, 'to be incorrect, resulting in crashes or save corruption', NEWLINE, - {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'} + {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'}, NEWLINE, } +path = dfhack.getHackPath():lower() +if path:find('lnp') or path:find('starter') or path:find('newb') or path:find('lazy') or path:find('pack') then + local pack_msg = [[ +Under no circumstances should this be enabled by default in a pack. +If you are seeing this message and did not enable DFHack yourself, +please report this to your pack's maintainer.]] + for _, v in pairs(utils.split_string(pack_msg, '\n')) do + table.insert(message, NEWLINE) + table.insert(message, {text=v, pen=COLOR_LIGHTMAGENTA}) + end +end + dfhack.print('\n') for k,v in ipairs(message) do From a75a8cb4966f101a843876703b2f5f82b61264b8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 22 Dec 2015 19:35:40 -0500 Subject: [PATCH 118/222] Update version in CMakeLists.txt --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 274b58fce..3c027374f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,8 +97,8 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.42.02") -SET(DFHACK_RELEASE "r0") +set(DF_VERSION "0.42.03") +SET(DFHACK_RELEASE "alpha1") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From e3e68a8df91dfe3ffc8a5512fbceeaf39b360c37 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 23 Dec 2015 16:57:43 -0500 Subject: [PATCH 119/222] Add a search option to the location occupation menu --- NEWS.rst | 7 +++++++ library/xml | 2 +- plugins/search.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 4ff70f63e..e7fbe0ef7 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -29,6 +29,13 @@ Changelog .. contents:: :depth: 2 +DFHack future +============= + +New Features +------------ +- `search-plugin`: Support for the location occupation assignment menu + DFHack 0.40.24-r5 ================= diff --git a/library/xml b/library/xml index 9e8fa01ee..ed0eec72c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9e8fa01ee53857b29b6b55f39597bc6176f4ba07 +Subproject commit ed0eec72c7b29a61cc367337d89c339c2853f0ab diff --git a/plugins/search.cpp b/plugins/search.cpp index f5b10f156..cd94b3320 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -21,6 +21,7 @@ #include "df/viewscreen_buildinglistst.h" #include "df/viewscreen_joblistst.h" #include "df/historical_figure.h" +#include "df/viewscreen_locationsst.h" #include "df/interface_key.h" #include "df/interfacest.h" #include "df/layer_object_listst.h" @@ -1948,6 +1949,47 @@ IMPLEMENT_HOOKS(df::viewscreen_topicmeeting_fill_land_holder_positionsst, noble_ // END: Noble suggestion search // +// +// START: Location occupation assignment search +// + +typedef search_generic location_assign_occupation_search_base; +class location_assign_occupation_search : public location_assign_occupation_search_base +{ +public: + bool can_init (df::viewscreen_locationsst *screen) + { + return screen->menu == df::viewscreen_locationsst::AssignOccupation; + } + + string get_element_description (df::unit *unit) const + { + return unit ? get_unit_description(unit) : "Nobody"; + } + + void render() const + { + print_search_option(37, gps->dimy - 3); + } + + vector *get_primary_list() + { + return &viewscreen->units; + } + + virtual int32_t *get_viewscreen_cursor() + { + return &viewscreen->unit_idx; + } + +}; + +IMPLEMENT_HOOKS(df::viewscreen_locationsst, location_assign_occupation_search); + +// +// END: Location occupation assignment search +// + #define SEARCH_HOOKS \ HOOK_ACTION(unitlist_search_hook) \ HOOK_ACTION(roomlist_search_hook) \ @@ -1964,7 +2006,8 @@ IMPLEMENT_HOOKS(df::viewscreen_topicmeeting_fill_land_holder_positionsst, noble_ HOOK_ACTION(burrow_search_hook) \ HOOK_ACTION(stockpile_search_hook) \ HOOK_ACTION(room_assign_search_hook) \ - HOOK_ACTION(noble_suggest_search_hook) + HOOK_ACTION(noble_suggest_search_hook) \ + HOOK_ACTION(location_assign_occupation_search_hook) DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) { From 7d9f2d0c08748428c9201e6ed4ee06bdc697b3af Mon Sep 17 00:00:00 2001 From: moversti Date: Thu, 24 Dec 2015 00:31:23 +0200 Subject: [PATCH 120/222] Updated Windows compile docs Needing cmake.portable instead of cmake --- docs/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Compile.rst b/docs/Compile.rst index f17206d8b..81719c902 100644 --- a/docs/Compile.rst +++ b/docs/Compile.rst @@ -363,7 +363,7 @@ To install Chocolatey and the required dependencies: * Close this ``cmd.exe`` window and open another Admin ``cmd.exe`` in the same way * Run the following command:: - choco install git cmake strawberryperl -y + choco install git cmake.portable strawberryperl -y * Close the Admin ``cmd.exe`` window; you're done! From 25e808be3891c8f5d6d889f7a73fad7a88211f83 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 23 Dec 2015 17:45:08 -0500 Subject: [PATCH 121/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index ed0eec72c..636f77875 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ed0eec72c7b29a61cc367337d89c339c2853f0ab +Subproject commit 636f7787552cc663f01561c7dc84f758cea027f1 From 10eed10b63153e8e939a013c728c60bbc1afb44a Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 24 Dec 2015 22:13:25 +0530 Subject: [PATCH 122/222] Add genger do remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index aaf78ad91..3dc96cabd 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -370,6 +370,7 @@ message CasteRaw repeated string caste_name = 3; repeated string baby_name = 4; repeated string child_name = 5; + optional int32 gender = 6; } message CreatureRaw diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 2c97b35b7..6c7dfffcd 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1869,6 +1869,7 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage send_caste->add_child_name(orig_caste->child_name[0]); send_caste->add_child_name(orig_caste->child_name[1]); + send_caste->set_gender(orig_caste->gender); } } From de160de0e8fe721e5ec8353cef07ad01935d5a16 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 24 Dec 2015 21:34:38 -0500 Subject: [PATCH 123/222] showmood: use correct console encoding --- NEWS.rst | 5 +++++ plugins/showmood.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index e7fbe0ef7..ec7fa5454 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,6 +36,11 @@ New Features ------------ - `search-plugin`: Support for the location occupation assignment menu +Fixes +----- +- `showmood`: Fixed name display on OS X/Linux + + DFHack 0.40.24-r5 ================= diff --git a/plugins/showmood.cpp b/plugins/showmood.cpp index c1e4ff019..05e9a67ad 100644 --- a/plugins/showmood.cpp +++ b/plugins/showmood.cpp @@ -69,7 +69,7 @@ command_result df_showmood (color_ostream &out, vector & parameters) out.printerr("Dwarf with strange mood does not have a mood type!\n"); continue; } - out.print("%s is currently ", Translation::TranslateName(&unit->name, false).c_str()); + out.print("%s is currently ", DF2CONSOLE(Translation::TranslateName(&unit->name, false)).c_str()); switch (unit->mood) { case mood_type::Macabre: From 7fe71c94f6ea9c2f97a2ac994d356518bf9c2ee6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 25 Dec 2015 10:05:13 -0500 Subject: [PATCH 124/222] A few devel/unit-path fixes * Handle unrecognized unit_path_type values * Handle getSelectedUnit() * Only zoom to path.dest if it's valid --- scripts/devel/unit-path.lua | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/devel/unit-path.lua b/scripts/devel/unit-path.lua index d05203b71..2eff7ed2d 100644 --- a/scripts/devel/unit-path.lua +++ b/scripts/devel/unit-path.lua @@ -20,11 +20,16 @@ UnitPathUI.focus_path = 'unit-path' UnitPathUI.ATTRS { unit = DEFAULT_NIL, + has_path = false, + has_goal = false, } function UnitPathUI:init() self.saved_mode = df.global.ui.main.mode - + if self.unit then + self.has_path = #self.unit.path.path.x > 0 + self.has_goal = self.unit.path.dest.x >= 0 + end end function UnitPathUI:onShow() @@ -139,12 +144,11 @@ function UnitPathUI:onRenderBody(dc) end local cursor = guidm.getCursorPos() - local has_path = #self.unit.path.path.x>0 local vp = self:getViewport() local mdc = gui.Painter.new(self.df_layout.map) - if not has_path then + if not self.has_path then if gui.blink_visible(120) then paintMapTile(mdc, vp, cursor, self.unit.pos, 15, COLOR_LIGHTRED, COLOR_RED) end @@ -153,7 +157,7 @@ function UnitPathUI:onRenderBody(dc) else self:renderPath(mdc,vp,cursor) - dc:seek(1,6):pen(COLOR_GREEN):string(df.unit_path_goal[self.unit.path.goal]) + dc:seek(1,6):pen(COLOR_GREEN):string(df.unit_path_goal[self.unit.path.goal] or '?') end dc:newline():pen(COLOR_GREY) @@ -183,7 +187,7 @@ function UnitPathUI:onRenderBody(dc) dc:newline():newline(1):pen(COLOR_WHITE) dc:key('CUSTOM_Z'):string(": Zoom unit, ") - dc:key('CUSTOM_G'):string(": Zoom goal",COLOR_GREY,nil,has_path) + dc:key('CUSTOM_G'):string(": Zoom goal",COLOR_GREY,nil,self.has_goal) dc:newline(1) dc:key('CUSTOM_N'):string(": Zoom station",COLOR_GREY,nil,has_station) dc:newline():newline(1) @@ -194,7 +198,7 @@ function UnitPathUI:onInput(keys) if keys.CUSTOM_Z then self:moveCursorTo(copyall(self.unit.pos)) elseif keys.CUSTOM_G then - if #self.unit.path.path.x > 0 then + if self.has_goal then self:moveCursorTo(copyall(self.unit.path.dest)) end elseif keys.CUSTOM_N then @@ -208,6 +212,10 @@ function UnitPathUI:onInput(keys) end end +function UnitPathUI:onGetSelectedUnit() + return self.unit +end + local unit = dfhack.gui.getSelectedUnit(true) if not unit or not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/ViewUnits/Some/') then From d4b631d9fda9dd862aeba0d09efb5e9fc884a7c0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 25 Dec 2015 10:53:48 -0500 Subject: [PATCH 125/222] tweak prerelease pack warning --- scripts/gui/prerelease-warning.lua | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua index a065e5224..bb72cbafc 100644 --- a/scripts/gui/prerelease-warning.lua +++ b/scripts/gui/prerelease-warning.lua @@ -13,22 +13,25 @@ local gui = require 'gui' local dlg = require 'gui.dialogs' local utils = require 'utils' -local message = { +message = { 'This is a prerelease build of DFHack. Some structures are likely', NEWLINE, 'to be incorrect, resulting in crashes or save corruption', NEWLINE, - {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'}, NEWLINE, + {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'}, } +pack_message = pack_message or [[ + +This should not be enabled by default in a pack. +If you are seeing this message and did not enable/install DFHack +yourself, please report this to your pack's maintainer.]] + path = dfhack.getHackPath():lower() -if path:find('lnp') or path:find('starter') or path:find('newb') or path:find('lazy') or path:find('pack') then - local pack_msg = [[ -Under no circumstances should this be enabled by default in a pack. -If you are seeing this message and did not enable DFHack yourself, -please report this to your pack's maintainer.]] - for _, v in pairs(utils.split_string(pack_msg, '\n')) do +if #pack_message > 0 and (path:find('lnp') or path:find('starter') or path:find('newb') or path:find('lazy') or path:find('pack')) then + for _, v in pairs(utils.split_string(pack_message, '\n')) do table.insert(message, NEWLINE) table.insert(message, {text=v, pen=COLOR_LIGHTMAGENTA}) end + pack_message = '' end dfhack.print('\n') From 64d861bf6b99e8411395bc0f6b0f0ac99fc197e0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 25 Dec 2015 11:09:05 -0500 Subject: [PATCH 126/222] Add support for viewscreen_locationsst to various gui functions --- library/modules/Gui.cpp | 24 ++++++++++++++++++++++++ library/xml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 8de672ec6..518fe9bda 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -62,6 +62,7 @@ using namespace DFHack; #include "df/viewscreen_layer_assigntradest.h" #include "df/viewscreen_layer_militaryst.h" #include "df/viewscreen_layer_stockpilest.h" +#include "df/viewscreen_locationsst.h" #include "df/viewscreen_petst.h" #include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_storesst.h" @@ -542,6 +543,11 @@ DEFINE_GET_FOCUS_STRING_HANDLER(layer_stockpile) } } +DEFINE_GET_FOCUS_STRING_HANDLER(locations) +{ + focus += "/" + enum_item_key(screen->menu); +} + std::string Gui::getFocusString(df::viewscreen *top) { if (!top) @@ -835,6 +841,24 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) } } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_locationsst, top)) + { + switch (screen->menu) + { + case df::viewscreen_locationsst::AssignOccupation: + return vector_get(screen->units, screen->unit_idx); + case df::viewscreen_locationsst::Occupations: + { + auto occ = vector_get(screen->occupations, screen->occupation_idx); + if (occ) + return df::unit::find(occ->unit_id); + return NULL; + } + default: + return NULL; + } + } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_petst, top)) { switch (screen->mode) diff --git a/library/xml b/library/xml index 636f77875..73a475830 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 636f7787552cc663f01561c7dc84f758cea027f1 +Subproject commit 73a4758307b01396ed28c8df011a6f95867450cf From a9ad2f40f1db79b0153083bd2beb7b3235502552 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 25 Dec 2015 11:18:55 -0500 Subject: [PATCH 127/222] Add a location retirement confirmation --- NEWS.rst | 1 + plugins/confirm.cpp | 2 ++ plugins/lua/confirm.lua | 11 +++++++++++ 3 files changed, 14 insertions(+) diff --git a/NEWS.rst b/NEWS.rst index ec7fa5454..5d4ef51e3 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -34,6 +34,7 @@ DFHack future New Features ------------ +- `confirm`: Added a confirmation for retiring locations - `search-plugin`: Support for the location occupation assignment menu Fixes diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index ec8ee2a73..3ea5d540c 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -19,6 +19,7 @@ #include "df/general_ref_contained_in_itemst.h" #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_layer_militaryst.h" +#include "df/viewscreen_locationsst.h" #include "df/viewscreen_tradegoodsst.h" using namespace DFHack; @@ -453,6 +454,7 @@ DEFINE_CONFIRMATION(squad_disband, viewscreen_layer_militaryst, 0); DEFINE_CONFIRMATION(uniform_delete, viewscreen_layer_militaryst, 0); DEFINE_CONFIRMATION(note_delete, viewscreen_dwarfmodest, 0); DEFINE_CONFIRMATION(route_delete, viewscreen_dwarfmodest, 0); +DEFINE_CONFIRMATION(location_retire, viewscreen_locationsst, 0); DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) { diff --git a/plugins/lua/confirm.lua b/plugins/lua/confirm.lua index 751b1b4da..135187358 100644 --- a/plugins/lua/confirm.lua +++ b/plugins/lua/confirm.lua @@ -192,6 +192,17 @@ end route_delete.title = "Delete route" route_delete.message = "Are you sure you want to delete this route?" +location_retire = defconf('location-retire') +function location_retire.intercept_key(key) + return key == keys.LOCATION_RETIRE and + (screen.menu == df.viewscreen_locationsst.T_menu.Locations or + screen.menu == df.viewscreen_locationsst.T_menu.Occupations) and + screen.in_edit == df.viewscreen_locationsst.T_in_edit.None and + screen.locations[screen.location_idx] +end +location_retire.title = "Retire location" +location_retire.message = "Are you sure you want to retire this location?" + -- End of confirmation definitions function check() From 05926d9734925f88aba21db6f16eed4f20851b9c Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 26 Dec 2015 11:47:55 -0500 Subject: [PATCH 128/222] New tweak: title-start-rename Adds a safe rename option to the title screen "Start Playing" menu --- NEWS.rst | 5 +- docs/Plugins.rst | 1 + library/xml | 2 +- plugins/tweak/tweak.cpp | 7 ++ plugins/tweak/tweaks/title-start-rename.h | 112 ++++++++++++++++++++++ 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 plugins/tweak/tweaks/title-start-rename.h diff --git a/NEWS.rst b/NEWS.rst index 5d4ef51e3..4444ded39 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -9,7 +9,7 @@ Internals Lua - New [Internal Commands | Plugins | Scripts | Tweaks] + New [Internal Commands | Plugins | Scripts | Features] Fixes Misc Improvements Removed @@ -36,6 +36,9 @@ New Features ------------ - `confirm`: Added a confirmation for retiring locations - `search-plugin`: Support for the location occupation assignment menu +- `tweak`: + + - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu Fixes ----- diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 677d75c82..952813180 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -315,6 +315,7 @@ Subcommands that persist until disabled or DF quits: :nestbox-color: Fixes the color of built nestboxes :shift-8-scroll: Gives Shift-8 (or :kbd:`*`) priority when scrolling menus, instead of scrolling the map :stable-cursor: Saves the exact cursor position between t/q/k/d/b/etc menus of fortress mode. +:title-start-rename: Adds a safe rename option to the title screen "Start Playing" menu :tradereq-pet-gender: Displays pet genders on the trade request screen .. _fix-armory: diff --git a/library/xml b/library/xml index 73a475830..11dfc8f83 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 73a4758307b01396ed28c8df011a6f95867450cf +Subproject commit 11dfc8f838617ee5d42524a838345491704d9dff diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 98ec21eb3..6b7f11603 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -14,6 +14,7 @@ #include "modules/Materials.h" #include "modules/MapCache.h" #include "modules/Buildings.h" +#include "modules/Filesystem.h" #include "MiscUtils.h" @@ -96,6 +97,7 @@ #include "tweaks/nestbox-color.h" #include "tweaks/shift-8-scroll.h" #include "tweaks/stable-cursor.h" +#include "tweaks/title-start-rename.h" #include "tweaks/tradereq-pet-gender.h" using std::set; @@ -218,6 +220,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector save_dir).c_str(), full_save_dir(entry).c_str()) != 0) + return false; + save->save_dir = entry; + entry = ""; + return true; + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + if (sel_subpage == T_sel_subpage::StartSelectWorld || sel_subpage == T_sel_subpage::StartSelectMode) + { + auto save = get_cur_save(); + if (save) + { + int x = 1, y = 7; + OutputHotkeyString(x, y, + in_rename ? entry.c_str() : "Rename", + df::interface_key::CUSTOM_R, + false, 0, + rename_failed ? COLOR_LIGHTRED : COLOR_WHITE, + in_rename ? COLOR_RED : COLOR_LIGHTRED); + if (in_rename) + OutputString(COLOR_LIGHTGREEN, x, y, "_"); + } + } + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { + using namespace df::enums::interface_key; + if (in_rename) + { + rename_failed = false; + auto string_key = get_string_key(input); + if (input->count(SELECT) && !entry.empty()) + { + if (do_rename()) + in_rename = false; + else + rename_failed = true; + } + else if (input->count(STRING_A000)) + { + if (!entry.empty()) + entry.erase(entry.size() - 1); + } + else if (string_key != NONE) + { + entry += Screen::keyToChar(string_key); + } + else if (input->count(LEAVESCREEN) || (input->count(SELECT) && entry.empty()) || + input->count(STANDARDSCROLL_UP) || input->count(STANDARDSCROLL_DOWN)) + { + entry = ""; + in_rename = false; + std::set tmp; + if (input->count(STANDARDSCROLL_UP)) + tmp.insert(STANDARDSCROLL_UP); + if (input->count(STANDARDSCROLL_DOWN)) + tmp.insert(STANDARDSCROLL_DOWN); + INTERPOSE_NEXT(feed)(&tmp); + } + } + else if (input->count(CUSTOM_R)) + { + in_rename = true; + } + else + { + INTERPOSE_NEXT(feed)(input); + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(title_start_rename_hook, render); +IMPLEMENT_VMETHOD_INTERPOSE(title_start_rename_hook, feed); + +df::viewscreen_titlest::T_sel_subpage title_start_rename_hook::last_subpage = + df::viewscreen_titlest::T_sel_subpage::None; +bool title_start_rename_hook::in_rename = false; +bool title_start_rename_hook::rename_failed = false; +std::string title_start_rename_hook::entry; From 106891f6e09eff657fe6f9e09edb6666fe8e51d6 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sun, 13 Dec 2015 14:03:25 -0600 Subject: [PATCH 129/222] vim-style +-args. for example, "./dfhack +echo foo" would be equivalent to running ./dfhack and then typing "echo foo" into the console. uses shell argument splitting, so "./dfhack +somecommand 'foo bar' baz" does the right thing. See DFHack#755. --- library/Core.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/library/Core.cpp b/library/Core.cpp index e58db7755..9c2ef6403 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -62,6 +62,7 @@ using namespace std; using namespace DFHack; #include "df/ui.h" +#include "df/ui_sidebar_menus.h" #include "df/world.h" #include "df/world_data.h" #include "df/interfacest.h" @@ -1549,6 +1550,68 @@ bool Core::Init() if (!server->listen(RemoteClient::GetDefaultPort())) cerr << "TCP listen failed.\n"; + if (df::global::ui_sidebar_menus) + { + vector args; + const string & raw = df::global::ui_sidebar_menus->command_line.raw; + size_t offset = 0; + while (offset < raw.size()) + { + if (raw[offset] == '"') + { + offset++; + size_t next = raw.find("\"", offset); + args.push_back(raw.substr(offset, next - offset)); + offset = next + 2; + } + else + { + size_t next = raw.find(" ", offset); + if (next == string::npos) + { + args.push_back(raw.substr(offset)); + offset = raw.size(); + } + else + { + args.push_back(raw.substr(offset, next - offset)); + offset = next + 1; + } + } + } + for (auto it = args.begin(); it != args.end(); ) + { + const string & first = *it; + if (first.length() > 0 && first[0] == '+') + { + vector cmd; + for (it++; it != args.end(); it++) { + const string & arg = *it; + if (arg.length() > 0 && arg[0] == '+') + { + break; + } + cmd.push_back(arg); + } + + color_ostream_proxy out(getConsole()); + if (runCommand(out, first.substr(1), cmd) != CR_OK) + { + cerr << "Error running command: " << first.substr(1); + for (auto it2 = cmd.begin(); it2 != cmd.end(); it2++) + { + cerr << " \"" << *it2 << "\""; + } + cerr << "\n"; + } + } + else + { + it++; + } + } + } + cerr << "DFHack is running.\n"; return true; } From c8b937b1158295f3fcd43a6a6306c86a1c11c021 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 26 Dec 2015 14:25:25 -0500 Subject: [PATCH 130/222] Update 3rdparty/lethosor (install devel/send-key) --- scripts/3rdparty/lethosor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/3rdparty/lethosor b/scripts/3rdparty/lethosor index 01b594027..26c600132 160000 --- a/scripts/3rdparty/lethosor +++ b/scripts/3rdparty/lethosor @@ -1 +1 @@ -Subproject commit 01b594027a84c6b732f7639870538f138483a78c +Subproject commit 26c60013223e02b5558e31bed8e0625495430995 From fabff1ddfb015190942771b60c54f68705c4a7b7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 26 Dec 2015 19:59:54 -0500 Subject: [PATCH 131/222] Fix df::occupation usage --- library/modules/Gui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 518fe9bda..ae7c97236 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -90,6 +90,7 @@ using namespace DFHack; #include "df/route_stockpile_link.h" #include "df/game_mode.h" #include "df/unit.h" +#include "df/occupation.h" using namespace df::enums; using df::global::gview; From a977f274b16b37f8531a54402dabcf0cfa9ca074 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 26 Dec 2015 20:00:09 -0500 Subject: [PATCH 132/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 11dfc8f83..cc74796a9 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 11dfc8f838617ee5d42524a838345491704d9dff +Subproject commit cc74796a90b139e6f7ca7291d5161f84d7beb985 From d087f4f741c74b4bc8dd915690ff89ddc188b954 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 27 Dec 2015 14:59:18 -0500 Subject: [PATCH 133/222] Expose process MD5/PE to Lua (useful in export-dt-ini) --- docs/Lua API.rst | 8 ++++++++ library/LuaApi.cpp | 20 ++++++++++++++++++++ library/Process-darwin.cpp | 7 ++++--- library/Process-linux.cpp | 7 ++++--- library/Process-windows.cpp | 6 +++--- library/include/MemAccess.h | 5 +++++ scripts/devel/export-dt-ini.lua | 9 +++++++-- 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 2a3db9b16..c090b8a9d 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1908,6 +1908,14 @@ and are only documented here for completeness: The table used by ``dfhack.run_script()`` to give every script its own global environment, persistent between calls to the script. +* ``dfhack.internal.getPE()`` + + Returns the PE timestamp of the DF executable (only on Windows) + +* ``dfhack.internal.getMD5()`` + + Returns the MD5 of the DF executable (only on OS X and Linux) + * ``dfhack.internal.getAddress(name)`` Returns the global address ``name``, or *nil*. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index a3a9eb070..ba9591719 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2304,6 +2304,24 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = { { NULL, NULL } }; +static int internal_getmd5(lua_State *L) +{ + auto p = Core::getInstance().p; + if (p->getDescriptor()->getOS() == OS_WINDOWS) + luaL_error(L, "process MD5 not available on Windows"); + lua_pushstring(L, p->getMD5().c_str()); + return 1; +} + +static int internal_getPE(lua_State *L) +{ + auto p = Core::getInstance().p; + if (p->getDescriptor()->getOS() != OS_WINDOWS) + luaL_error(L, "process PE timestamp not available on non-Windows"); + lua_pushinteger(L, p->getPE()); + return 1; +} + static int internal_getAddress(lua_State *L) { const char *name = luaL_checkstring(L, 1); @@ -2683,6 +2701,8 @@ static int internal_findScript(lua_State *L) } static const luaL_Reg dfhack_internal_funcs[] = { + { "getPE", internal_getPE }, + { "getMD5", internal_getmd5 }, { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, { "getVTable", internal_getVTable }, diff --git a/library/Process-darwin.cpp b/library/Process-darwin.cpp index a485e196d..6f159e5fe 100644 --- a/library/Process-darwin.cpp +++ b/library/Process-darwin.cpp @@ -60,15 +60,16 @@ Process::Process(VersionInfoFactory * known_versions) identified = false; my_descriptor = 0; + my_pe = 0; md5wrapper md5; uint32_t length; uint8_t first_kb [1024]; memset(first_kb, 0, sizeof(first_kb)); // get hash of the running DF process - string hash = md5.getHashFromFile(real_path, length, (char *) first_kb); + my_md5 = md5.getHashFromFile(real_path, length, (char *) first_kb); // create linux process, add it to the vector - VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash); + VersionInfo * vinfo = known_versions->getVersionInfoByMD5(my_md5); if(vinfo) { my_descriptor = new VersionInfo(*vinfo); @@ -79,7 +80,7 @@ Process::Process(VersionInfoFactory * known_versions) char * wd = getcwd(NULL, 0); cerr << "Unable to retrieve version information.\n"; cerr << "File: " << real_path << endl; - cerr << "MD5: " << hash << endl; + cerr << "MD5: " << my_md5 << endl; cerr << "working dir: " << wd << endl; cerr << "length:" << length << endl; cerr << "1KB hexdump follows:" << endl; diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index 1b430e5a8..e4c647f7f 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -55,15 +55,16 @@ Process::Process(VersionInfoFactory * known_versions) identified = false; my_descriptor = 0; + my_pe = 0; md5wrapper md5; uint32_t length; uint8_t first_kb [1024]; memset(first_kb, 0, sizeof(first_kb)); // get hash of the running DF process - string hash = md5.getHashFromFile(exe_link_name, length, (char *) first_kb); + my_md5 = md5.getHashFromFile(exe_link_name, length, (char *) first_kb); // create linux process, add it to the vector - VersionInfo * vinfo = known_versions->getVersionInfoByMD5(hash); + VersionInfo * vinfo = known_versions->getVersionInfoByMD5(my_md5); if(vinfo) { my_descriptor = new VersionInfo(*vinfo); @@ -74,7 +75,7 @@ Process::Process(VersionInfoFactory * known_versions) char * wd = getcwd(NULL, 0); cerr << "Unable to retrieve version information.\n"; cerr << "File: " << exe_link_name << endl; - cerr << "MD5: " << hash << endl; + cerr << "MD5: " << my_md5 << endl; cerr << "working dir: " << wd << endl; cerr << "length:" << length << endl; cerr << "1KB hexdump follows:" << endl; diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index c923441e3..5474d7cfb 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -95,7 +95,8 @@ Process::Process(VersionInfoFactory * factory) { return; } - VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(d->pe_header.FileHeader.TimeDateStamp); + my_pe = d->pe_header.FileHeader.TimeDateStamp; + VersionInfo* vinfo = factory->getVersionInfoByPETimestamp(my_pe); if(vinfo) { identified = true; @@ -105,8 +106,7 @@ Process::Process(VersionInfoFactory * factory) } else { - fprintf(stderr, "Unable to retrieve version information.\nPE timestamp: 0x%x\n", - d->pe_header.FileHeader.TimeDateStamp); + fprintf(stderr, "Unable to retrieve version information.\nPE timestamp: 0x%x\n", my_pe); fflush(stderr); } } diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h index 80844ae5f..36100b400 100644 --- a/library/include/MemAccess.h +++ b/library/include/MemAccess.h @@ -287,6 +287,9 @@ namespace DFHack EXEC = 4 }; + uint32_t getPE() { return my_pe; } + std::string getMD5() { return my_md5; } + private: VersionInfo * my_descriptor; PlatformSpecific *d; @@ -294,6 +297,8 @@ namespace DFHack uint32_t my_pid; uint32_t base; std::map classNameCache; + uint32_t my_pe; + std::string my_md5; }; class DFHACK_EXPORT ClassNameCheck diff --git a/scripts/devel/export-dt-ini.lua b/scripts/devel/export-dt-ini.lua index 1d99b2d55..c75acd1dd 100644 --- a/scripts/devel/export-dt-ini.lua +++ b/scripts/devel/export-dt-ini.lua @@ -421,8 +421,13 @@ address('uniform_indiv_choice',df.squad_uniform_spec,'indiv_choice') local out = io.open('therapist.ini', 'w') out:write('[info]\n') --- TODO: add an api function to retrieve the checksum -out:write('checksum=<>\n') +if dfhack.getOSType() == 'windows' and dfhack.internal.getPE then + out:write(('checksum=0x%x\n'):format(dfhack.internal.getPE())) +elseif dfhack.getOSType() ~= 'windows' and dfhack.internal.getMD5 then + out:write(('checksum=0x%s\n'):format(dfhack.internal.getMD5():sub(1, 8))) +else + out:write('checksum=<>\n') +end out:write('version_name='..dfhack.getDFVersion()..'\n') out:write('complete='..(complete and 'true' or 'false')..'\n') From e075a064861fb3ea0cfee507105e8898c9130265 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 27 Dec 2015 15:49:10 -0500 Subject: [PATCH 134/222] Add search controls to all viewscreen_petst subpages --- NEWS.rst | 7 ++- library/xml | 2 +- plugins/search.cpp | 141 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 140 insertions(+), 10 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 04e99c056..cab6c0c69 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -44,7 +44,12 @@ Internals New Features ------------ - `confirm`: Added a confirmation for retiring locations -- `search-plugin`: Support for the location occupation assignment menu +- `search-plugin`: Support for new screens: + + - location occupation assignment + - civilization animal training knowledge + - animal trainer assignment + - `tweak`: - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu diff --git a/library/xml b/library/xml index cc74796a9..c8f486bf7 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit cc74796a90b139e6f7ca7291d5161f84d7beb985 +Subproject commit c8f486bf79ee456ef7a9ed5ed938263fd3703466 diff --git a/plugins/search.cpp b/plugins/search.cpp index cd94b3320..83d498367 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -7,6 +7,7 @@ #include "uicommon.h" +#include "df/creature_raw.h" #include "df/ui_look_list.h" #include "df/viewscreen_announcelistst.h" #include "df/viewscreen_petst.h" @@ -621,7 +622,7 @@ protected: }; // This basic match function is separated out from the generic multi column class, because the -// pets screen, which uses a union in its primary list, will cause a compile failure is this +// pets screen, which uses a union in its primary list, will cause a compile failure if this // match function exists in the generic class template < class S, class T, class PARENT = search_generic > class search_multicolumn_modifiable : public search_multicolumn_modifiable_generic @@ -751,7 +752,7 @@ template V generic_search_hook ::module; typedef generic_search_hook module##_hook; \ template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, feed, prio); \ template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, render, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio) + template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio); // // END: Generic Search functionality @@ -761,19 +762,24 @@ template V generic_search_hook ::module; // // START: Animal screen search // -typedef df::viewscreen_petst::T_animal T_animal; -typedef df::viewscreen_petst::T_mode T_mode; -class pets_search : public search_multicolumn_modifiable_generic +typedef search_multicolumn_modifiable_generic pets_search_base; +class pets_search : public pets_search_base { + typedef df::viewscreen_petst::T_animal T_animal; + typedef df::viewscreen_petst::T_mode T_mode; public: void render() const { - if (viewscreen->mode == T_mode::List) - print_search_option(25, 4); + print_search_option(25, 4); } private: + bool can_init(df::viewscreen_petst *screen) + { + return pets_search_base::can_init(screen) && screen->mode == T_mode::List; + } + int32_t *get_viewscreen_cursor() { return &viewscreen->cursor; @@ -876,13 +882,130 @@ private: std::vector *is_adopting, is_adopting_s; }; -IMPLEMENT_HOOKS(df::viewscreen_petst, pets_search); +IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, pets_search, 1, 0); // // END: Animal screen search // +// +// START: Animal knowledge screen search +// + +typedef search_generic animal_knowledge_search_base; +class animal_knowledge_search : public animal_knowledge_search_base +{ + typedef df::viewscreen_petst::T_mode T_mode; + bool can_init(df::viewscreen_petst *screen) + { + return animal_knowledge_search_base::can_init(screen) && screen->mode == T_mode::TrainingKnowledge; + } + +public: + void render() const + { + print_search_option(2, 4); + } + +private: + int32_t *get_viewscreen_cursor() + { + return NULL; + } + + vector *get_primary_list() + { + return &viewscreen->known; + } + + string get_element_description(int32_t id) const + { + auto craw = df::creature_raw::find(id); + string out; + if (craw) + { + for (size_t i = 0; i < 3; ++i) + out += craw->name[i] + " "; + } + return out; + } +}; + +IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_knowledge_search, 2, 0); + +// +// END: Animal knowledge screen search +// + + +// +// START: Animal trainer search +// + +typedef search_twocolumn_modifiable animal_trainer_search_base; +class animal_trainer_search : public animal_trainer_search_base +{ + typedef df::viewscreen_petst::T_mode T_mode; + typedef df::viewscreen_petst::T_trainer_mode T_trainer_mode; + + bool can_init(df::viewscreen_petst *screen) + { + return animal_trainer_search_base::can_init(screen) && screen->mode == T_mode::SelectTrainer; + } + +public: + void render() const + { + Screen::paintTile(Screen::Pen(186, 8, 0), 14, 2); + Screen::paintTile(Screen::Pen(186, 8, 0), gps->dimx - 14, 2); + Screen::paintTile(Screen::Pen(201, 8, 0), 14, 1); + Screen::paintTile(Screen::Pen(187, 8, 0), gps->dimx - 14, 1); + for (int x = 15; x <= gps->dimx - 15; ++x) + { + Screen::paintTile(Screen::Pen(205, 8, 0), x, 1); + Screen::paintTile(Screen::Pen(0, 0, 0), x, 2); + } + print_search_option(16, 2); + } + +private: + int32_t *get_viewscreen_cursor() + { + return &viewscreen->trainer_cursor; + } + + vector *get_primary_list() + { + return &viewscreen->trainer_unit; + } + + string get_element_description(df::unit *u) const + { + return get_unit_description(u); + } + + std::vector *get_secondary_list() + { + return &viewscreen->trainer_mode; + } + +public: + bool process_input(set *input) + { + if (input->count(interface_key::SELECT) && viewscreen->trainer_unit.empty() && !in_entry_mode()) + return true; + return animal_trainer_search_base::process_input(input); + } + +}; + +IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_trainer_search, 3, 0); + +// +// END: Animal trainer search +// + // // START: Stocks screen search @@ -1997,6 +2120,8 @@ IMPLEMENT_HOOKS(df::viewscreen_locationsst, location_assign_occupation_search); HOOK_ACTION(trade_search_fort_hook) \ HOOK_ACTION(stocks_search_hook) \ HOOK_ACTION(pets_search_hook) \ + HOOK_ACTION(animal_knowledge_search_hook) \ + HOOK_ACTION(animal_trainer_search_hook) \ HOOK_ACTION(military_search_hook) \ HOOK_ACTION(nobles_search_hook) \ HOOK_ACTION(profiles_search_hook) \ From c23ac50250e9c4137c8c5fc38c44e41ed2940c71 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 27 Dec 2015 16:39:10 -0500 Subject: [PATCH 135/222] Always run dfhack.init-example if dfhack.init doesn't exist This previously only happened if no files matching *dfhack*.init existed --- library/Core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index 61a1cc2b8..00447fe72 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1256,7 +1256,7 @@ static void run_dfhack_init(color_ostream &out, Core *core) std::vector prefixes(1, "dfhack"); size_t count = loadScriptFiles(core, out, prefixes, "."); - if (!count) + if (!count || !Filesystem::isfile("dfhack.init")) { core->runCommand(out, "gui/no-dfhack-init"); core->loadScriptFile(out, "dfhack.init-example", true); From 2ef24a3daf58d186cbeb00c7d60e7150d70f6202 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 27 Dec 2015 22:35:14 -0500 Subject: [PATCH 136/222] Prevent nested command invocations in command-prompt For example, running "devel/send-key SELECT" in command-prompt would blow up the stack by recursively calling submit() --- plugins/command-prompt.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/command-prompt.cpp b/plugins/command-prompt.cpp index 2ac4d3af9..dd3b59398 100644 --- a/plugins/command-prompt.cpp +++ b/plugins/command-prompt.cpp @@ -56,7 +56,7 @@ public: df::building* getSelectedBuilding() { return Gui::getAnyBuilding(parent); } std::string getFocusString() { return "commandprompt"; } - viewscreen_commandpromptst(std::string entry):is_response(false) + viewscreen_commandpromptst(std::string entry):is_response(false), submitted(false) { show_fps=gps->display_frames; gps->display_frames=0; @@ -127,6 +127,7 @@ protected: std::list > responses; int cursor_pos; int history_idx; + bool submitted; bool is_response; bool show_fps; int frame; @@ -194,6 +195,9 @@ void viewscreen_commandpromptst::submit() Screen::dismiss(this); return; } + if(submitted) + return; + submitted = true; prompt_ostream out(this); Core::getInstance().runCommand(out, get_entry()); if(out.empty() && responses.empty()) From 39086acf64b246a34a663e4c7293dc4e2b2aec01 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 15:46:42 -0500 Subject: [PATCH 137/222] Merge export-dt-ini changes from splintermind/Dwarf-Therapist --- library/xml | 2 +- scripts/devel/export-dt-ini.lua | 94 ++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 33 deletions(-) diff --git a/library/xml b/library/xml index c8f486bf7..1017578b0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c8f486bf79ee456ef7a9ed5ed938263fd3703466 +Subproject commit 1017578b0e32257aefa39bcc2444b8830100ff74 diff --git a/scripts/devel/export-dt-ini.lua b/scripts/devel/export-dt-ini.lua index c75acd1dd..0bb344d5c 100644 --- a/scripts/devel/export-dt-ini.lua +++ b/scripts/devel/export-dt-ini.lua @@ -1,10 +1,8 @@ -- Exports an ini file for Dwarf Therapist. --[[=begin - devel/export-dt-ini =================== Exports an ini file containing memory addresses for Dwarf Therapist. - =end]] local utils = require 'utils' @@ -66,22 +64,39 @@ end -- List of actual values header('addresses') -address('translation_vector',globals,'world','raws','language','translations') -address('language_vector',globals,'world','raws','language','words') -address('creature_vector',globals,'world','units','all') -address('active_creature_vector',globals,'world','units','active') -address('dwarf_race_index',globals,'ui','race_id') -address('squad_vector',globals,'world','squads','all') -address('current_year',globals,'cur_year') address('cur_year_tick',globals,'cur_year_tick') +address('current_year',globals,'cur_year') address('dwarf_civ_index',globals,'ui','civ_id') -address('races_vector',globals,'world','raws','creatures','all') -address('reactions_vector',globals,'world','raws','reactions') -address('events_vector',globals,'world','history','events') -address('historical_figures_vector',globals,'world','history','figures') -address('fake_identities_vector',globals,'world','identities','all') +address('dwarf_race_index',globals,'ui','race_id') address('fortress_entity',globals,'ui','main','fortress_entity') address('historical_entities_vector',globals,'world','entities','all') +address('creature_vector',globals,'world','units','all') +address('active_creature_vector',globals,'world','units','active') +address('weapons_vector',globals,'world','items','other','WEAPON') +address('shields_vector',globals,'world','items','other', 'SHIELD') +address('quivers_vector',globals,'world','items','other', 'QUIVER') +address('crutches_vector',globals,'world','items','other', 'CRUTCH') +address('backpacks_vector',globals,'world','items','other', 'BACKPACK') +address('ammo_vector',globals,'world','items','other', 'AMMO') +address('flasks_vector',globals,'world','items','other', 'FLASK') +address('pants_vector',globals,'world','items','other', 'PANTS') +address('armor_vector',globals,'world','items','other', 'ARMOR') +address('shoes_vector',globals,'world','items','other', 'SHOES') +address('helms_vector',globals,'world','items','other', 'HELM') +address('gloves_vector',globals,'world','items','other', 'GLOVES') +address('artifacts_vector',globals,'world','artifacts','all') +address('squad_vector',globals,'world','squads','all') +address('activities_vector',globals,'world','activities','all') +address('fake_identities_vector',globals,'world','identities','all') +address('poetic_forms_vector',globals,'world','poetic_forms','all') +address('musical_forms_vector',globals,'world','musical_forms','all') +address('dance_forms_vector',globals,'world','dance_forms','all') +address('occupations_vector',globals,'world','occupations','all') +address('world_data',globals,'world','world_data') +address('material_templates_vector',globals,'world','raws','material_templates') +address('inorganics_vector',globals,'world','raws','inorganics') +address('plants_vector',globals,'world','raws','plants','all') +address('races_vector',globals,'world','raws','creatures','all') address('itemdef_weapons_vector',globals,'world','raws','itemdefs','weapons') address('itemdef_trap_vector',globals,'world','raws','itemdefs','trapcomps') address('itemdef_toy_vector',globals,'world','raws','itemdefs','toys') @@ -96,29 +111,17 @@ address('itemdef_shield_vector',globals,'world','raws','itemdefs','shields') address('itemdef_helm_vector',globals,'world','raws','itemdefs','helms') address('itemdef_pant_vector',globals,'world','raws','itemdefs','pants') address('itemdef_food_vector',globals,'world','raws','itemdefs','food') +address('language_vector',globals,'world','raws','language','words') +address('translation_vector',globals,'world','raws','language','translations') address('colors_vector',globals,'world','raws','language','colors') address('shapes_vector',globals,'world','raws','language','shapes') +address('reactions_vector',globals,'world','raws','reactions') address('base_materials',globals,'world','raws','mat_table','builtin') -address('inorganics_vector',globals,'world','raws','inorganics') -address('plants_vector',globals,'world','raws','plants','all') -address('material_templates_vector',globals,'world','raws','material_templates') address('all_syndromes_vector',globals,'world','raws','syndromes','all') -address('world_data',globals,'world','world_data') -address('active_sites_vector',df.world_data,'active_site') +address('events_vector',globals,'world','history','events') +address('historical_figures_vector',globals,'world','history','figures') address('world_site_type',df.world_site,'type') -address('weapons_vector',globals,'world','items','other','WEAPON') -address('shields_vector',globals,'world','items','other', 'SHIELD') -address('quivers_vector',globals,'world','items','other', 'QUIVER') -address('crutches_vector',globals,'world','items','other', 'CRUTCH') -address('backpacks_vector',globals,'world','items','other', 'BACKPACK') -address('ammo_vector',globals,'world','items','other', 'AMMO') -address('flasks_vector',globals,'world','items','other', 'FLASK') -address('pants_vector',globals,'world','items','other', 'PANTS') -address('armor_vector',globals,'world','items','other', 'ARMOR') -address('shoes_vector',globals,'world','items','other', 'SHOES') -address('helms_vector',globals,'world','items','other', 'HELM') -address('gloves_vector',globals,'world','items','other', 'GLOVES') -address('artifacts_vector',globals,'world','artifacts','all') +address('active_sites_vector',df.world_data,'active_site') header('offsets') address('word_table',df.language_translation,'words') @@ -220,6 +223,7 @@ address('stack_size',df.item_actual,'stack_size') address('wear',df.item_actual,'wear') address('mat_type',df.item_crafted,'mat_type') address('mat_index',df.item_crafted,'mat_index') +address('maker_race',df.item_crafted,'maker_race') address('quality',df.item_crafted,'quality') header('item_subtype_offsets') @@ -400,9 +404,20 @@ address('id',df.squad,'id') address('name',df.squad,'name') address('alias',df.squad,'alias') address('members',df.squad,'positions') +address('orders',df.squad,'orders') +address('schedules',df.squad,'schedule') +if os_type ~= 'windows' then --squad_schedule_entry size + value('sched_size',0x20) +else + value('sched_size',0x40) +end +address('sched_orders',df.squad_schedule_entry,'orders') +address('sched_assign',df.squad_schedule_entry,'order_assignments') +address('alert',df.squad,'cur_alert_idx') address('carry_food',df.squad,'carry_food') address('carry_water',df.squad,'carry_water') address('ammunition',df.squad,'ammunition') +address('ammunition_qty',df.squad_ammo_spec,'amount') address('quiver',df.squad_position,'quiver') address('backpack',df.squad_position,'backpack') address('flask',df.squad_position,'flask') @@ -416,6 +431,21 @@ address('weapon_vector',df.squad_position,'uniform','weapon') address('uniform_item_filter',df.squad_uniform_spec,'item_filter') address('uniform_indiv_choice',df.squad_uniform_spec,'indiv_choice') +header('activity_offsets') +address('activity_type',df.activity_entry,'id') +address('events',df.activity_entry,'events') +address('participants',df.activity_event_combat_trainingst,'participants') +address('sq_lead',df.activity_event_skill_demonstrationst,'hist_figure_id') +address('sq_skill',df.activity_event_skill_demonstrationst,'skill') +address('sq_train_rounds',df.activity_event_skill_demonstrationst,'train_rounds') +address('pray_deity',df.activity_event_prayerst,'histfig_id') +address('pray_sphere',df.activity_event_prayerst,'topic') +address('knowledge_category',df.activity_event_ponder_topicst,'knowledge_category') +address('knowledge_flag',df.activity_event_ponder_topicst,'knowledge_flag') +address('perf_type',df.activity_event_performancest,'type') +address('perf_participants',df.activity_event_performancest,'activity_event_performancest::anon2') +address('perf_histfig',df.activity_event_performancest::anon2,'histfig_id') + -- Final creation of the file local out = io.open('therapist.ini', 'w') From 9dbb5b92f9f234198c5644929df946c70ef84b64 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 15:55:09 -0500 Subject: [PATCH 138/222] Fix some issues in devel/export-dt-ini.lua --- scripts/devel/export-dt-ini.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/devel/export-dt-ini.lua b/scripts/devel/export-dt-ini.lua index 0bb344d5c..28a583a2d 100644 --- a/scripts/devel/export-dt-ini.lua +++ b/scripts/devel/export-dt-ini.lua @@ -443,8 +443,8 @@ address('pray_sphere',df.activity_event_prayerst,'topic') address('knowledge_category',df.activity_event_ponder_topicst,'knowledge_category') address('knowledge_flag',df.activity_event_ponder_topicst,'knowledge_flag') address('perf_type',df.activity_event_performancest,'type') -address('perf_participants',df.activity_event_performancest,'activity_event_performancest::anon2') -address('perf_histfig',df.activity_event_performancest::anon2,'histfig_id') +address('perf_participants',df.activity_event_performancest,'participants') +address('perf_histfig',df.activity_event_performancest,'anon_2') -- Final creation of the file From 6637a8516405419f8fd97106ceadf2e0b5a95a45 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 16:31:36 -0500 Subject: [PATCH 139/222] Don't hardcode line numbers in script documentation check --- travis/script-in-readme.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/travis/script-in-readme.py b/travis/script-in-readme.py index a6804fb00..b8ad67b65 100644 --- a/travis/script-in-readme.py +++ b/travis/script-in-readme.py @@ -1,3 +1,4 @@ +from __future__ import print_function from io import open import os from os.path import basename, dirname, join, splitext @@ -16,6 +17,8 @@ def check_file(fname): errors, doclines = 0, [] with open(fname, errors='ignore') as f: for l in f.readlines(): + if not l.strip(): + continue if doclines or l.strip().endswith('=begin'): doclines.append(l.rstrip()) if l.startswith('=end'): @@ -26,7 +29,7 @@ def check_file(fname): else: print('Error: no documentation in: ' + fname) return 1 - title, underline = doclines[2], doclines[3] + title, underline = doclines[1], doclines[2] if underline != '=' * len(title): print('Error: title/underline mismatch:', fname, title, underline) errors += 1 From 7431329e2df547fb0cec39a5ff209e1696a369f3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 17:01:47 -0500 Subject: [PATCH 140/222] New script: devel/save-version.lua --- NEWS.rst | 4 + scripts/devel/save-version.lua | 146 +++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 scripts/devel/save-version.lua diff --git a/NEWS.rst b/NEWS.rst index cab6c0c69..c213b165f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -41,6 +41,10 @@ Internals ./dfhack +devel/print-args example "Dwarf Fortress.exe" +devel/print-args example +New Scripts +----------- +- `devel/save-version`: Displays DF version information about the current save + New Features ------------ - `confirm`: Added a confirmation for retiring locations diff --git a/scripts/devel/save-version.lua b/scripts/devel/save-version.lua new file mode 100644 index 000000000..5b346c1d5 --- /dev/null +++ b/scripts/devel/save-version.lua @@ -0,0 +1,146 @@ +-- Display DF version information about the current save +--@module = true +--[[=begin + +devel/save-version +================== +Display DF version information about the current save + +=end]] + +local function dummy() return nil end + +function has_field(tbl, field) + return (pcall(function() assert(tbl[field] ~= nil) end)) +end + +function class_has_field(cls, field) + local obj = cls:new() + local ret = has_field(obj, field) + obj:delete() + return ret +end + +versions = { +-- skipped v0.21-v0.28 + [1287] = "0.31.01", + [1288] = "0.31.02", + [1289] = "0.31.03", + [1292] = "0.31.04", + [1295] = "0.31.05", + [1297] = "0.31.06", + [1300] = "0.31.08", + [1304] = "0.31.09", + [1305] = "0.31.10", + [1310] = "0.31.11", + [1311] = "0.31.12", + [1323] = "0.31.13", + [1325] = "0.31.14", + [1326] = "0.31.15", + [1327] = "0.31.16", + [1340] = "0.31.17", + [1341] = "0.31.18", + [1351] = "0.31.19", + [1353] = "0.31.20", + [1354] = "0.31.21", + [1359] = "0.31.22", + [1360] = "0.31.23", + [1361] = "0.31.24", + [1362] = "0.31.25", + [1372] = "0.34.01", + [1374] = "0.34.02", + [1376] = "0.34.03", + [1377] = "0.34.04", + [1378] = "0.34.05", + [1382] = "0.34.06", + [1383] = "0.34.07", + [1400] = "0.34.08", + [1402] = "0.34.09", + [1403] = "0.34.10", + [1404] = "0.34.11", + [1441] = "0.40.01", + [1442] = "0.40.02", + [1443] = "0.40.03", + [1444] = "0.40.04", + [1445] = "0.40.05", + [1446] = "0.40.06", + [1448] = "0.40.07", + [1449] = "0.40.08", + [1451] = "0.40.09", + [1452] = "0.40.10", + [1456] = "0.40.11", + [1459] = "0.40.12", + [1462] = "0.40.13", + [1469] = "0.40.14", + [1470] = "0.40.15", + [1471] = "0.40.16", + [1472] = "0.40.17", + [1473] = "0.40.18", + [1474] = "0.40.19", + [1477] = "0.40.20", + [1478] = "0.40.21", + [1479] = "0.40.22", + [1480] = "0.40.23", + [1481] = "0.40.24", + [1531] = "0.42.01", + [1532] = "0.42.02", + [1533] = "0.42.03", + [1534] = "0.42.04", +} + +min_version = math.huge +max_version = -math.huge + +for k in pairs(versions) do + min_version = math.min(min_version, k) + max_version = math.max(max_version, k) +end + +if class_has_field(df.world.T_cur_savegame, 'save_version') then + function get_save_version() + return df.global.world.cur_savegame.save_version + end +elseif class_has_field(df.world.T_pathfinder, 'anon_2') then + function get_save_version() + return df.global.world.pathfinder.anon_2 + end +else + get_save_version = dummy +end + +if class_has_field(df.world, 'original_save_version') then + function get_original_save_version() + return df.global.world.original_save_version + end +else + get_original_save_version = dummy +end + +function describe(version) + if version == 0 then + return 'no world loaded' + elseif versions[version] then + return versions[version] + elseif version < min_version then + return 'unknown old version before ' .. describe(min_version) .. ': ' .. tostring(version) + elseif version > max_version then + return 'unknown new version after ' .. describe(max_version) .. ': ' .. tostring(version) + else + return 'unknown version: ' .. tostring(version) + end +end + +function dump(desc, func) + local ret = tonumber(func()) + if ret then + print(desc .. ': ' .. describe(ret)) + else + dfhack.printerr('could not find ' .. desc .. ' (DFHack version too old)') + end +end + +if not moduleMode then + if not dfhack.isWorldLoaded() then qerror('no world loaded') end + dump('original DF version', get_original_save_version) + dump('most recent DF version', get_save_version) +end From 0a4287afba895cae9f8b50c8a30453eed2afdd66 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 17:28:50 -0500 Subject: [PATCH 141/222] gps scan: fall back to data section --- scripts/devel/find-offsets.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index a105c1350..8718dea6e 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -530,6 +530,9 @@ local function find_gps() local w,h = ms.get_screen_size() local idx, addr = zone.area.int32_t:find_one{w, h, -1, -1} + if not idx then + idx, addr = data.int32_t.find_one{w, h, -1, -1} + end if idx then validate_offset('gps', is_valid_gps, addr, df.graphic, 'dimx') return From 22283066caf48854f40e005f20894e662faf9203 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 17:30:05 -0500 Subject: [PATCH 142/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 1017578b0..15775d808 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1017578b0e32257aefa39bcc2444b8830100ff74 +Subproject commit 15775d808cded53ddcbe2675bdbe03b0f123c707 From 51164d554773c016bd4576052902b1f2681afbcb Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 21:35:47 -0500 Subject: [PATCH 143/222] Add standing orders scans to find-offsets --- scripts/devel/find-offsets.lua | 119 +++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index 8718dea6e..368e8ac98 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -1584,6 +1584,50 @@ Searching for pause_state. Please do as instructed below:]], ms.found_offset('pause_state', addr) end +-- +-- standing orders +-- + +local function find_standing_orders(gname, seq, depends) + if type(seq) ~= 'table' then seq = {seq} end + for k, v in pairs(depends) do + if not dfhack.internal.getAddress(k) then + qerror(('Cannot locate %s: %s not found'):format(gname, k)) + end + df.global[k] = v + end + local addr + if dwarfmode_to_top() then + addr = searcher:find_interactive( + 'Auto-searching for ' .. gname, + 'uint8_t', + function(idx) + df.global.ui.main.mode = df.ui_sidebar_mode.Orders + dwarfmode_feed_input(table.unpack(seq)) + return true + end + ) + else + dfhack.printerr("Won't scan for standing orders global manually: " .. gname) + return + end + + ms.found_offset(gname, addr) +end + +local function exec_finder_so(gname, seq, _depends) + local depends = {} + for k, v in pairs(_depends or {}) do + if k:find('standing_orders_') ~= 1 then + k = 'standing_orders_' .. k + end + depends[k] = v + end + exec_finder(function() + return find_standing_orders(gname, seq, depends) + end, gname) +end + -- -- MAIN FLOW -- @@ -1639,6 +1683,81 @@ exec_finder(find_process_jobs, 'process_jobs') exec_finder(find_process_dig, 'process_dig') exec_finder(find_pause_state, 'pause_state') +print('\nStanding orders:\n') + +exec_finder_so('standing_orders_gather_animals', 'ORDERS_GATHER_ANIMALS') +exec_finder_so('standing_orders_gather_bodies', 'ORDERS_GATHER_BODIES') +exec_finder_so('standing_orders_gather_food', 'ORDERS_GATHER_FOOD') +exec_finder_so('standing_orders_gather_furniture', 'ORDERS_GATHER_FURNITURE') +exec_finder_so('standing_orders_gather_minerals', 'ORDERS_GATHER_STONE') +exec_finder_so('standing_orders_gather_wood', 'ORDERS_GATHER_WOOD') + +exec_finder_so('standing_orders_gather_refuse', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_GATHER'}) +exec_finder_so('standing_orders_gather_refuse_outside', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_OUTSIDE'}, {gather_refuse=1}) +exec_finder_so('standing_orders_gather_vermin_remains', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_OUTSIDE_VERMIN'}, {gather_refuse=1, gather_refuse_outside=1}) +exec_finder_so('standing_orders_dump_bones', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_BONE'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_corpses', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_CORPSE'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_hair', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_STRAND_TISSUE'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_other', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_OTHER'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_shells', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_SHELL'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_skins', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_SKIN'}, {gather_refuse=1}) +exec_finder_so('standing_orders_dump_skulls', + {'ORDERS_REFUSE', 'ORDERS_REFUSE_DUMP_SKULL'}, {gather_refuse=1}) + + +exec_finder_so('standing_orders_auto_butcher', + {'ORDERS_WORKSHOP', 'ORDERS_BUTCHER'}) +exec_finder_so('standing_orders_auto_collect_webs', + {'ORDERS_WORKSHOP', 'ORDERS_COLLECT_WEB'}) +exec_finder_so('standing_orders_auto_fishery', + {'ORDERS_WORKSHOP', 'ORDERS_AUTO_FISHERY'}) +exec_finder_so('standing_orders_auto_kiln', + {'ORDERS_WORKSHOP', 'ORDERS_AUTO_KILN'}) +exec_finder_so('standing_orders_auto_kitchen', + {'ORDERS_WORKSHOP', 'ORDERS_AUTO_KITCHEN'}) +exec_finder_so('standing_orders_auto_loom', + {'ORDERS_WORKSHOP', 'ORDERS_LOOM'}) +exec_finder_so('standing_orders_auto_other', + {'ORDERS_WORKSHOP', 'ORDERS_AUTO_OTHER'}) +exec_finder_so('standing_orders_auto_slaughter', + {'ORDERS_WORKSHOP', 'ORDERS_SLAUGHTER'}) +exec_finder_so('standing_orders_auto_smelter', + {'ORDERS_WORKSHOP', 'ORDERS_AUTO_SMELTER'}) +exec_finder_so('standing_orders_auto_tan', + {'ORDERS_WORKSHOP', 'ORDERS_TAN'}) +exec_finder_so('standing_orders_use_dyed_cloth', + {'ORDERS_WORKSHOP', 'ORDERS_DYED_CLOTH'}) + +exec_finder_so('standing_orders_forbid_other_dead_items', + {'ORDERS_AUTOFORBID', 'ORDERS_FORBID_OTHER_ITEMS'}) +exec_finder_so('standing_orders_forbid_other_nohunt', + {'ORDERS_AUTOFORBID', 'ORDERS_FORBID_OTHER_CORPSE'}) +exec_finder_so('standing_orders_forbid_own_dead', + {'ORDERS_AUTOFORBID', 'ORDERS_FORBID_YOUR_CORPSE'}) +exec_finder_so('standing_orders_forbid_own_dead_items', + {'ORDERS_AUTOFORBID', 'ORDERS_FORBID_YOUR_ITEMS'}) +exec_finder_so('standing_orders_forbid_used_ammo', + {'ORDERS_AUTOFORBID', 'ORDERS_FORBID_PROJECTILE'}) + +exec_finder_so('standing_orders_farmer_harvest', 'ORDERS_ALL_HARVEST') +exec_finder_so('standing_orders_job_cancel_announce', 'ORDERS_EXCEPTIONS') +exec_finder_so('standing_orders_mix_food', 'ORDERS_MIXFOODS') + +exec_finder_so('standing_orders_zoneonly_drink', + {'ORDERS_ZONE', 'ORDERS_ZONE_DRINKING'}) +exec_finder_so('standing_orders_zoneonly_fish', + {'ORDERS_ZONE', 'ORDERS_ZONE_FISHING'}) + +dwarfmode_to_top() print('\nDone. Now exit the game with the die command and add\n'.. 'the newly-found globals to symbols.xml. You can find them\n'.. 'in stdout.log or here:\n') From 2079093d5a20ef5ffd129aedb59b40ecf68d5dbf Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 28 Dec 2015 23:19:02 -0500 Subject: [PATCH 144/222] Fix new addresses in export-dt-ini --- library/xml | 2 +- scripts/devel/export-dt-ini.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index 15775d808..357197817 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 15775d808cded53ddcbe2675bdbe03b0f123c707 +Subproject commit 357197817bf05677ff51287b3015e1621f4c0888 diff --git a/scripts/devel/export-dt-ini.lua b/scripts/devel/export-dt-ini.lua index 28a583a2d..180a3e011 100644 --- a/scripts/devel/export-dt-ini.lua +++ b/scripts/devel/export-dt-ini.lua @@ -443,8 +443,8 @@ address('pray_sphere',df.activity_event_prayerst,'topic') address('knowledge_category',df.activity_event_ponder_topicst,'knowledge_category') address('knowledge_flag',df.activity_event_ponder_topicst,'knowledge_flag') address('perf_type',df.activity_event_performancest,'type') -address('perf_participants',df.activity_event_performancest,'participants') -address('perf_histfig',df.activity_event_performancest,'anon_2') +address('perf_participants',df.activity_event_performancest,'participant_actions') +address('perf_histfig',df.activity_event_performancest.T_participant_actions,'histfig_id') -- Final creation of the file From bd7039f4e0540fab544bbd8a859931aa0e3a19be Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 30 Dec 2015 10:11:27 -0500 Subject: [PATCH 145/222] Don't show prerelease message during worldgen --- scripts/gui/prerelease-warning.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua index bb72cbafc..8f99e450d 100644 --- a/scripts/gui/prerelease-warning.lua +++ b/scripts/gui/prerelease-warning.lua @@ -8,6 +8,10 @@ Shows a warning on world load for pre-release builds. =end]] if not dfhack.isPrerelease() then qerror('not a prerelease build') end +-- Don't fire during worldgen +if dfhack.internal.getAddress('gametype') and df.global.gametype == df.game_type.NONE then + return +end local gui = require 'gui' local dlg = require 'gui.dialogs' From 26f66ce8e263a6da48e3933f0e784d4eef44cff9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 30 Dec 2015 11:27:19 -0500 Subject: [PATCH 146/222] Bump version to 0.42.04 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c027374f..2a20b8dba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,7 +97,7 @@ if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhac endif() # set up versioning. -set(DF_VERSION "0.42.03") +set(DF_VERSION "0.42.04") SET(DFHACK_RELEASE "alpha1") SET(DFHACK_PRERELEASE TRUE) From aaae6d54cddb4303f48fa468af245ad96e28d0e4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 30 Dec 2015 12:15:01 -0500 Subject: [PATCH 147/222] exportlegends: Fix issues with entities with no race Some, such as specific site governments, have races of -1 Fixes #780 --- NEWS.rst | 1 + scripts/exportlegends.lua | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index c213b165f..d43229487 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -60,6 +60,7 @@ New Features Fixes ----- +- `exportlegends`: Handles entities without specific races - `showmood`: Fixed name display on OS X/Linux diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 3c2999412..2ff14860d 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -205,7 +205,9 @@ function export_more_legends_xml() for entityK, entityV in ipairs(df.global.world.entities.all) do io.write ("\t".."".."\n") io.write ("\t\t"..""..entityV.id.."".."\n") - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[entityV.race].creature_id):lower().."".."\n") + if entityV.race >= 0 then + io.write ("\t\t"..""..(df.global.world.raws.creatures.all[entityV.race].creature_id):lower().."".."\n") + end io.write ("\t\t"..""..(df.historical_entity_type[entityV.type]):lower().."".."\n") if (df.historical_entity_type[entityV.type]):lower() == "religion" then -- Get worshipped figure if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nill and From d284d9e83ad168115d05a9ae4708a1ea58e60d24 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 30 Dec 2015 14:45:15 -0500 Subject: [PATCH 148/222] exportlegends cleanup * Remove unnecessary string concatenations (e.g. `write("".."\n")`) * Open a separate file instead of rerouting stdout - this ensures that stdout doesn't point to the xml file if the export fails for some reason * Encode artifact descriptions properly --- scripts/exportlegends.lua | 294 +++++++++++++++++++------------------- 1 file changed, 148 insertions(+), 146 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 2ff14860d..39b21e417 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -91,151 +91,153 @@ function export_more_legends_xml() local year_str = string.format('%0'..math.max(5, string.len(''..df.global.cur_year))..'d', df.global.cur_year) local date_str = year_str..string.format('-%02d-%02d', month, day) - io.output(tostring(df.global.world.cur_savegame.save_dir).."-"..date_str.."-legends_plus.xml") + local filename = df.global.world.cur_savegame.save_dir.."-"..date_str.."-legends_plus.xml" + local file = io.open(filename, 'w') + if not file then qerror("could not open file: " .. filename) end - io.write ("".."\n") - io.write ("".."\n") - io.write (""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name)).."".."\n") - io.write (""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name,1)).."".."\n") + file:write("\n") + file:write("\n") + file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name)).."\n") + file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name,1)).."\n") - io.write ("".."\n") + file:write("\n") for regionK, regionV in ipairs(df.global.world.world_data.regions) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..regionV.index.."".."\n") - io.write ("\t\t".."") + file:write("\t\n") + file:write("\t\t"..regionV.index.."\n") + file:write("\t\t") for xK, xVal in ipairs(regionV.region_coords.x) do - io.write (xVal..","..regionV.region_coords.y[xK].."|") + file:write(xVal..","..regionV.region_coords.y[xK].."|") end - io.write ("\n") - io.write ("\t".."".."\n") + file:write("\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for regionK, regionV in ipairs(df.global.world.world_data.underground_regions) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..regionV.index.."".."\n") - io.write ("\t\t".."") + file:write("\t\n") + file:write("\t\t"..regionV.index.."\n") + file:write("\t\t") for xK, xVal in ipairs(regionV.region_coords.x) do - io.write (xVal..","..regionV.region_coords.y[xK].."|") + file:write(xVal..","..regionV.region_coords.y[xK].."|") end - io.write ("\n") - io.write ("\t".."".."\n") + file:write("\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for siteK, siteV in ipairs(df.global.world.world_data.sites) do if (#siteV.buildings > 0) then - io.write ("\t".."".."\n") + file:write("\t\n") for k,v in pairs(siteV) do if (k == "id") then - io.write ("\t\t".."<"..k..">"..tostring(v).."".."\n") + file:write("\t\t<"..k..">"..tostring(v).."\n") elseif (k == "buildings") then - io.write ("\t\t".."".."\n") + file:write("\t\t\n") for buildingK, buildingV in ipairs(siteV.buildings) do - io.write ("\t\t\t".."".."\n") - io.write ("\t\t\t\t"..""..buildingV.id.."".."\n") - io.write ("\t\t\t\t"..""..df.abstract_building_type[buildingV:getType()]:lower().."".."\n") + file:write("\t\t\t\n") + file:write("\t\t\t\t"..buildingV.id.."\n") + file:write("\t\t\t\t"..df.abstract_building_type[buildingV:getType()]:lower().."\n") if (df.abstract_building_type[buildingV:getType()]:lower() ~= "underworld_spire") then - io.write ("\t\t\t\t"..""..dfhack.df2utf(dfhack.TranslateName(buildingV.name, 1)).."".."\n") - io.write ("\t\t\t\t"..""..dfhack.df2utf(dfhack.TranslateName(buildingV.name)).."".."\n") + file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name, 1)).."\n") + file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name)).."\n") end - io.write ("\t\t\t".."".."\n") + file:write("\t\t\t\n") end - io.write ("\t\t".."".."\n") + file:write("\t\t\n") end end - io.write ("\t".."".."\n") + file:write("\t\n") end end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for wcK, wcV in ipairs(df.global.world.world_data.constructions.list) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..wcV.id.."".."\n") - io.write ("\t\t"..""..dfhack.df2utf(dfhack.TranslateName(wcV.name,1)).."".."\n") - io.write ("\t\t"..""..(df.world_construction_type[wcV:getType()]):lower().."".."\n") - io.write ("\t\t".."") + file:write("\t\n") + file:write("\t\t"..wcV.id.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(wcV.name,1)).."\n") + file:write("\t\t"..(df.world_construction_type[wcV:getType()]):lower().."\n") + file:write("\t\t") for xK, xVal in ipairs(wcV.square_pos.x) do - io.write (xVal..","..wcV.square_pos.y[xK].."|") + file:write(xVal..","..wcV.square_pos.y[xK].."|") end - io.write ("\n") - io.write ("\t".."".."\n") + file:write("\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for artifactK, artifactV in ipairs(df.global.world.artifacts.all) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..artifactV.id.."".."\n") + file:write("\t\n") + file:write("\t\t"..artifactV.id.."\n") if (artifactV.item:getType() ~= -1) then - io.write ("\t\t"..""..tostring(df.item_type[artifactV.item:getType()]):lower().."".."\n") + file:write("\t\t"..tostring(df.item_type[artifactV.item:getType()]):lower().."\n") if (artifactV.item:getSubtype() ~= -1) then - io.write ("\t\t"..""..artifactV.item.subtype.name.."".."\n") + file:write("\t\t"..artifactV.item.subtype.name.."\n") end end if (table.containskey(artifactV.item,"description")) then - io.write ("\t\t"..""..artifactV.item.description:lower().."".."\n") + file:write("\t\t"..dfhack.df2utf(artifactV.item.description:lower()).."\n") end if (artifactV.item:getMaterial() ~= -1 and artifactV.item:getMaterialIndex() ~= -1) then - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(artifactV.item:getMaterial(), artifactV.item:getMaterialIndex())).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(artifactV.item:getMaterial(), artifactV.item:getMaterialIndex())).."\n") end - io.write ("\t".."".."\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n".."".."\n") + file:write("\n\n") - io.write ("".."\n") + file:write("\n") for entityPopK, entityPopV in ipairs(df.global.world.entity_populations) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..entityPopV.id.."".."\n") + file:write("\t\n") + file:write("\t\t"..entityPopV.id.."\n") for raceK, raceV in ipairs(entityPopV.races) do local raceName = (df.global.world.raws.creatures.all[raceV].creature_id):lower() - io.write ("\t\t"..""..raceName..":"..entityPopV.counts[raceK].."".."\n") + file:write("\t\t"..raceName..":"..entityPopV.counts[raceK].."\n") end - io.write ("\t\t"..""..entityPopV.civ_id.."".."\n") - io.write ("\t".."".."\n") + file:write("\t\t"..entityPopV.civ_id.."\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for entityK, entityV in ipairs(df.global.world.entities.all) do - io.write ("\t".."".."\n") - io.write ("\t\t"..""..entityV.id.."".."\n") + file:write("\t\n") + file:write("\t\t"..entityV.id.."\n") if entityV.race >= 0 then - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[entityV.race].creature_id):lower().."".."\n") + file:write("\t\t"..(df.global.world.raws.creatures.all[entityV.race].creature_id):lower().."\n") end - io.write ("\t\t"..""..(df.historical_entity_type[entityV.type]):lower().."".."\n") + file:write("\t\t"..(df.historical_entity_type[entityV.type]):lower().."\n") if (df.historical_entity_type[entityV.type]):lower() == "religion" then -- Get worshipped figure if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nill and #entityV.unknown1b.worship == 1) then - io.write ("\t\t"..""..entityV.unknown1b.worship[0].."".."\n") + file:write("\t\t"..entityV.unknown1b.worship[0].."\n") else print(entityV.unknown1b, entityV.unknown1b.worship, #entityV.unknown1b.worship) end end for id, link in pairs(entityV.entity_links) do - io.write ("\t\t".."".."\n") + file:write("\t\t\n") for k, v in pairs(link) do if (k == "type") then - io.write ("\t\t\t".."<"..k..">"..tostring(df.entity_entity_link_type[v]).."".."\n") + file:write("\t\t\t<"..k..">"..tostring(df.entity_entity_link_type[v]).."\n") else - io.write ("\t\t\t".."<"..k..">"..v.."".."\n") + file:write("\t\t\t<"..k..">"..v.."\n") end end - io.write ("\t\t".."".."\n") + file:write("\t\t\n") end for id, link in ipairs(entityV.children) do - io.write ("\t\t"..""..link.."".."\n") + file:write("\t\t"..link.."\n") end - io.write ("\t".."".."\n") + file:write("\t\n") end - io.write ("".."\n") + file:write("\n") - io.write ("".."\n") + file:write("\n") for ID, event in ipairs(df.global.world.history.events) do if event:getType() == df.history_event_type.ADD_HF_ENTITY_LINK or event:getType() == df.history_event_type.ADD_HF_SITE_LINK @@ -276,9 +278,9 @@ function export_more_legends_xml() or event:getType() == df.history_event_type.HIST_FIGURE_WOUNDED or event:getType() == df.history_event_type.HIST_FIGURE_DIED then - io.write ("\t".."".."\n") - io.write ("\t\t"..""..event.id.."".."\n") - io.write ("\t\t"..""..tostring(df.history_event_type[event:getType()]):lower().."".."\n") + file:write("\t\n") + file:write("\t\t"..event.id.."\n") + file:write("\t\t"..tostring(df.history_event_type[event:getType()]):lower().."\n") for k,v in pairs(event) do if k == "year" or k == "seconds" or k == "flags" or k == "id" or (k == "region" and event:getType() ~= df.history_event_type.HF_DOES_INTERACTION) @@ -286,70 +288,70 @@ function export_more_legends_xml() or k == "anon_1" or k == "anon_2" or k == "flags2" or k == "unk1" then elseif event:getType() == df.history_event_type.ADD_HF_ENTITY_LINK and k == "link_type" then - io.write ("\t\t".."<"..k..">"..df.histfig_entity_link_type[v]:lower().."".."\n") + file:write("\t\t<"..k..">"..df.histfig_entity_link_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.ADD_HF_ENTITY_LINK and k == "position_id" then local entity = findEntity(event.civ) if (entity ~= nil and event.civ > -1 and v > -1) then for entitypositionsK, entityPositionsV in ipairs(entity.positions.own) do if entityPositionsV.id == v then - io.write ("\t\t"..""..tostring(entityPositionsV.name[0]):lower().."".."\n") + file:write("\t\t"..tostring(entityPositionsV.name[0]):lower().."\n") break end end else - io.write ("\t\t".."-1".."\n") + file:write("\t\t-1\n") end elseif event:getType() == df.history_event_type.CREATE_ENTITY_POSITION and k == "position" then local entity = findEntity(event.site_civ) if (entity ~= nil and v > -1) then for entitypositionsK, entityPositionsV in ipairs(entity.positions.own) do if entityPositionsV.id == v then - io.write ("\t\t"..""..tostring(entityPositionsV.name[0]):lower().."".."\n") + file:write("\t\t"..tostring(entityPositionsV.name[0]):lower().."\n") break end end else - io.write ("\t\t".."-1".."\n") + file:write("\t\t-1\n") end elseif event:getType() == df.history_event_type.REMOVE_HF_ENTITY_LINK and k == "link_type" then - io.write ("\t\t".."<"..k..">"..df.histfig_entity_link_type[v]:lower().."".."\n") + file:write("\t\t<"..k..">"..df.histfig_entity_link_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.REMOVE_HF_ENTITY_LINK and k == "position_id" then local entity = findEntity(event.civ) if (entity ~= nil and event.civ > -1 and v > -1) then for entitypositionsK, entityPositionsV in ipairs(entity.positions.own) do if entityPositionsV.id == v then - io.write ("\t\t"..""..tostring(entityPositionsV.name[0]):lower().."".."\n") + file:write("\t\t"..tostring(entityPositionsV.name[0]):lower().."\n") break end end else - io.write ("\t\t".."-1".."\n") + file:write("\t\t-1\n") end elseif event:getType() == df.history_event_type.ADD_HF_HF_LINK and k == "type" then - io.write ("\t\t"..""..df.histfig_hf_link_type[v]:lower().."".."\n") + file:write("\t\t"..df.histfig_hf_link_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.ADD_HF_SITE_LINK and k == "type" then - io.write ("\t\t"..""..df.histfig_site_link_type[v]:lower().."".."\n") + file:write("\t\t"..df.histfig_site_link_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.REMOVE_HF_SITE_LINK and k == "type" then - io.write ("\t\t"..""..df.histfig_site_link_type[v]:lower().."".."\n") + file:write("\t\t"..df.histfig_site_link_type[v]:lower().."\n") elseif (event:getType() == df.history_event_type.ITEM_STOLEN or event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM or event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM_IMPROVEMENT ) and k == "item_type" then - io.write ("\t\t"..""..df.item_type[v]:lower().."".."\n") + file:write("\t\t"..df.item_type[v]:lower().."\n") elseif (event:getType() == df.history_event_type.ITEM_STOLEN or event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM or event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM_IMPROVEMENT ) and k == "item_subtype" then --if event.item_type > -1 and v > -1 then - io.write ("\t\t".."<"..k..">"..getItemSubTypeName(event.item_type,v).."".."\n") + file:write("\t\t<"..k..">"..getItemSubTypeName(event.item_type,v).."\n") --end elseif event:getType() == df.history_event_type.ITEM_STOLEN and k == "mattype" then if (v > -1) then if (dfhack.matinfo.decode(event.mattype, event.matindex) == nil) then - io.write ("\t\t"..""..event.mattype.."".."\n") - io.write ("\t\t"..""..event.matindex.."".."\n") + file:write("\t\t"..event.mattype.."\n") + file:write("\t\t"..event.matindex.."\n") else - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.mattype, event.matindex)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.mattype, event.matindex)).."\n") end end elseif (event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM or @@ -357,19 +359,19 @@ function export_more_legends_xml() ) and k == "mat_type" then if (v > -1) then if (dfhack.matinfo.decode(event.mat_type, event.mat_index) == nil) then - io.write ("\t\t"..""..event.mat_type.."".."\n") - io.write ("\t\t"..""..event.mat_index.."".."\n") + file:write("\t\t"..event.mat_type.."\n") + file:write("\t\t"..event.mat_index.."\n") else - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.mat_type, event.mat_index)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.mat_type, event.mat_index)).."\n") end end elseif event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM_IMPROVEMENT and k == "imp_mat_type" then if (v > -1) then if (dfhack.matinfo.decode(event.imp_mat_type, event.imp_mat_index) == nil) then - io.write ("\t\t"..""..event.imp_mat_type.."".."\n") - io.write ("\t\t"..""..event.imp_mat_index.."".."\n") + file:write("\t\t"..event.imp_mat_type.."\n") + file:write("\t\t"..event.imp_mat_index.."\n") else - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.imp_mat_type, event.imp_mat_index)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.imp_mat_type, event.imp_mat_index)).."\n") end end @@ -389,76 +391,76 @@ function export_more_legends_xml() event:getType() == df.history_event_type.TOPICAGREEMENT_REJECTED or event:getType() == df.history_event_type.TOPICAGREEMENT_MADE ) and k == "topic" then - io.write ("\t\t"..""..tostring(df.meeting_topic[v]):lower().."".."\n") + file:write("\t\t"..tostring(df.meeting_topic[v]):lower().."\n") elseif event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM_IMPROVEMENT and k == "improvement_type" then - io.write ("\t\t"..""..df.improvement_type[v]:lower().."".."\n") + file:write("\t\t"..df.improvement_type[v]:lower().."\n") elseif ((event:getType() == df.history_event_type.HIST_FIGURE_REACH_SUMMIT and k == "figures") or (event:getType() == df.history_event_type.HIST_FIGURE_NEW_PET and k == "group") or (event:getType() == df.history_event_type.BODY_ABUSED and k == "bodies")) then for detailK,detailV in pairs(v) do - io.write ("\t\t".."<"..k..">"..detailV.."".."\n") + file:write("\t\t<"..k..">"..detailV.."\n") end elseif event:getType() == df.history_event_type.HIST_FIGURE_NEW_PET and k == "pets" then for detailK,detailV in pairs(v) do - io.write ("\t\t".."<"..k..">"..(df.global.world.raws.creatures.all[detailV].creature_id):lower().."".."\n") + file:write("\t\t<"..k..">"..(df.global.world.raws.creatures.all[detailV].creature_id):lower().."\n") end elseif event:getType() == df.history_event_type.BODY_ABUSED and (k == "props") then - io.write ("\t\t".."<"..k.."_item_type"..">"..tostring(df.item_type[event.props.item.item_type]):lower().."".."\n") - io.write ("\t\t".."<"..k.."_item_subtype"..">"..getItemSubTypeName(event.props.item.item_type,event.props.item.item_subtype).."".."\n") + file:write("\t\t<"..k.."_item_type>"..tostring(df.item_type[event.props.item.item_type]):lower().."\n") + file:write("\t\t<"..k.."_item_subtype>"..getItemSubTypeName(event.props.item.item_type,event.props.item.item_subtype).."\n") if (event.props.item.mat_type > -1) then if (dfhack.matinfo.decode(event.props.item.mat_type, event.props.item.mat_index) == nil) then - io.write ("\t\t"..""..event.props.item.mat_type.."".."\n") - io.write ("\t\t"..""..event.props.item.mat_index.."".."\n") + file:write("\t\t"..event.props.item.mat_type.."\n") + file:write("\t\t"..event.props.item.mat_index.."\n") else - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.props.item.mat_type, event.props.item.mat_index)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.props.item.mat_type, event.props.item.mat_index)).."\n") end end - --io.write ("\t\t".."<"..k.."_item_mat_type"..">"..tostring(event.props.item.mat_type).."".."\n") - --io.write ("\t\t".."<"..k.."_item_mat_index"..">"..tostring(event.props.item.mat_index).."".."\n") - io.write ("\t\t".."<"..k.."_pile_type"..">"..tostring(event.props.pile_type).."".."\n") + --file:write("\t\t<"..k.."_item_mat_type>"..tostring(event.props.item.mat_type).."\n") + --file:write("\t\t<"..k.."_item_mat_index>"..tostring(event.props.item.mat_index).."\n") + file:write("\t\t<"..k.."_pile_type>"..tostring(event.props.pile_type).."\n") elseif event:getType() == df.history_event_type.ASSUME_IDENTITY and k == "identity" then if (table.contains(df.global.world.identities.all,v)) then if (df.global.world.identities.all[v].histfig_id == -1) then local thisIdentity = df.global.world.identities.all[v] - io.write ("\t\t"..""..thisIdentity.name.first_name.."".."\n") - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[thisIdentity.race].creature_id):lower().."".."\n") - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[thisIdentity.race].caste[thisIdentity.caste].caste_id):lower().."".."\n") + file:write("\t\t"..thisIdentity.name.first_name.."\n") + file:write("\t\t"..(df.global.world.raws.creatures.all[thisIdentity.race].creature_id):lower().."\n") + file:write("\t\t"..(df.global.world.raws.creatures.all[thisIdentity.race].caste[thisIdentity.caste].caste_id):lower().."\n") else - io.write ("\t\t"..""..df.global.world.identities.all[v].histfig_id.."".."\n") + file:write("\t\t"..df.global.world.identities.all[v].histfig_id.."\n") end end elseif event:getType() == df.history_event_type.MASTERPIECE_CREATED_ARCH_CONSTRUCT and k == "building_type" then - io.write ("\t\t"..""..df.building_type[v]:lower().."".."\n") + file:write("\t\t"..df.building_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.MASTERPIECE_CREATED_ARCH_CONSTRUCT and k == "building_subtype" then if (df.building_type[event.building_type]:lower() == "furnace") then - io.write ("\t\t"..""..df.furnace_type[v]:lower().."".."\n") + file:write("\t\t"..df.furnace_type[v]:lower().."\n") elseif v > -1 then - io.write ("\t\t"..""..tostring(v).."".."\n") + file:write("\t\t"..tostring(v).."\n") end elseif k == "race" then if v > -1 then - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[v].creature_id):lower().."".."\n") + file:write("\t\t"..(df.global.world.raws.creatures.all[v].creature_id):lower().."\n") end elseif k == "caste" then if v > -1 then - io.write ("\t\t"..""..(df.global.world.raws.creatures.all[event.race].caste[v].caste_id):lower().."".."\n") + file:write("\t\t"..(df.global.world.raws.creatures.all[event.race].caste[v].caste_id):lower().."\n") end elseif k == "interaction" and event:getType() == df.history_event_type.HF_DOES_INTERACTION then - io.write ("\t\t"..""..df.global.world.raws.interactions[v].str[3].value.."".."\n") - io.write ("\t\t"..""..df.global.world.raws.interactions[v].str[4].value.."".."\n") + file:write("\t\t"..df.global.world.raws.interactions[v].str[3].value.."\n") + file:write("\t\t"..df.global.world.raws.interactions[v].str[4].value.."\n") elseif k == "interaction" and event:getType() == df.history_event_type.HF_LEARNS_SECRET then - io.write ("\t\t"..""..df.global.world.raws.interactions[v].str[2].value.."".."\n") + file:write("\t\t"..df.global.world.raws.interactions[v].str[2].value.."\n") elseif event:getType() == df.history_event_type.HIST_FIGURE_DIED and k == "weapon" then for detailK,detailV in pairs(v) do if (detailK == "item") then if detailV > -1 then - io.write ("\t\t".."<"..detailK..">"..detailV.."".."\n") + file:write("\t\t<"..detailK..">"..detailV.."\n") local thisItem = df.item.find(detailV) if (thisItem ~= nil) then if (thisItem.flags.artifact == true) then for refk,refv in pairs(thisItem.general_refs) do if (refv:getType() == 1) then - io.write ("\t\t"..""..refv.artifact_id.."".."\n") + file:write("\t\t"..refv.artifact_id.."\n") break end end @@ -468,27 +470,27 @@ function export_more_legends_xml() end elseif (detailK == "item_type") then if event.weapon.item > -1 then - io.write ("\t\t".."<"..detailK..">"..tostring(df.item_type[detailV]):lower().."".."\n") + file:write("\t\t<"..detailK..">"..tostring(df.item_type[detailV]):lower().."\n") end elseif (detailK == "item_subtype") then if event.weapon.item > -1 and detailV > -1 then - io.write ("\t\t".."<"..detailK..">"..getItemSubTypeName(event.weapon.item_type,detailV).."".."\n") + file:write("\t\t<"..detailK..">"..getItemSubTypeName(event.weapon.item_type,detailV).."\n") end elseif (detailK == "mattype") then if (detailV > -1) then - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.weapon.mattype, event.weapon.matindex)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.weapon.mattype, event.weapon.matindex)).."\n") end elseif (detailK == "matindex") then elseif (detailK == "shooter_item") then if detailV > -1 then - io.write ("\t\t".."<"..detailK..">"..detailV.."".."\n") + file:write("\t\t<"..detailK..">"..detailV.."\n") local thisItem = df.item.find(detailV) if thisItem ~= nil then if (thisItem.flags.artifact == true) then for refk,refv in pairs(thisItem.general_refs) do if (refv:getType() == 1) then - io.write ("\t\t"..""..refv.artifact_id.."".."\n") + file:write("\t\t"..refv.artifact_id.."\n") break end end @@ -497,42 +499,42 @@ function export_more_legends_xml() end elseif (detailK == "shooter_item_type") then if event.weapon.shooter_item > -1 then - io.write ("\t\t".."<"..detailK..">"..tostring(df.item_type[detailV]):lower().."".."\n") + file:write("\t\t<"..detailK..">"..tostring(df.item_type[detailV]):lower().."\n") end elseif (detailK == "shooter_item_subtype") then if event.weapon.shooter_item > -1 and detailV > -1 then - io.write ("\t\t".."<"..detailK..">"..getItemSubTypeName(event.weapon.shooter_item_type,detailV).."".."\n") + file:write("\t\t<"..detailK..">"..getItemSubTypeName(event.weapon.shooter_item_type,detailV).."\n") end elseif (detailK == "shooter_mattype") then if (detailV > -1) then - io.write ("\t\t"..""..dfhack.matinfo.toString(dfhack.matinfo.decode(event.weapon.shooter_mattype, event.weapon.shooter_matindex)).."".."\n") + file:write("\t\t"..dfhack.matinfo.toString(dfhack.matinfo.decode(event.weapon.shooter_mattype, event.weapon.shooter_matindex)).."\n") end elseif (detailK == "shooter_matindex") then --skip elseif detailK == "slayer_race" or detailK == "slayer_caste" then --skip else - io.write ("\t\t".."<"..detailK..">"..detailV.."".."\n") + file:write("\t\t<"..detailK..">"..detailV.."\n") end end elseif event:getType() == df.history_event_type.HIST_FIGURE_DIED and k == "death_cause" then - io.write ("\t\t".."<"..k..">"..df.death_type[v]:lower().."".."\n") + file:write("\t\t<"..k..">"..df.death_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.CHANGE_HF_JOB and (k == "new_job" or k == "old_job") then - io.write ("\t\t".."<"..k..">"..df.profession[v]:lower().."".."\n") + file:write("\t\t<"..k..">"..df.profession[v]:lower().."\n") else - io.write ("\t\t".."<"..k..">"..tostring(v).."".."\n") + file:write("\t\t<"..k..">"..tostring(v).."\n") end end - io.write ("\t".."".."\n") + file:write("\t\n") end end - io.write ("".."\n") - io.write ("".."\n") - io.write ("".."\n") - io.write ("".."\n") - io.write ("".."\n") - io.write ("".."\n") - io.close() + file:write("\n") + file:write("\n") + file:write("\n") + file:write("\n") + file:write("\n") + file:write("\n") + file:close() end -- export information and XML ('p, x') From d775333c005c85210189af82368c260576b9994a Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Dec 2015 13:38:38 -0500 Subject: [PATCH 149/222] fix-unit-occupancy: Account for wagon occupancy correctly Previously, non-central wagon tiles would have their occupancy flag cleared. --- plugins/fix-unit-occupancy.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugins/fix-unit-occupancy.cpp b/plugins/fix-unit-occupancy.cpp index e83392512..8b7be0c0f 100644 --- a/plugins/fix-unit-occupancy.cpp +++ b/plugins/fix-unit-occupancy.cpp @@ -9,6 +9,7 @@ #include "modules/Translation.h" #include "modules/World.h" +#include "df/creature_raw.h" #include "df/map_block.h" #include "df/unit.h" #include "df/world.h" @@ -40,16 +41,6 @@ static std::string get_unit_description(df::unit *unit) return desc; } -df::unit *findUnit(int x, int y, int z) -{ - for (auto u = world->units.active.begin(); u != world->units.active.end(); ++u) - { - if ((**u).pos.x == x && (**u).pos.y == y && (**u).pos.z == z) - return *u; - } - return NULL; -} - struct uo_buf { uint32_t dim_x, dim_y, dim_z; size_t size; @@ -154,8 +145,21 @@ unsigned fix_unit_occupancy (color_ostream &out, uo_opts &opts) } } - for (auto u = world->units.active.begin(); u != world->units.active.end(); ++u) - uo_buffer.set((**u).pos.x, (**u).pos.y, (**u).pos.z, 0); + for (auto it = world->units.active.begin(); it != world->units.active.end(); ++it) + { + df::unit *u = *it; + if (!u || u->flags1.bits.caged || u->pos.x < 0) + continue; + df::creature_raw *craw = df::creature_raw::find(u->race); + int unit_extents = (craw && craw->flags.is_set(df::creature_raw_flags::EQUIPMENT_WAGON)) ? 1 : 0; + for (int16_t x = u->pos.x - unit_extents; x <= u->pos.x + unit_extents; ++x) + { + for (int16_t y = u->pos.y - unit_extents; y <= u->pos.y + unit_extents; ++y) + { + uo_buffer.set(x, y, u->pos.z, 0); + } + } + } for (size_t i = 0; i < uo_buffer.size; i++) { From 090787e9272efc3866b797e9b102a6b175672da4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Dec 2015 13:41:46 -0500 Subject: [PATCH 150/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 357197817..3b7d07599 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 357197817bf05677ff51287b3015e1621f4c0888 +Subproject commit 3b7d075992692c709730d34720b35598b5cb4710 From 31745f4a361d5300fd10a3387e4dd2e7f3da5abd Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Dec 2015 14:32:31 -0500 Subject: [PATCH 151/222] Fix a couple exportlegends issues and update xml --- library/xml | 2 +- scripts/exportlegends.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index 3b7d07599..bd5f8a901 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3b7d075992692c709730d34720b35598b5cb4710 +Subproject commit bd5f8a90178371f83ef6348eaa3e376aee5e7af3 diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 39b21e417..b8c37efde 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -211,8 +211,8 @@ function export_more_legends_xml() file:write("\t\t"..(df.global.world.raws.creatures.all[entityV.race].creature_id):lower().."\n") end file:write("\t\t"..(df.historical_entity_type[entityV.type]):lower().."\n") - if (df.historical_entity_type[entityV.type]):lower() == "religion" then -- Get worshipped figure - if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nill and + if entityV.type == df.historical_entity_type.Religion then -- Get worshipped figure + if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nil and #entityV.unknown1b.worship == 1) then file:write("\t\t"..entityV.unknown1b.worship[0].."\n") else From ef62c044a321361ba5fab3998c167ec826b807bf Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 10:30:02 -0500 Subject: [PATCH 152/222] Update NEWS, xml --- NEWS.rst | 2 +- library/xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index d43229487..f42a52d5a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -60,7 +60,7 @@ New Features Fixes ----- -- `exportlegends`: Handles entities without specific races +- `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42 - `showmood`: Fixed name display on OS X/Linux diff --git a/library/xml b/library/xml index bd5f8a901..9b14c4560 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bd5f8a90178371f83ef6348eaa3e376aee5e7af3 +Subproject commit 9b14c45604fcd1ba5851d91d122d75f86936000b From d0c28d3f50ba9178462681114dcaef74addc15b1 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 11:15:29 -0500 Subject: [PATCH 153/222] Prevent plugins with active viewscreens from being unloaded This requires plugins to pass plugin_self to Screen::show(), but avoids the need to implement special checks in plugin_onstatechange for the SC_BEGIN_UNLOAD event. --- NEWS.rst | 2 ++ library/PluginManager.cpp | 7 +++++++ library/include/modules/Screen.h | 6 +++++- library/modules/Screen.cpp | 26 +++++++++++++++++++++++++- plugins/autochop.cpp | 4 ++-- plugins/buildingplan.cpp | 2 +- plugins/command-prompt.cpp | 4 +--- plugins/dwarfmonitor.cpp | 8 ++++---- plugins/embark-tools.cpp | 16 ++++------------ plugins/hotkeys.cpp | 2 +- plugins/manipulator.cpp | 10 +++++----- plugins/stocks.cpp | 12 ++++-------- 12 files changed, 61 insertions(+), 38 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index f42a52d5a..17ea64e38 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -41,6 +41,8 @@ Internals ./dfhack +devel/print-args example "Dwarf Fortress.exe" +devel/print-args example +- Prevented plugins with active viewscreens from being unloaded and causing a crash + New Scripts ----------- - `devel/save-version`: Displays DF version information about the current save diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index 2dad07797..9711e2e4d 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -24,6 +24,7 @@ distribution. #include "modules/EventManager.h" #include "modules/Filesystem.h" +#include "modules/Screen.h" #include "Internal.h" #include "Core.h" #include "MemAccess.h" @@ -385,6 +386,12 @@ bool Plugin::unload(color_ostream &con) // if we are actually loaded if(state == PS_LOADED) { + if (Screen::hasActiveScreens(this)) + { + con.printerr("Cannot unload plugin %s: has active viewscreens\n", name.c_str()); + access->unlock(); + return false; + } EventManager::unregisterAll(this); // notify the plugin about an attempt to shutdown if (plugin_onstatechange && diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 37dc9808c..2c4a29062 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -54,6 +54,7 @@ namespace df namespace DFHack { class Core; + class Plugin; typedef std::set interface_key_set; @@ -208,9 +209,12 @@ namespace DFHack DFHACK_EXPORT bool findGraphicsTile(const std::string &page, int x, int y, int *ptile, int *pgs = NULL); // Push and remove viewscreens - DFHACK_EXPORT bool show(df::viewscreen *screen, df::viewscreen *before = NULL); + DFHACK_EXPORT bool show(df::viewscreen *screen, df::viewscreen *before = NULL, Plugin *p = NULL); + inline bool show(df::viewscreen *screen, Plugin *p) + { return show(screen, NULL, p); } DFHACK_EXPORT void dismiss(df::viewscreen *screen, bool to_first = false); DFHACK_EXPORT bool isDismissed(df::viewscreen *screen); + DFHACK_EXPORT bool hasActiveScreens(Plugin *p); /// Retrieve the string representation of the bound key. DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key); diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 0f79e1a46..71103ffda 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -282,7 +282,9 @@ bool Screen::findGraphicsTile(const std::string &pagename, int x, int y, int *pt return false; } -bool Screen::show(df::viewscreen *screen, df::viewscreen *before) +static std::map plugin_screens; + +bool Screen::show(df::viewscreen *screen, df::viewscreen *before, Plugin *plugin) { CHECK_NULL_POINTER(screen); CHECK_INVALID_ARGUMENT(!screen->parent && !screen->child); @@ -306,6 +308,9 @@ bool Screen::show(df::viewscreen *screen, df::viewscreen *before) if (dfhack_viewscreen::is_instance(screen)) static_cast(screen)->onShow(); + if (plugin) + plugin_screens[screen] = plugin; + return true; } @@ -313,6 +318,10 @@ void Screen::dismiss(df::viewscreen *screen, bool to_first) { CHECK_NULL_POINTER(screen); + auto it = plugin_screens.find(screen); + if (it != plugin_screens.end()) + plugin_screens.erase(it); + if (screen->breakdown_level != interface_breakdown_types::NONE) return; @@ -332,6 +341,21 @@ bool Screen::isDismissed(df::viewscreen *screen) return screen->breakdown_level != interface_breakdown_types::NONE; } +bool Screen::hasActiveScreens(Plugin *plugin) +{ + if (plugin_screens.empty()) + return false; + df::viewscreen *screen = &gview->view; + while (screen) + { + auto it = plugin_screens.find(screen); + if (it != plugin_screens.end() && it->second == plugin) + return true; + screen = screen->child; + } + return false; +} + #ifdef _LINUX // Link to the libgraphics class directly: class DFHACK_EXPORT enabler_inputst { diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index f7ba3d300..cbb5db0b3 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -600,7 +600,7 @@ struct autochop_hook : public df::viewscreen_dwarfmodest if (isInDesignationMenu() && input->count(interface_key::CUSTOM_C)) { sendKey(interface_key::LEAVESCREEN); - Screen::show(new ViewscreenAutochop()); + Screen::show(new ViewscreenAutochop(), plugin_self); } else { @@ -643,7 +643,7 @@ command_result df_autochop (color_ostream &out, vector & parameters) return CR_WRONG_USAGE; } if (Maps::IsValid()) - Screen::show(new ViewscreenAutochop()); + Screen::show(new ViewscreenAutochop(), plugin_self); return CR_OK; } diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index ddc804897..6f833ba6d 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -161,7 +161,7 @@ struct buildingplan_hook : public df::viewscreen_dwarfmodest } else if (input->count(interface_key::CUSTOM_SHIFT_M)) { - Screen::show(new ViewscreenChooseMaterial(planner.getDefaultItemFilterForType(type))); + Screen::show(new ViewscreenChooseMaterial(planner.getDefaultItemFilterForType(type)), plugin_self); } else if (input->count(interface_key::CUSTOM_SHIFT_Q)) { diff --git a/plugins/command-prompt.cpp b/plugins/command-prompt.cpp index dd3b59398..042d5f642 100644 --- a/plugins/command-prompt.cpp +++ b/plugins/command-prompt.cpp @@ -318,7 +318,7 @@ command_result show_prompt(color_ostream &out, std::vector & param std::string params; for(size_t i=0;icount(interface_key::CUSTOM_SHIFT_Z)) { @@ -1665,7 +1665,7 @@ private: static void open_stats_srceen() { - Screen::show(new ViewscreenFortStats()); + Screen::show(new ViewscreenFortStats(), plugin_self); } static void add_work_history(df::unit *unit, activity_type type) @@ -1915,12 +1915,12 @@ static command_result dwarfmonitor_cmd(color_ostream &out, vector & par else if (cmd == 's' || cmd == 'S') { if(Maps::IsValid()) - Screen::show(new ViewscreenFortStats()); + Screen::show(new ViewscreenFortStats(), plugin_self); } else if (cmd == 'p' || cmd == 'P') { if(Maps::IsValid()) - Screen::show(new ViewscreenPreferences()); + Screen::show(new ViewscreenPreferences(), plugin_self); } else if (cmd == 'r' || cmd == 'R') { diff --git a/plugins/embark-tools.cpp b/plugins/embark-tools.cpp index 7fa9cafca..d2bdf4909 100644 --- a/plugins/embark-tools.cpp +++ b/plugins/embark-tools.cpp @@ -21,6 +21,9 @@ using namespace DFHack; using df::global::enabler; using df::global::gps; +DFHACK_PLUGIN("embark-tools"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + #define FOR_ITER_TOOLS(iter) for(auto iter = tools.begin(); iter != tools.end(); iter++) void update_embark_sidebar (df::viewscreen_choose_start_sitest * screen) @@ -684,7 +687,7 @@ struct choose_start_site_hook : df::viewscreen_choose_start_sitest void display_settings() { - Screen::show(new embark_tools_settings); + Screen::show(new embark_tools_settings, plugin_self); } inline bool is_valid_page() @@ -734,9 +737,6 @@ struct choose_start_site_hook : df::viewscreen_choose_start_sitest IMPLEMENT_VMETHOD_INTERPOSE(choose_start_site_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(choose_start_site_hook, render); -DFHACK_PLUGIN("embark-tools"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - command_result embark_tools_cmd (color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) @@ -783,14 +783,6 @@ DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) DFhackCExport command_result plugin_onstatechange (color_ostream &out, state_change_event evt) { - if (evt == SC_BEGIN_UNLOAD) - { - if (Gui::getCurFocus() == "dfhack/embark-tools/options") - { - out.printerr("Settings screen active.\n"); - return CR_FAILURE; - } - } return CR_OK; } diff --git a/plugins/hotkeys.cpp b/plugins/hotkeys.cpp index 45ca07cbd..d7139dd96 100644 --- a/plugins/hotkeys.cpp +++ b/plugins/hotkeys.cpp @@ -319,7 +319,7 @@ static command_result hotkeys_cmd(color_ostream &out, vector & paramete if (Gui::getFocusString(top_screen) != "dfhack/viewscreen_hotkeys") { find_active_keybindings(top_screen); - Screen::show(new ViewscreenHotkeys(top_screen)); + Screen::show(new ViewscreenHotkeys(top_screen), plugin_self); } } } diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index a3f0f8ef8..e2a4e54a0 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -1773,14 +1773,14 @@ void viewscreen_unitlaborsst::feed(set *events) if (events->count(interface_key::CUSTOM_B)) { - Screen::show(new viewscreen_unitbatchopst(units, true, &do_refresh_names)); + Screen::show(new viewscreen_unitbatchopst(units, true, &do_refresh_names), plugin_self); } if (events->count(interface_key::CUSTOM_E)) { vector tmp; tmp.push_back(cur); - Screen::show(new viewscreen_unitbatchopst(tmp, false, &do_refresh_names)); + Screen::show(new viewscreen_unitbatchopst(tmp, false, &do_refresh_names), plugin_self); } if (events->count(interface_key::CUSTOM_P)) @@ -1791,11 +1791,11 @@ void viewscreen_unitlaborsst::feed(set *events) has_selected = true; if (has_selected) { - Screen::show(new viewscreen_unitprofessionset(units, true)); + Screen::show(new viewscreen_unitprofessionset(units, true), plugin_self); } else { vector tmp; tmp.push_back(cur); - Screen::show(new viewscreen_unitprofessionset(tmp, false)); + Screen::show(new viewscreen_unitprofessionset(tmp, false), plugin_self); } } @@ -2144,7 +2144,7 @@ struct unitlist_hook : df::viewscreen_unitlistst { if (units[page].size()) { - Screen::show(new viewscreen_unitlaborsst(units[page], cursor_pos[page])); + Screen::show(new viewscreen_unitlaborsst(units[page], cursor_pos[page]), plugin_self); return; } } diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 85fedb9f2..8565c703f 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -771,7 +771,7 @@ public: } else if (input->count(interface_key::HELP)) { - Screen::show(new search_help); + Screen::show(new search_help, plugin_self); } bool key_processed = false; @@ -1425,7 +1425,7 @@ struct stocks_hook : public df::viewscreen_storesst if (input->count(interface_key::CUSTOM_E)) { Screen::dismiss(this); - Screen::show(new ViewscreenStocks()); + Screen::show(new ViewscreenStocks(), plugin_self); return; } INTERPOSE_NEXT(feed)(input); @@ -1457,7 +1457,7 @@ struct stocks_stockpile_hook : public df::viewscreen_dwarfmodest if (input->count(interface_key::CUSTOM_I)) { - Screen::show(new ViewscreenStocks(sp)); + Screen::show(new ViewscreenStocks(sp), plugin_self); return true; } @@ -1531,7 +1531,7 @@ static command_result stocks_cmd(color_ostream &out, vector & parameter } else if (toLower(parameters[0])[0] == 's') { - Screen::show(new ViewscreenStocks()); + Screen::show(new ViewscreenStocks(), plugin_self); return CR_OK; } } @@ -1557,10 +1557,6 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan case SC_MAP_LOADED: ViewscreenStocks::reset(); break; - case SC_BEGIN_UNLOAD: - if (Gui::getCurFocus().find("dfhack/stocks") == 0) - return CR_FAILURE; - break; default: break; } From 93fe222c352136cab2e549b0876f3dc409cb1aa5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 11:20:54 -0500 Subject: [PATCH 154/222] Revert #719 No plugins built prior to the symbol naming change in 4fc6cb6f can be loaded in DFHack for v0.42. --- library/PluginManager.cpp | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index 9711e2e4d..774d19143 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -273,23 +273,13 @@ bool Plugin::load(color_ostream &con) plugin_abort_load; \ return false; \ } - #define plugin_check_symbols(sym1,sym2) \ - if (!LookupPlugin(plug, sym1) && !LookupPlugin(plug, sym2)) \ - { \ - con.printerr("Plugin %s: missing symbols: %s & %s\n", name.c_str(), sym1, sym2); \ - plugin_abort_load; \ - return false; \ - } - plugin_check_symbols("plugin_name", "name") // allow r3 plugins - plugin_check_symbols("plugin_version", "version") // allow r3 plugins + plugin_check_symbol("plugin_name") + plugin_check_symbol("plugin_version") plugin_check_symbol("plugin_self") plugin_check_symbol("plugin_init") plugin_check_symbol("plugin_globals") const char ** plug_name =(const char ** ) LookupPlugin(plug, "plugin_name"); - if (!plug_name) // allow r3 plugin naming - plug_name = (const char ** )LookupPlugin(plug, "name"); - if (name != *plug_name) { con.printerr("Plugin %s: name mismatch, claims to be %s\n", name.c_str(), *plug_name); @@ -297,9 +287,6 @@ bool Plugin::load(color_ostream &con) return false; } const char ** plug_version =(const char ** ) LookupPlugin(plug, "plugin_version"); - if (!plug_version) // allow r3 plugin version - plug_version =(const char ** ) LookupPlugin(plug, "version"); - const char ** plug_git_desc_ptr = (const char**) LookupPlugin(plug, "plugin_git_description"); Plugin **plug_self = (Plugin**)LookupPlugin(plug, "plugin_self"); const char *dfhack_version = Version::dfhack_version(); From d92363368968e3ac6dcede3b10ea9ddc9ceef8af Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 11:34:52 -0500 Subject: [PATCH 155/222] Add moversti, TheBloke, txtsd to Authors.rst --- docs/Authors.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 13ef59721..0b2066076 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -58,6 +58,7 @@ Mike Stewart thewonderidiot Mikko Juola Noeda Adeon MithrilTuxedo MithrilTuxedo mizipzor mizipzor +moversti moversti Neil Little nmlittle Nick Rart nickrart comestible Omniclasm @@ -91,7 +92,9 @@ Simon Jackson sizeak Tacomagic Tim Walberg twalberg Timothy Collett danaris +Tom Jobbins TheBloke Tom Prince +txtsd txtsd U-glouglou\\simon Valentin Ochs Cat-Ion Vjek From 81b055ee936d2abb0a51b29266ec4d41ebb1a4c2 Mon Sep 17 00:00:00 2001 From: PeridexisErrant Date: Fri, 4 Dec 2015 15:48:15 +0930 Subject: [PATCH 156/222] Implement "weather" as a script --- NEWS.rst | 4 ++ docs/Plugins.rst | 5 -- plugins/CMakeLists.txt | 1 - plugins/weather.cpp | 147 ----------------------------------------- scripts/weather.lua | 35 ++++++++++ 5 files changed, 39 insertions(+), 153 deletions(-) delete mode 100644 plugins/weather.cpp create mode 100644 scripts/weather.lua diff --git a/NEWS.rst b/NEWS.rst index 17ea64e38..a30f91c1a 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -65,6 +65,10 @@ Fixes - `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42 - `showmood`: Fixed name display on OS X/Linux +Misc Improvements +----------------- +- `weather`: now implemented by a script + DFHack 0.40.24-r5 ================= diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 952813180..c50001dbd 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2105,11 +2105,6 @@ Options: Beware that filling in hollow veins will trigger a demon invasion on top of your miner when you dig into the region that used to be hollow. -weather -======= -Prints the current weather, and lets you change the weather to 'clear', 'rain' -or 'snow', with those words as commands (eg ``weather rain``). - ================= diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 78e13b157..9781401ff 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -167,7 +167,6 @@ if (BUILD_SUPPORTED) # DFHACK_PLUGIN(treefarm treefarm.cpp) DFHACK_PLUGIN(tubefill tubefill.cpp) add_subdirectory(tweak) - DFHACK_PLUGIN(weather weather.cpp) DFHACK_PLUGIN(workflow workflow.cpp LINK_LIBRARIES lua) DFHACK_PLUGIN(workNow workNow.cpp) DFHACK_PLUGIN(zone zone.cpp LINK_LIBRARIES lua) diff --git a/plugins/weather.cpp b/plugins/weather.cpp deleted file mode 100644 index 481c1a779..000000000 --- a/plugins/weather.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" -#include -#include -#include "modules/World.h" -#include "DataDefs.h" -#include "df/weather_type.h" - -using std::vector; -using std::string; -using namespace DFHack; -using namespace df::enums; - -DFHACK_PLUGIN("weather"); - -REQUIRE_GLOBAL(current_weather); - -bool locked = false; -unsigned char locked_data[25]; - -command_result weather (color_ostream &out, vector & parameters); - -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand( - "weather", "Print the weather map or change weather.", - weather, false, - " Prints the current weather map by default.\n" - "Options:\n" - " snow - make it snow everywhere.\n" - " rain - make it rain.\n" - " clear - clear the sky.\n" - )); - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - return CR_OK; -} - -command_result weather (color_ostream &con, vector & parameters) -{ - int val_override = -1; - bool lock = false; - bool unlock = false; - bool snow = false; - bool rain = false; - bool clear = false; - for(size_t i = 0; i < parameters.size();i++) - { - if(parameters[i] == "rain") - rain = true; - else if(parameters[i] == "snow") - snow = true; - else if(parameters[i] == "clear") - clear = true; - else if(parameters[i] == "lock") - lock = true; - else if(parameters[i] == "unlock") - unlock = true; - else - { - val_override = atoi(parameters[i].c_str()); - if(val_override == 0) - return CR_WRONG_USAGE; - } - } - if(lock && unlock) - { - con << "Lock or unlock? DECIDE!" << std::endl; - return CR_FAILURE; - } - int cnt = 0; - cnt += rain; - cnt += snow; - cnt += clear; - if(cnt > 1) - { - con << "Rain, snow or clear sky? DECIDE!" << std::endl; - return CR_FAILURE; - } - bool something = lock || unlock || rain || snow || clear || val_override != -1; - - CoreSuspender suspend; - - if(!current_weather) - { - con << "Weather support seems broken :(" << std::endl; - return CR_FAILURE; - } - if(!something) - { - // paint weather map - con << "Weather map (C = clear, R = rain, S = snow):" << std::endl; - for(int y = 0; y<5;y++) - { - for(int x = 0; x<5;x++) - { - switch((*current_weather)[x][y]) - { - case weather_type::None: - con << "C "; - break; - case weather_type::Rain: - con << "R "; - break; - case weather_type::Snow: - con << "S "; - break; - default: - con << (int) (*current_weather)[x][y] << " "; - break; - } - } - con << std::endl; - } - } - else - { - // weather changing action! - if(rain) - { - con << "Here comes the rain." << std::endl; - World::SetCurrentWeather(weather_type::Rain); - } - if(snow) - { - con << "Snow everywhere!" << std::endl; - World::SetCurrentWeather(weather_type::Snow); - } - if(clear) - { - con << "Suddenly, sunny weather!" << std::endl; - World::SetCurrentWeather(weather_type::None); - } - if(val_override != -1) - { - con << "I have no damn idea what this is... " << val_override << std::endl; - World::SetCurrentWeather(val_override); - } - // FIXME: weather lock needs map ID to work reliably... needs to be implemented. - } - return CR_OK; -} diff --git a/scripts/weather.lua b/scripts/weather.lua new file mode 100644 index 000000000..2cbb05fa8 --- /dev/null +++ b/scripts/weather.lua @@ -0,0 +1,35 @@ +-- Print the weather map or change weather. +local helpstr = [[=begin + +weather +======= +Prints a map of the local weather, or with arguments ``clear``, +``rain``, and ``snow`` changes the weather. + +=end]] + +local args = {...} +if args[1] == "help" or args[1] == "?" then + print("The current weather is "..df.weather_type[dfhack.world.ReadCurrentWeather()]) + print((helpstr:gsub('=[a-z]+', ''))) +elseif args[1] == "clear" then + dfhack.world.SetCurrentWeather(df.weather_type["None"]) + print("The weather has cleared.") +elseif args[1] == "rain" then + dfhack.world.SetCurrentWeather(df.weather_type["Rain"]) + print("It is now raining.") +elseif args[1] == "snow" then + dfhack.world.SetCurrentWeather(df.weather_type["Snow"]) + print("It is now snowing.") +else + -- df.global.current_weather is arranged in columns, not rows + kind = {[0]="C ", "R ", "S "} + print("Weather map (C = clear, R = rain, S = snow):") + for y=0, 4 do + s = "" + for x=0, 4 do + s = s..kind[df.global.current_weather[x][y]] + end + print(s) + end +end From 51690b4ba264fa5e44642c5912728a38e0131949 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 11:46:40 -0500 Subject: [PATCH 157/222] weather: re-add val_override, minor cleanup --- scripts/weather.lua | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/weather.lua b/scripts/weather.lua index 2cbb05fa8..a61ab48bd 100644 --- a/scripts/weather.lua +++ b/scripts/weather.lua @@ -9,26 +9,37 @@ Prints a map of the local weather, or with arguments ``clear``, =end]] local args = {...} -if args[1] == "help" or args[1] == "?" then +local cmd +local val_override = tonumber(args[1]) +if args[1] then + cmd = args[1]:sub(1, 1) +end +if cmd == "h" or cmd == "?" then print("The current weather is "..df.weather_type[dfhack.world.ReadCurrentWeather()]) print((helpstr:gsub('=[a-z]+', ''))) -elseif args[1] == "clear" then - dfhack.world.SetCurrentWeather(df.weather_type["None"]) +elseif cmd == "c" then + dfhack.world.SetCurrentWeather(df.weather_type.None) print("The weather has cleared.") -elseif args[1] == "rain" then - dfhack.world.SetCurrentWeather(df.weather_type["Rain"]) +elseif cmd == "r" then + dfhack.world.SetCurrentWeather(df.weather_type.Rain) print("It is now raining.") -elseif args[1] == "snow" then - dfhack.world.SetCurrentWeather(df.weather_type["Snow"]) +elseif cmd == "s" then + dfhack.world.SetCurrentWeather(df.weather_type.Snow) print("It is now snowing.") +elseif val_override then + dfhack.world.SetCurrentWeather(val_override) + print("Set weather to " .. val_override) +elseif args[1] then + qerror("Unrecognized argument: " .. args[1]) else -- df.global.current_weather is arranged in columns, not rows - kind = {[0]="C ", "R ", "S "} + kind = {[0]="C", "R", "S"} print("Weather map (C = clear, R = rain, S = snow):") for y=0, 4 do s = "" for x=0, 4 do - s = s..kind[df.global.current_weather[x][y]] + local cur = df.global.current_weather[x][y] + s = s .. (kind[cur] or cur) .. ' ' end print(s) end From 9e020bb8c11e3088ba0f923e07516f232771dac9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 11:50:11 -0500 Subject: [PATCH 158/222] Make title-version show git info for dev builds --- plugins/title-version.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/title-version.cpp b/plugins/title-version.cpp index c62568f1e..78a694211 100644 --- a/plugins/title-version.cpp +++ b/plugins/title-version.cpp @@ -34,7 +34,12 @@ struct title_version_hook : df::viewscreen_titlest { int x = 0, y = 0; OutputString(COLOR_WHITE, x, y, string("DFHack ") + DFHACK_VERSION); if (!DFHACK_IS_RELEASE) + { OutputString(COLOR_WHITE, x, y, " (dev)"); + x = 0; y = 1; + OutputString(COLOR_WHITE, x, y, "Git: "); + OutputString(COLOR_WHITE, x, y, DFHACK_GIT_DESCRIPTION); + } } }; From 45ba3c0c68522bd218b850eb29d4b4a523048eaf Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 1 Jan 2016 20:01:24 -0500 Subject: [PATCH 159/222] Try specifying ZLIB_ROOT --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a20b8dba..193339077 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ endif() if(NOT UNIX) SET(ZLIB_ROOT depends/zlib/) endif() +set(ZLIB_ROOT /usr/lib/i386-linux-gnu) find_package(ZLIB REQUIRED) include_directories(depends/protobuf) include_directories(depends/lua/include) From 06b3b94e8de1ccf3e3c99809da55fd7f98460557 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 2 Jan 2016 17:06:30 -0500 Subject: [PATCH 160/222] Tweak prerelease warning - low risk of save corruption at this point --- scripts/gui/prerelease-warning.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua index 8f99e450d..7eb6094c3 100644 --- a/scripts/gui/prerelease-warning.lua +++ b/scripts/gui/prerelease-warning.lua @@ -20,7 +20,7 @@ local utils = require 'utils' message = { 'This is a prerelease build of DFHack. Some structures are likely', NEWLINE, 'to be incorrect, resulting in crashes or save corruption', NEWLINE, - {pen=COLOR_LIGHTRED, text='Make backups of your saves and avoid saving if possible.'}, + {pen=COLOR_LIGHTRED, text='Make backups of your saves often!'}, } pack_message = pack_message or [[ From 2acdede03bde2f486479099787d7a4a09b7f3c00 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 19:29:30 -0500 Subject: [PATCH 161/222] New tweak: hide-priority Adds an option to hide designation priority indicators --- NEWS.rst | 1 + dfhack.init-example | 2 + docs/Plugins.rst | 1 + plugins/tweak/tweak.cpp | 6 +++ plugins/tweak/tweaks/hide-priority.h | 61 ++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+) create mode 100644 plugins/tweak/tweaks/hide-priority.h diff --git a/NEWS.rst b/NEWS.rst index a30f91c1a..b1c214f57 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -58,6 +58,7 @@ New Features - `tweak`: + - ``tweak hide-priority``: Adds an option to hide designation priority indicators - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu Fixes diff --git a/dfhack.init-example b/dfhack.init-example index 080bb1488..d1a28e169 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -181,10 +181,12 @@ tweak import-priority-category # Misc. UI tweaks tweak civ-view-agreement tweak fps-min +tweak hide-priority tweak kitchen-keys tweak kitchen-prefs-empty tweak max-wheelbarrow tweak shift-8-scroll +tweak title-start-rename tweak tradereq-pet-gender ########################### diff --git a/docs/Plugins.rst b/docs/Plugins.rst index c50001dbd..ef6a004ad 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -294,6 +294,7 @@ Subcommands that persist until disabled or DF quits: :fast-trade: Makes Shift-Down in the Move Goods to Depot and Trade screens select the current item (fully, in case of a stack), and scroll down one line. :fps-min: Fixes the in-game minimum FPS setting +:hide-priority: Adds an option to hide designation priority indicators :import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index 6b7f11603..df472e84d 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -87,6 +87,7 @@ #include "tweaks/fast-heat.h" #include "tweaks/fast-trade.h" #include "tweaks/fps-min.h" +#include "tweaks/hide-priority.h" #include "tweaks/import-priority-category.h" #include "tweaks/kitchen-keys.h" #include "tweaks/kitchen-prefs-color.h" @@ -195,6 +196,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector main.mode) + { + case df::ui_sidebar_mode::DesignateMine: + case df::ui_sidebar_mode::DesignateRemoveRamps: + case df::ui_sidebar_mode::DesignateUpStair: + case df::ui_sidebar_mode::DesignateDownStair: + case df::ui_sidebar_mode::DesignateUpDownStair: + case df::ui_sidebar_mode::DesignateUpRamp: + case df::ui_sidebar_mode::DesignateChannel: + case df::ui_sidebar_mode::DesignateGatherPlants: + case df::ui_sidebar_mode::DesignateRemoveDesignation: + case df::ui_sidebar_mode::DesignateSmooth: + case df::ui_sidebar_mode::DesignateCarveTrack: + case df::ui_sidebar_mode::DesignateEngrave: + case df::ui_sidebar_mode::DesignateCarveFortification: + case df::ui_sidebar_mode::DesignateChopTrees: + case df::ui_sidebar_mode::DesignateToggleEngravings: + case df::ui_sidebar_mode::DesignateToggleMarker: + case df::ui_sidebar_mode::DesignateRemoveConstruction: + return true; + default: + return false; + } + } + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + if (valid_mode()) + { + auto dims = Gui::getDwarfmodeViewDims(); + if (dims.menu_on) + { + int x = dims.menu_x1 + 1, y = gps->dimy - (gps->dimy > 26 ? 8 : 7); + OutputToggleString(x, y, "Show priorities", df::interface_key::CUSTOM_ALT_P, + ui_sidebar_menus->designation.priority_set, true, 0, + COLOR_WHITE, COLOR_LIGHTRED); + } + } + } + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { + if (valid_mode() && input->count(df::interface_key::CUSTOM_ALT_P)) + ui_sidebar_menus->designation.priority_set = !ui_sidebar_menus->designation.priority_set; + else + INTERPOSE_NEXT(feed)(input); + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(hide_priority_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(hide_priority_hook, render); From bdd4b11e2d1ee67ea4439c1e7208d8c73845f27c Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 19:30:10 -0500 Subject: [PATCH 162/222] Add an option to scan for all "standing_orders_*" globals --- scripts/devel/find-offsets.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index 368e8ac98..a2b5a55df 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -1623,6 +1623,9 @@ local function exec_finder_so(gname, seq, _depends) end depends[k] = v end + if force_scan['standing_orders'] then + force_scan[gname] = true + end exec_finder(function() return find_standing_orders(gname, seq, depends) end, gname) From 3bcd58fca7181a4293b96b08f695f1065b1d48a4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 19:31:57 -0500 Subject: [PATCH 163/222] Use consistent key display --- plugins/mousequery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mousequery.cpp b/plugins/mousequery.cpp index 3731d96c0..2da47d8cd 100644 --- a/plugins/mousequery.cpp +++ b/plugins/mousequery.cpp @@ -582,7 +582,7 @@ struct mousequery_hook : public df::viewscreen_dwarfmodest { int x = left_margin; int y = gps->dimy - 2; - OutputToggleString(x, y, "Box Select", "Alt+M", box_designation_enabled, + OutputToggleString(x, y, "Box Select", interface_key::CUSTOM_ALT_M, box_designation_enabled, true, left_margin, COLOR_WHITE, COLOR_LIGHTRED); } From aa435a14d70c7c6656976a6e39fbc66d8fe35ea4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 19:55:12 -0500 Subject: [PATCH 164/222] find-offsets: Look up colors from colors.txt if possible --- scripts/devel/find-offsets.lua | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index a2b5a55df..00cd4e076 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -465,6 +465,22 @@ end -- enabler -- +local function lookup_colors() + local f = io.open('data/init/colors.txt', 'r') or error('failed to open file') + local text = f:read('*all') + f:close() + local colors = {} + for _, color in pairs({'BLACK', 'BLUE', 'GREEN', 'CYAN', 'RED', 'MAGENTA', + 'BROWN', 'LGRAY', 'DGRAY', 'LBLUE', 'LGREEN', 'LCYAN', 'LRED', + 'LMAGENTA', 'YELLOW', 'WHITE'}) do + for _, part in pairs({'R', 'G', 'B'}) do + local opt = color .. '_' .. part + table.insert(colors, tonumber(text:match(opt .. ':(%d+)') or error('missing from colors.txt: ' .. opt))) + end + end + return colors +end + local function is_valid_enabler(e) if not ms.is_valid_vector(e.textures.raws, 4) or not ms.is_valid_vector(e.text_system, 4) @@ -478,7 +494,7 @@ end local function find_enabler() -- Data from data/init/colors.txt - local colors = { + local default_colors = { 0, 0, 0, 0, 0, 128, 0, 128, 0, 0, 128, 128, 128, 0, 0, 128, 0, 128, 128, 128, 0, 192, 192, 192, 128, 128, 128, @@ -486,10 +502,21 @@ local function find_enabler() 255, 0, 0, 255, 0, 255, 255, 255, 0, 255, 255, 255 } + local colors + local ok, ret = pcall(lookup_colors) + if not ok then + dfhack.printerr('Failed to look up colors, using defaults: \n' .. ret) + colors = default_colors + else + colors = ret + end for i = 1,#colors do colors[i] = colors[i]/255 end local idx, addr = data.float:find_one(colors) + if not idx then + idx, addr = data.float:find_one(default_colors) + end if idx then validate_offset('enabler', is_valid_enabler, addr, df.enabler, 'ccolor') return From 9ae55177ef12b940a5e0b52446e89c27fecd8ce4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 20:05:45 -0500 Subject: [PATCH 165/222] Stop feed_menu_choice exit sequence from triggering after restarting scan --- scripts/devel/find-offsets.lua | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index 00cd4e076..ce475e8f1 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -260,17 +260,14 @@ local function dwarfmode_to_top() end local function feed_menu_choice(catnames,catkeys,enum,enter_seq,exit_seq,prompt) - local entered = false return function (idx) if idx == 0 and prompt and not utils.prompt_yes_no(' Proceed?', true) then return false end - idx = idx % #catnames + 1 - if not entered then - entered = true - else + if idx > 0 then dwarfmode_feed_input(table.unpack(exit_seq or {})) end + idx = idx % #catnames + 1 dwarfmode_feed_input(table.unpack(enter_seq or {})) dwarfmode_feed_input(catkeys[idx]) if enum then From 7eb442e98c88e019a8aa41156122875f1ddc01ac Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 4 Jan 2016 20:09:05 -0500 Subject: [PATCH 166/222] Feed D_ORDERS instead of relying on sidebar mode enum --- scripts/devel/find-offsets.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/devel/find-offsets.lua b/scripts/devel/find-offsets.lua index ce475e8f1..89cb0918a 100644 --- a/scripts/devel/find-offsets.lua +++ b/scripts/devel/find-offsets.lua @@ -1626,7 +1626,7 @@ local function find_standing_orders(gname, seq, depends) 'Auto-searching for ' .. gname, 'uint8_t', function(idx) - df.global.ui.main.mode = df.ui_sidebar_mode.Orders + dwarfmode_feed_input('D_ORDERS') dwarfmode_feed_input(table.unpack(seq)) return true end From da3c6404fa026e776d4a495fe585161947d0ee4d Mon Sep 17 00:00:00 2001 From: Nikolay Amiantov Date: Wed, 6 Jan 2016 03:03:19 +0300 Subject: [PATCH 167/222] blueprint: fix compilation (i.e. undefined find) --- plugins/blueprint.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index b9047a14e..badc094c9 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -2,6 +2,8 @@ //By cdombroski //Translates a region of tiles specified by the cursor and arguments/prompts into a series of blueprint files suitable for digfort/buildingplan/quickfort +#include + #include #include From 97fb50c28f8a7a65ee1b3b70d7a1d5a7411261f3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 6 Jan 2016 17:30:07 -0500 Subject: [PATCH 168/222] Add better support for default ListColumn values This is only necessary for multiple-selection columns, and there aren't any with non-pointer entry types currently, but casting nullptr to non-pointer types isn't a great idea. --- plugins/listcolumn.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/listcolumn.h b/plugins/listcolumn.h index 0576ca4e4..5c96b4594 100644 --- a/plugins/listcolumn.h +++ b/plugins/listcolumn.h @@ -35,8 +35,9 @@ public: bool allow_search; bool feed_mouse_set_highlight; bool feed_changed_highlight; + T default_value; - ListColumn() + ListColumn(const T default_value_ = T()) { bottom_margin = 3; clear(); @@ -50,6 +51,7 @@ public: allow_search = true; feed_mouse_set_highlight = false; feed_changed_highlight = false; + default_value = default_value_; } void clear() @@ -310,7 +312,7 @@ public: { vector results = getSelectedElems(true); if (results.size() == 0) - return (T)nullptr; + return default_value; else return results[0]; } From 203b9aca2a6c76cc552b9e32abb2459053ed21e0 Mon Sep 17 00:00:00 2001 From: Jim Lisi Date: Fri, 8 Jan 2016 14:53:33 -0500 Subject: [PATCH 169/222] autolabor-artisans.lua remove brewer skill alcohol has no quality level, so brewer skill has no effect on output quality --- scripts/autolabor-artisans.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/autolabor-artisans.lua b/scripts/autolabor-artisans.lua index 22d394646..68b85817c 100644 --- a/scripts/autolabor-artisans.lua +++ b/scripts/autolabor-artisans.lua @@ -14,7 +14,6 @@ local artisan_labors = { "ARCHITECT", "ANIMALTRAIN", "LEATHER", - "BREWER", "WEAVER", "CLOTHESMAKER", "COOK", From 974b427833e033b1ad012ed892c7d0a0ab63bbb0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 8 Jan 2016 17:01:22 -0500 Subject: [PATCH 170/222] Add stonetoad to Authors.rst --- docs/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Authors.rst b/docs/Authors.rst index 0b2066076..92ed1a9d4 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -37,6 +37,7 @@ IndigoFenix James Logsdon jlogsdon Japa JapaMala Jared Adams +Jim Lisi stonetoad jj jjyg jj`` John Beisley huin John Shade gsvslto From d670ee8ab4de69c2ba57aec703b7735d0ed3d407 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 8 Jan 2016 19:27:11 -0500 Subject: [PATCH 171/222] New tweak: block-labors Prevents labors that can't be used from being toggled Suggested at http://www.bay12forums.com/smf/index.php?topic=121451.msg6719464#msg6719464 --- NEWS.rst | 1 + dfhack.init-example | 1 + docs/Plugins.rst | 1 + library/xml | 2 +- plugins/tweak/tweak.cpp | 8 +++ plugins/tweak/tweaks/block-labors.h | 104 ++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 plugins/tweak/tweaks/block-labors.h diff --git a/NEWS.rst b/NEWS.rst index b1c214f57..504237163 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -58,6 +58,7 @@ New Features - `tweak`: + - ``tweak block-labors``: Prevents labors that can't be used from being toggled - ``tweak hide-priority``: Adds an option to hide designation priority indicators - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu diff --git a/dfhack.init-example b/dfhack.init-example index d1a28e169..430aa803a 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -179,6 +179,7 @@ tweak farm-plot-select tweak import-priority-category # Misc. UI tweaks +tweak block-labors # Prevents labors that can't be used from being toggled tweak civ-view-agreement tweak fps-min tweak hide-priority diff --git a/docs/Plugins.rst b/docs/Plugins.rst index ef6a004ad..eb519cac6 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -280,6 +280,7 @@ Subcommands that persist until disabled or DF quits: in advmode. The issue is that the screen tries to force you to select the contents separately from the container. This forcefully skips child reagents. +:block-labors: Prevents labors that can't be used from being toggled :civ-view-agreement: Fixes overlapping text on the "view agreement" screen :craft-age-wear: Fixes the behavior of crafted items wearing out over time (:bug:`6003`). With this tweak, items made from cloth and leather will gain a level of diff --git a/library/xml b/library/xml index 9b14c4560..d952e79b6 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9b14c45604fcd1ba5851d91d122d75f86936000b +Subproject commit d952e79b684f518b04eae5f973fa39679a2a4fa0 diff --git a/plugins/tweak/tweak.cpp b/plugins/tweak/tweak.cpp index df472e84d..3b17d9fa0 100644 --- a/plugins/tweak/tweak.cpp +++ b/plugins/tweak/tweak.cpp @@ -79,6 +79,7 @@ #include "tweaks/adamantine-cloth-wear.h" #include "tweaks/advmode-contained.h" +#include "tweaks/block-labors.h" #include "tweaks/civ-agreement-ui.h" #include "tweaks/craft-age-wear.h" #include "tweaks/eggs-fertile.h" @@ -117,7 +118,9 @@ REQUIRE_GLOBAL(ui_area_map_width); REQUIRE_GLOBAL(ui_build_selector); REQUIRE_GLOBAL(ui_building_item_cursor); REQUIRE_GLOBAL(ui_menu_width); +REQUIRE_GLOBAL(ui_look_cursor); REQUIRE_GLOBAL(ui_sidebar_menus); +REQUIRE_GLOBAL(ui_unit_view_mode); REQUIRE_GLOBAL(ui_workshop_in_add); REQUIRE_GLOBAL(world); @@ -177,6 +180,8 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector main.mode == df::ui_sidebar_mode::ViewUnits && + ui_unit_view_mode->value == df::ui_unit_view_mode::T_value::PrefLabor; + } + + inline bool forbidden_labor (df::unit *unit, df::unit_labor labor) + { + return is_valid_enum_item(labor) && !Units::isValidLabor(unit, labor); + } + + inline bool all_labors_enabled (df::unit *unit, df::unit_labor_category cat) + { + FOR_ENUM_ITEMS(unit_labor, labor) + { + if (ENUM_ATTR(unit_labor, category, labor) == cat && + !unit->status.labors[labor] && + !forbidden_labor(unit, labor)) + return false; + } + return true; + } + + inline void recolor_line (int x1, int x2, int y, UIColor color) + { + for (int x = x1; x <= x2; x++) + { + auto tile = Screen::readTile(x, y); + tile.fg = color; + tile.bold = false; + Screen::paintTile(tile, x, y); + } + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + auto dims = Gui::getDwarfmodeViewDims(); + if (valid_mode()) + { + df::unit *unit = Gui::getAnyUnit(this); + + for (int y = 5, i = (*ui_look_cursor/13)*13; + y <= 17 && i < unit_labors_sidemenu.size(); + ++y, ++i) + { + df::unit_labor labor = unit_labors_sidemenu[i]; + df::unit_labor_category cat = df::unit_labor_category(labor); + + if (is_valid_enum_item(cat) && all_labors_enabled(unit, cat)) + recolor_line(dims.menu_x1, dims.menu_x2, y, COLOR_WHITE); + + if (forbidden_labor(unit, labor)) + recolor_line(dims.menu_x1, dims.menu_x2, y, COLOR_RED + + (unit->status.labors[labor] ? 8 : 0)); + } + } + } + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { + using namespace df::enums::interface_key; + if (valid_mode()) + { + df::unit *unit = Gui::getAnyUnit(this); + df::unit_labor labor = unit_labors_sidemenu[*ui_look_cursor]; + df::unit_labor_category cat = df::unit_labor_category(labor); + + if ((input->count(SELECT) || input->count(SELECT_ALL)) && forbidden_labor(unit, labor)) + { + unit->status.labors[labor] = false; + return; + } + else if (input->count(SELECT_ALL) && is_valid_enum_item(cat)) + { + bool new_state = !all_labors_enabled(unit, cat); + FOR_ENUM_ITEMS(unit_labor, labor) + { + if (ENUM_ATTR(unit_labor, category, labor) == cat) + unit->status.labors[labor] = (new_state && !forbidden_labor(unit, labor)); + } + return; + } + } + INTERPOSE_NEXT(feed)(input); + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(block_labors_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(block_labors_hook, render); From 8cec8af3b14230d5bb9bd60b58b732029c6d3a0c Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 8 Jan 2016 21:08:26 -0500 Subject: [PATCH 172/222] CMake: Support cross-compiling This relies on a working cross-compiler, of course, as well as a separate build directory for cross-compiled builds, with DFHACK_NATIVE_BUILD_DIR pointing to an already-successful native build directory (this is needed for protoc). --- CMakeLists.txt | 5 +++++ depends/protobuf/CMakeLists.txt | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 193339077..a8e29ebb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,11 @@ if(MSVC) add_definitions( "/wd4819" ) endif() +IF(CMAKE_CROSSCOMPILING) + SET(DFHACK_NATIVE_BUILD_DIR "DFHACK_NATIVE_BUILD_DIR-NOTFOUND" CACHE FILEPATH "Path to a native build directory") + INCLUDE("${DFHACK_NATIVE_BUILD_DIR}/ImportExecutables.cmake") +ENDIF() + # set up folder structures for IDE solutions # MSVC Express won't load solutions that use this. It also doesn't include MFC supported # Check for MFC! diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 9ec13e6ca..39726c81a 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -22,7 +22,12 @@ IF(CMAKE_COMPILER_IS_GNUCC) FOREACH(namespace std::tr1 std ) IF(HAVE_HASH_MAP EQUAL 0 AND NOT STL_HASH_OLD_GCC) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") - TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + IF(CMAKE_CROSSCOMPILING) + TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + SET(HASH_MAP_RUN_RESULT ${HASH_MAP_COMPILE_RESULT}) + ELSE() + TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + ENDIF() IF (HASH_MAP_COMPILE_RESULT AND HASH_MAP_RUN_RESULT EQUAL 1) SET(HASH_MAP_H <${header}>) STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H}) @@ -237,8 +242,12 @@ TARGET_LINK_LIBRARIES(protoc protobuf) # Protobuf compiler executable -ADD_EXECUTABLE(protoc-bin google/protobuf/compiler/main.cc google/protobuf/compiler/command_line_interface.h google/protobuf/compiler/cpp/cpp_generator.h) -IDE_FOLDER(protoc-bin "Depends") +IF(NOT CMAKE_CROSSCOMPILING) + ADD_EXECUTABLE(protoc-bin google/protobuf/compiler/main.cc google/protobuf/compiler/command_line_interface.h google/protobuf/compiler/cpp/cpp_generator.h) + IDE_FOLDER(protoc-bin "Depends") -SET_TARGET_PROPERTIES(protoc-bin PROPERTIES OUTPUT_NAME protoc) -TARGET_LINK_LIBRARIES(protoc-bin protoc) + SET_TARGET_PROPERTIES(protoc-bin PROPERTIES OUTPUT_NAME protoc) + TARGET_LINK_LIBRARIES(protoc-bin protoc) + + EXPORT(TARGETS protoc-bin FILE ${CMAKE_BINARY_DIR}/ImportExecutables.cmake ) +ENDIF() From 53780d8232546107a745051a630289e45a6daa98 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Fri, 8 Jan 2016 22:28:07 -0700 Subject: [PATCH 173/222] New autogems plugin, automatically cutting rough gems. --- NEWS.rst | 4 + dfhack.init-example | 1 + docs/Plugins.rst | 7 + plugins/CMakeLists.txt | 1 + plugins/autogems.cpp | 293 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 306 insertions(+) create mode 100644 plugins/autogems.cpp diff --git a/NEWS.rst b/NEWS.rst index 504237163..065efeee7 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -43,6 +43,10 @@ Internals - Prevented plugins with active viewscreens from being unloaded and causing a crash +New Plugins +----------- +- `autogems`: Creates a new Workshop Order setting, automatically cutting rough gems + New Scripts ----------- - `devel/save-version`: Displays DF version information about the current save diff --git a/dfhack.init-example b/dfhack.init-example index 430aa803a..f2cf6b156 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -211,6 +211,7 @@ enable \ confirm \ dwarfmonitor \ mousequery \ + autogems \ automelt \ autotrade \ buildingplan \ diff --git a/docs/Plugins.rst b/docs/Plugins.rst index eb519cac6..33db4d8c3 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -875,6 +875,13 @@ job-duplicate In :kbd:`q` mode, when a job is highlighted within a workshop or furnace building, calling ``job-duplicate`` instantly duplicates the job. +.. _autogems: + +autogems +======== +Creates a new Workshop Order setting, automatically cutting rough gems +when `enabled `. + .. _stockflow: stockflow diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9781401ff..a321f178a 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -90,6 +90,7 @@ if (BUILD_SUPPORTED) # DFHACK_PLUGIN(advtools advtools.cpp) DFHACK_PLUGIN(autochop autochop.cpp) DFHACK_PLUGIN(autodump autodump.cpp) + DFHACK_PLUGIN(autogems autogems.cpp) DFHACK_PLUGIN(autohauler autohauler.cpp) DFHACK_PLUGIN(autolabor autolabor.cpp) DFHACK_PLUGIN(automaterial automaterial.cpp) diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp new file mode 100644 index 000000000..4ae6b7efc --- /dev/null +++ b/plugins/autogems.cpp @@ -0,0 +1,293 @@ +/* + * Autogems plugin. + * Creates a new Workshop Order setting, automatically cutting rough gems. + * For best effect, include "enable autogems" in your dfhack.init configuration. + */ + +#include "uicommon.h" + +#include "modules/Buildings.h" +#include "modules/Gui.h" +#include "modules/Job.h" +#include "modules/World.h" + +#include "df/building_workshopst.h" +#include "df/buildings_other_id.h" +#include "df/builtin_mats.h" +#include "df/general_ref_building_holderst.h" +#include "df/job.h" +#include "df/job_item.h" +#include "df/viewscreen_dwarfmodest.h" + +#define CONFIG_KEY "autogems/config" +#define DELTA_TICKS 1800 +#define MAX_WORKSHOP_JOBS 10 + +using namespace DFHack; + +DFHACK_PLUGIN("autogems"); +DFHACK_PLUGIN_IS_ENABLED(enabled); + +REQUIRE_GLOBAL(ui); +REQUIRE_GLOBAL(world); + +typedef decltype(df::item::id) item_id; +typedef decltype(df::job_item::mat_index) mat_index; +typedef std::map gem_map; + +bool running = false; +decltype(world->frame_counter) last_frame_count = 0; +const char *tagline = "Creates a new Workshop Order setting, automatically cutting rough gems."; +const char *usage = ( + " enable autogems\n" + " Enable the plugin.\n" + " disable autogems\n" + " Disable the plugin.\n" + "\n" + "While enabled, the Current Workshop Orders screen (o-W) have a new option:\n" + " g: Auto Cut Gems\n" + "\n" + "While this option is enabled, jobs will be created in Jeweler's Workshops\n" + "to cut any accessible rough gems.\n" +); + +void add_task(mat_index gem_type, df::building_workshopst *workshop) { + // Create a single task in the specified workshop. + // Partly copied from Buildings::linkForConstruct(); perhaps a refactor is in order. + + auto ref = df::allocate(); + if (!ref) { + //Core::printerr("Could not allocate general_ref_building_holderst\n"); + return; + } + + ref->building_id = workshop->id; + + auto item = new df::job_item(); + if (!item) { + //Core::printerr("Could not allocate job_item\n"); + return; + } + + item->item_type = df::item_type::ROUGH; + item->mat_type = df::builtin_mats::INORGANIC; + item->mat_index = gem_type; + item->quantity = 1; + item->vector_id = df::job_item_vector_id::ROUGH; + + auto job = new df::job(); + if (!job) { + //Core::printerr("Could not allocate job\n"); + return; + } + + job->job_type = df::job_type::CutGems; + job->pos = df::coord(workshop->centerx, workshop->centery, workshop->z); + job->mat_type = df::builtin_mats::INORGANIC; + job->mat_index = gem_type; + job->general_refs.push_back(ref); + job->job_items.push_back(item); + + workshop->jobs.push_back(job); + Job::linkIntoWorld(job); +} + +void add_tasks(gem_map &gem_types, df::building_workshopst *workshop) { + int slots = MAX_WORKSHOP_JOBS - workshop->jobs.size(); + if (slots <= 0) { + return; + } + + for (auto g = gem_types.begin(); g != gem_types.end() && slots > 0; ++g) { + while (g->second > 0 && slots > 0) { + add_task(g->first, workshop); + g->second -= 1; + slots -= 1; + } + } +} + +void create_jobs() { + // Creates jobs in Jeweler's Workshops as necessary. + // Todo: Consider path availability? + std::set stockpiled; + std::set unlinked; + gem_map available; + auto workshops = &world->buildings.other[df::buildings_other_id::WORKSHOP_JEWELER]; + + for (auto w = workshops->begin(); w != workshops->end(); ++w) { + auto workshop = virtual_cast(*w); + auto links = workshop->links.take_from_pile; + + if (workshop->construction_stage < 3) { + // Construction in progress. + continue; + } + + if (workshop->jobs.size() == 1 && workshop->jobs[0]->job_type == df::job_type::DestroyBuilding) { + // Queued for destruction. + continue; + } + + if (links.size() > 0) { + for (auto l = links.begin(); l != links.end() && workshop->jobs.size() <= MAX_WORKSHOP_JOBS; ++l) { + auto stockpile = virtual_cast(*l); + gem_map piled; + + Buildings::StockpileIterator stored; + for (stored.begin(stockpile); !stored.done(); ++stored) { + auto item = *stored; + if (item->getType() == item_type::ROUGH && item->getMaterial() == builtin_mats::INORGANIC) { + stockpiled.insert(item->id); + piled[item->getMaterialIndex()] += 1; + } + } + + // Decrement current jobs from all linked workshops, not just this one. + auto outbound = stockpile->links.give_to_workshop; + for (auto ws = outbound.begin(); ws != outbound.end(); ++ws) { + auto shop = virtual_cast(*ws); + for (auto j = shop->jobs.begin(); j != shop->jobs.end(); ++j) { + auto job = *j; + if (job->job_type == df::job_type::CutGems) { + if (job->flags.bits.repeat) { + piled[job->mat_index] = 0; + } else { + piled[job->mat_index] -= 1; + } + } + } + } + + add_tasks(piled, workshop); + } + } else { + // Note which gem types have already been ordered to be cut. + for (auto j = workshop->jobs.begin(); j != workshop->jobs.end(); ++j) { + auto job = *j; + if (job->job_type == df::job_type::CutGems) { + available[job->mat_index] -= job->flags.bits.repeat? 100: 1; + } + } + + if (workshop->jobs.size() <= MAX_WORKSHOP_JOBS) { + unlinked.insert(workshop); + } + } + } + + if (unlinked.size() > 0) { + // Count how many gems of each type are available to be cut. + // Gems in stockpiles linked to specific workshops don't count. + auto gems = world->items.other[items_other_id::ROUGH]; + for (auto g = gems.begin(); g != gems.end(); ++g) { + auto item = *g; + // ROUGH also includes raw glass; the INORGANIC check filters that out. + if (item->getMaterial() == builtin_mats::INORGANIC && !stockpiled.count(item->id)) { + available[item->getMaterialIndex()] += 1; + } + } + + for (auto w = unlinked.begin(); w != unlinked.end(); ++w) { + add_tasks(available, *w); + } + } +} + +DFhackCExport command_result plugin_onupdate(color_ostream &out) { + if (running && (world->frame_counter - last_frame_count >= DELTA_TICKS)) { + last_frame_count = world->frame_counter; + create_jobs(); + } + + return CR_OK; +} + + +/* + * Interface hooks + */ +struct autogem_hook : public df::viewscreen_dwarfmodest { + typedef df::viewscreen_dwarfmodest interpose_base; + + bool in_menu() { + // Determines whether we're looking at the Workshop Orders screen. + return ui->main.mode == ui_sidebar_mode::OrdersWorkshop; + } + + bool handleInput(std::set *input) { + if (!in_menu()) { + return false; + } + + if (input->count(interface_key::CUSTOM_G)) { + // Toggle whether gems are auto-cut for this fort. + auto config = World::GetPersistentData(CONFIG_KEY, NULL); + if (config.isValid()) { + config.ival(0) = running; + } + + running = !running; + return true; + } + + return false; + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) { + if (!handleInput(input)) { + INTERPOSE_NEXT(feed)(input); + } + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) { + INTERPOSE_NEXT(render)(); + if (in_menu()) { + auto dims = Gui::getDwarfmodeViewDims(); + int x = dims.menu_x1 + 1; + int y = dims.y1 + 12; + OutputHotkeyString(x, y, (running? "Auto Cut Gems": "No Auto Cut Gems"), "g", false, x, COLOR_WHITE, COLOR_LIGHTRED); + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(autogem_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(autogem_hook, render); + + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { + if (event == DFHack::SC_MAP_LOADED) { + if (enabled && World::isFortressMode()) { + // Determine whether auto gem cutting has been disabled for this fort. + auto config = World::GetPersistentData(CONFIG_KEY); + running = !(config.isValid() && config.ival(0)); + last_frame_count = world->frame_counter; + } + } else if (event == DFHack::SC_MAP_UNLOADED) { + running = false; + } + + return CR_OK; +} + +DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { + if (enable != enabled) { + if (!INTERPOSE_HOOK(autogem_hook, feed).apply(enable) || !INTERPOSE_HOOK(autogem_hook, render).apply(enable)) { + out.printerr("Could not %s autogem hooks!\n", enable? "insert": "remove"); + return CR_FAILURE; + } + + enabled = enable; + running = enabled && World::isFortressMode(); + } + + return CR_OK; +} + +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown(color_ostream &out) { + return plugin_enable(out, false); +} From e8ea5c93ca85b86977ce3b2f9b4b834f9f3c84da Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 9 Jan 2016 08:37:01 -0500 Subject: [PATCH 174/222] Build testHashMap.cpp in the build directory This allows switching between build directories without having to re-run CMake --- depends/protobuf/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 39726c81a..f8a1bdab8 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -21,12 +21,12 @@ IF(CMAKE_COMPILER_IS_GNUCC) FOREACH(header tr1/unordered_map unordered_map) FOREACH(namespace std::tr1 std ) IF(HAVE_HASH_MAP EQUAL 0 AND NOT STL_HASH_OLD_GCC) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") IF(CMAKE_CROSSCOMPILING) - TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") SET(HASH_MAP_RUN_RESULT ${HASH_MAP_COMPILE_RESULT}) ELSE() - TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + TRY_RUN(HASH_MAP_RUN_RESULT HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") ENDIF() IF (HASH_MAP_COMPILE_RESULT AND HASH_MAP_RUN_RESULT EQUAL 1) SET(HASH_MAP_H <${header}>) @@ -45,8 +45,8 @@ IF(CMAKE_COMPILER_IS_GNUCC) FOREACH(header ext/hash_map hash_map) FOREACH(namespace __gnu_cxx "" std stdext) IF (HAVE_HASH_MAP EQUAL 0) - CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") - TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp") + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/testHashMap.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") + TRY_COMPILE(HASH_MAP_COMPILE_RESULT ${PROJECT_BINARY_DIR}/CMakeTmp "${CMAKE_CURRENT_BINARY_DIR}/testHashMap.cpp") IF (HASH_MAP_COMPILE_RESULT) SET(HASH_MAP_H <${header}>) STRING(REPLACE "map" "set" HASH_SET_H ${HASH_MAP_H}) From b62a8673bc5cf678051d56fb6a94f41a6cf3fdcf Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 9 Jan 2016 10:51:55 -0500 Subject: [PATCH 175/222] Bump version to 0.42.04-alpha2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e29ebb5..891a130db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,7 @@ endif() # set up versioning. set(DF_VERSION "0.42.04") -SET(DFHACK_RELEASE "alpha1") +SET(DFHACK_RELEASE "alpha2") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 08bebc94e1d59db53e7f3e23985a6cd691dc400b Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sat, 9 Jan 2016 13:23:42 -0600 Subject: [PATCH 176/222] Fix dates being offset by 1 day in legends_plus.xml - Fixes #783 --- scripts/exportlegends.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index b8c37efde..cc83dbf5f 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -85,7 +85,7 @@ end --create an extra legends xml with extra data, by Mason11987 for World Viewer function export_more_legends_xml() - local julian_day = math.floor(df.global.cur_year_tick / 1200) + 1 + local julian_day = math.floor(df.global.cur_year_tick / 1200) local month = math.floor(julian_day / 28) + 1 --days and months are 1-indexed local day = julian_day % 28 + 1 local year_str = string.format('%0'..math.max(5, string.len(''..df.global.cur_year))..'d', df.global.cur_year) From 7c9002c4ea9321d89067d261225ff98ab6200db7 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Sat, 9 Jan 2016 14:47:00 -0700 Subject: [PATCH 177/222] Avoid overwriting dynamic lines. Even vanilla DF has three additional workshop order lines that only show up with modded raws. --- plugins/autogems.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp index 4ae6b7efc..dcce37c3c 100644 --- a/plugins/autogems.cpp +++ b/plugins/autogems.cpp @@ -246,7 +246,15 @@ struct autogem_hook : public df::viewscreen_dwarfmodest { auto dims = Gui::getDwarfmodeViewDims(); int x = dims.menu_x1 + 1; int y = dims.y1 + 12; - OutputHotkeyString(x, y, (running? "Auto Cut Gems": "No Auto Cut Gems"), "g", false, x, COLOR_WHITE, COLOR_LIGHTRED); + Screen::Pen pen = Screen::readTile(x, y); + + while (pen.valid() && pen.ch != ' ') { + pen = Screen::readTile(x, ++y); + } + + if (pen.valid()) { + OutputHotkeyString(x, y, (running? "Auto Cut Gems": "No Auto Cut Gems"), "g", false, x, COLOR_WHITE, COLOR_LIGHTRED); + } } } }; From 5f03bb743f06857b5aec8d99bcbfaa3f20bdafe9 Mon Sep 17 00:00:00 2001 From: Eric Wald Date: Sat, 9 Jan 2016 16:47:06 -0700 Subject: [PATCH 178/222] Increasing autogems checks to once per day. A legendary gem cutter couldn't quite clear a full suite of jobs before the next check, but it was a close call sometimes. --- plugins/autogems.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp index dcce37c3c..099a0e570 100644 --- a/plugins/autogems.cpp +++ b/plugins/autogems.cpp @@ -20,7 +20,7 @@ #include "df/viewscreen_dwarfmodest.h" #define CONFIG_KEY "autogems/config" -#define DELTA_TICKS 1800 +#define DELTA_TICKS 1200 #define MAX_WORKSHOP_JOBS 10 using namespace DFHack; From 0bcc8dc4437761e36d3dae8a516dccca5a11eaf5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 9 Jan 2016 19:28:12 -0500 Subject: [PATCH 179/222] exportlegends: fix day/month issues more reliably Fixes #783, #791 --- library/modules/World.cpp | 4 +++- scripts/exportlegends.lua | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/modules/World.cpp b/library/modules/World.cpp index 66390da6e..3be400515 100644 --- a/library/modules/World.cpp +++ b/library/modules/World.cpp @@ -78,7 +78,9 @@ uint32_t World::ReadCurrentYear() uint32_t World::ReadCurrentTick() { - return DF_GLOBAL_VALUE(cur_year_tick, 0); + // prevent this from returning anything less than 0, + // to avoid day/month calculations with 0xffffffff + return std::max(0, DF_GLOBAL_VALUE(cur_year_tick, 0)); } bool World::ReadGameMode(t_gamemodes& rd) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index cc83dbf5f..a0a04d9a2 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -85,9 +85,8 @@ end --create an extra legends xml with extra data, by Mason11987 for World Viewer function export_more_legends_xml() - local julian_day = math.floor(df.global.cur_year_tick / 1200) - local month = math.floor(julian_day / 28) + 1 --days and months are 1-indexed - local day = julian_day % 28 + 1 + local month = dfhack.world.ReadCurrentMonth() + 1 --days and months are 1-indexed + local day = dfhack.world.ReadCurrentDay() local year_str = string.format('%0'..math.max(5, string.len(''..df.global.cur_year))..'d', df.global.cur_year) local date_str = year_str..string.format('-%02d-%02d', month, day) From ebf2dada62c28384f541dfab9b6d7690de0694bc Mon Sep 17 00:00:00 2001 From: Japa Date: Sun, 10 Jan 2016 12:37:52 +0530 Subject: [PATCH 180/222] Increased DF version define --- plugins/remotefortressreader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 6c7dfffcd..04d8f6c8a 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -1,4 +1,4 @@ -#define DF_VERSION 40024 +#define DF_VERSION 42004 // some headers required for a plugin. Nothing special, just the basics. #include "Core.h" From 04cc9a2ad881a0619b41812f77a1521b69b63693 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Sun, 10 Jan 2016 21:11:11 +0100 Subject: [PATCH 181/222] export poetic, musical and dance forms, export written content --- scripts/exportlegends.lua | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index a0a04d9a2..65e84c28f 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -99,6 +99,73 @@ function export_more_legends_xml() file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name)).."\n") file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name,1)).."\n") + file:write("\n") + for formK, formV in ipairs(df.global.world.poetic_forms.all) do + for k,v in pairs(formV) do print(k,v) end + file:write("\t\n") + file:write("\t\t"..formV.id.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(formV.name,1)).."\n") + file:write("\t\n") + end + file:write("\n") + + file:write("\n") + for formK, formV in ipairs(df.global.world.poetic_forms.all) do + file:write("\t\n") + file:write("\t\t"..formV.id.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(formV.name,1)).."\n") + file:write("\t\n") + end + file:write("\n") + + file:write("\n") + for formK, formV in ipairs(df.global.world.dance_forms.all) do + file:write("\t\n") + file:write("\t\t"..formV.id.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(formV.name,1)).."\n") + file:write("\t\n") + end + file:write("\n") + + file:write("\n") + for wcK, wcV in ipairs(df.global.world.written_contents.all) do + file:write("\t\n") + file:write("\t\t"..wcV.id.."\n") + file:write("\t\t"..wcV.title.."\n") + file:write("\t\t"..wcV.page_start.."\n") + file:write("\t\t"..wcV.page_end.."\n") + for refK, refV in pairs(wcV.refs) do + file:write("\t\t\n") + file:write("\t\t\t"..df.general_ref_type[refV:getType()].."\n") + if refV:getType() == 64 then file:write("\t\t\t"..refV.anon_1.."\n") -- written content + elseif refV:getType() == 0 then file:write("\t\t\t"..refV.artifact_id.."\n") -- artifact + elseif refV:getType() == 42 then file:write("\t\t\t"..refV.entity_id.."\n") -- entity + elseif refV:getType() == 49 then file:write("\t\t\t"..refV.event_id.."\n") -- event + elseif refV:getType() == 51 then file:write("\t\t\t"..refV.site_id.."\n") -- site + elseif refV:getType() == 52 then file:write("\t\t\t"..refV.region_id.."\n") -- region + elseif refV:getType() == 54 then file:write("\t\t\t"..refV.hist_figure_id.."\n") -- hist figure + elseif refV:getType() == 65 then file:write("\t\t\t"..refV.poetic_form_id.."\n") -- poetic form + elseif refV:getType() == 66 then file:write("\t\t\t"..refV.musical_form_id.."\n") -- musical form + elseif refV:getType() == 67 then file:write("\t\t\t"..refV.dance_form_id.."\n") -- dance form + elseif refV:getType() == 47 then -- TODO interaction + elseif refV:getType() == 60 then -- TODO scholar knowledge + elseif refV:getType() == 62 then -- TODO value level + elseif refV:getType() == 63 then -- TODO language + else + print("unknown reference",refV:getType(),df.general_ref_type[refV:getType()]) + --for k,v in pairs(refV) do print(k,v) end + end + file:write("\t\t\n") + end + file:write("\t\t"..(df.written_content_type[wcV.type] or wcV.type).."\n") + for styleK, styleV in pairs(wcV.styles) do + file:write("\t\t\n") end file:write("\t\t"..wcV.author.."\n") file:write("\t\n") From 20f97b0cf9540e7c45b5c5c679cc372f7251be17 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Sun, 10 Jan 2016 22:09:31 +0100 Subject: [PATCH 184/222] bugfix copy & paste musical_forms --- scripts/exportlegends.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index d68b02a84..a926936b2 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -238,7 +238,6 @@ function export_more_legends_xml() file:write("\n") for formK, formV in ipairs(df.global.world.poetic_forms.all) do - for k,v in pairs(formV) do print(k,v) end file:write("\t\n") file:write("\t\t"..formV.id.."\n") file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(formV.name,1)).."\n") @@ -247,7 +246,7 @@ function export_more_legends_xml() file:write("\n") file:write("\n") - for formK, formV in ipairs(df.global.world.poetic_forms.all) do + for formK, formV in ipairs(df.global.world.musical_forms.all) do file:write("\t\n") file:write("\t\t"..formV.id.."\n") file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(formV.name,1)).."\n") From 98991c6b89fe8e83491e71efef83e07a8e4904e4 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 07:52:19 +0100 Subject: [PATCH 185/222] fixed type checks --- scripts/exportlegends.lua | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index a926936b2..4125786ef 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -272,21 +272,21 @@ function export_more_legends_xml() file:write("\t\t"..wcV.page_end.."\n") for refK, refV in pairs(wcV.refs) do file:write("\t\t\n") - file:write("\t\t\t"..df.general_ref_type[refV:getType()].."\n") - if refV:getType() == 64 then file:write("\t\t\t"..refV.anon_1.."\n") -- written content - elseif refV:getType() == 0 then file:write("\t\t\t"..refV.artifact_id.."\n") -- artifact - elseif refV:getType() == 42 then file:write("\t\t\t"..refV.entity_id.."\n") -- entity - elseif refV:getType() == 49 then file:write("\t\t\t"..refV.event_id.."\n") -- event - elseif refV:getType() == 51 then file:write("\t\t\t"..refV.site_id.."\n") -- site - elseif refV:getType() == 52 then file:write("\t\t\t"..refV.region_id.."\n") -- region - elseif refV:getType() == 54 then file:write("\t\t\t"..refV.hist_figure_id.."\n") -- hist figure - elseif refV:getType() == 65 then file:write("\t\t\t"..refV.poetic_form_id.."\n") -- poetic form - elseif refV:getType() == 66 then file:write("\t\t\t"..refV.musical_form_id.."\n") -- musical form - elseif refV:getType() == 67 then file:write("\t\t\t"..refV.dance_form_id.."\n") -- dance form - elseif refV:getType() == 47 then -- TODO interaction - elseif refV:getType() == 60 then -- TODO scholar knowledge - elseif refV:getType() == 62 then -- TODO value level - elseif refV:getType() == 63 then -- TODO language + file:write("\t\t\t"..df.general_ref_type[refV:getType()].."\n") + if refV:getType() == df.general_ref_type.ARTIFACT then file:write("\t\t\t"..refV.artifact_id.."\n") -- artifact + elseif refV:getType() == df.general_ref_type.ENTITY then file:write("\t\t\t"..refV.entity_id.."\n") -- entity + elseif refV:getType() == df.general_ref_type.HISTORICAL_EVENT then file:write("\t\t\t"..refV.event_id.."\n") -- event + elseif refV:getType() == df.general_ref_type.SITE then file:write("\t\t\t"..refV.site_id.."\n") -- site + elseif refV:getType() == df.general_ref_type.SUBREGION then file:write("\t\t\t"..refV.region_id.."\n") -- region + elseif refV:getType() == df.general_ref_type.HISTORICAL_FIGURE then file:write("\t\t\t"..refV.hist_figure_id.."\n") -- hist figure + elseif refV:getType() == df.general_ref_type.WRITTEN_CONTENT then file:write("\t\t\t"..refV.anon_1.."\n") + elseif refV:getType() == df.general_ref_type.POETIC_FORM then file:write("\t\t\t"..refV.poetic_form_id.."\n") -- poetic form + elseif refV:getType() == df.general_ref_type.MUSICAL_FORM then file:write("\t\t\t"..refV.musical_form_id.."\n") -- musical form + elseif refV:getType() == df.general_ref_type.DANCE_FORM then file:write("\t\t\t"..refV.dance_form_id.."\n") -- dance form + elseif refV:getType() == df.general_ref_type.INTERACTION then -- TODO INTERACTION + elseif refV:getType() == df.general_ref_type.KNOWLEDGE_SCHOLAR_FLAG then -- TODO KNOWLEDGE_SCHOLAR_FLAG + elseif refV:getType() == df.general_ref_type.VALUE_LEVEL then -- TODO VALUE_LEVEL + elseif refV:getType() == df.general_ref_type.LANGUAGE then -- TODO LANGUAGE else print("unknown reference",refV:getType(),df.general_ref_type[refV:getType()]) --for k,v in pairs(refV) do print(k,v) end @@ -524,7 +524,7 @@ function export_more_legends_xml() if (thisItem ~= nil) then if (thisItem.flags.artifact == true) then for refk,refv in pairs(thisItem.general_refs) do - if (refv:getType() == 1) then + if (refv:getType() == df.general_ref_type.IS_ARTIFACT) then file:write("\t\t"..refv.artifact_id.."\n") break end @@ -554,7 +554,7 @@ function export_more_legends_xml() if thisItem ~= nil then if (thisItem.flags.artifact == true) then for refk,refv in pairs(thisItem.general_refs) do - if (refv:getType() == 1) then + if (refv:getType() == df.general_ref_type.IS_ARTIFACT) then file:write("\t\t"..refv.artifact_id.."\n") break end From b262d495eca4fbd2fb444de767620afbffc54595 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 08:12:25 +0100 Subject: [PATCH 186/222] export only custom xml --- scripts/exportlegends.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 4125786ef..6e45b7be9 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -13,6 +13,7 @@ The 'info' option exports more data than is possible in vanilla, to a Options: :info: Exports the world/gen info, the legends XML, and a custom XML with more information +:custom Exports a custom XML with more information :sites: Exports all available site maps :maps: Exports all seventeen detailed maps :all: Equivalent to calling all of the above, in that order @@ -667,6 +668,8 @@ if dfhack.gui.getCurFocus() == "legends" or dfhack.gui.getCurFocus() == "dfhack/ wait_for_legends_vs() elseif args[1] == "info" then export_legends_info() + elseif args[1] == "custom" then + export_more_legends_xml() elseif args[1] == "maps" then wait_for_legends_vs() elseif args[1] == "sites" then From 15df508407269a8d947481251c786e8cc6331d0a Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 10:34:58 +0100 Subject: [PATCH 187/222] additional site and structure information --- scripts/exportlegends.lua | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 6e45b7be9..19664402b 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -128,28 +128,39 @@ function export_more_legends_xml() file:write("\n") for siteK, siteV in ipairs(df.global.world.world_data.sites) do - if (#siteV.buildings > 0) then - file:write("\t\n") - for k,v in pairs(siteV) do - if (k == "id") then - file:write("\t\t<"..k..">"..tostring(v).."\n") - elseif (k == "buildings") then + file:write("\t\n") + for k,v in pairs(siteV) do + if (k == "id" or k == "civ_id" or k == "cur_owner_id") then + file:write("\t\t<"..k..">"..tostring(v).."\n") + elseif (k == "buildings") then + if (#siteV.buildings > 0) then file:write("\t\t\n") for buildingK, buildingV in ipairs(siteV.buildings) do file:write("\t\t\t\n") file:write("\t\t\t\t"..buildingV.id.."\n") file:write("\t\t\t\t"..df.abstract_building_type[buildingV:getType()]:lower().."\n") if (df.abstract_building_type[buildingV:getType()]:lower() ~= "underworld_spire") then + -- if spire: unk_50 should be name and unk_bc some kind of flag file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name, 1)).."\n") file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name)).."\n") end + if (buildingV:getType() == df.abstract_building_type.TEMPLE) then + file:write("\t\t\t\t"..buildingV.deity.."\n") + file:write("\t\t\t\t"..buildingV.religion.."\n") + end + if (buildingV:getType() == df.abstract_building_type.DUNGEON) then + file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name)).."\n") + end + for inhabitabntK,inhabitabntV in pairs(buildingV.inhabitants) do + file:write("\t\t\t\t"..inhabitabntV.anon_2.."\n") + end file:write("\t\t\t\n") end file:write("\t\t\n") end end - file:write("\t\n") end + file:write("\t\n") end file:write("\n") From 6c3a1008dab83c388adc140b91d5903db089598c Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 11:03:46 +0100 Subject: [PATCH 188/222] additional entity information - positions - members --- scripts/exportlegends.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 19664402b..16e4ac286 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -241,6 +241,20 @@ function export_more_legends_xml() end file:write("\t\t\n") end + for positionK,positionV in pairs(entityV.positions.own) do + file:write("\t\t\n") + file:write("\t\t\t"..positionV.id.."\n") + if positionV.name[0] ~= "" then file:write("\t\t\t"..positionV.name[0].."\n") end + if positionV.name_male[0] ~= "" then file:write("\t\t\t"..positionV.name_male[0].."\n") end + if positionV.name_female[0] ~= "" then file:write("\t\t\t"..positionV.name_female[0].."\n") end + if positionV.spouse[0] ~= "" then file:write("\t\t\t"..positionV.spouse[0].."\n") end + if positionV.spouse_male[0] ~= "" then file:write("\t\t\t"..positionV.spouse_male[0].."\n") end + if positionV.spouse_female[0] ~= "" then file:write("\t\t\t"..positionV.spouse_female[0].."\n") end + file:write("\t\t\n") + end + for idx,id in pairs(entityV.histfig_ids) do + file:write("\t\t"..id.."\n") + end for id, link in ipairs(entityV.children) do file:write("\t\t"..link.."\n") end From c5309a930dd10dc8ec5cb23c09fd5e9a2ccb1f92 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 13:11:14 +0100 Subject: [PATCH 189/222] export entity position assignments to calculate postion on hf entity links --- scripts/exportlegends.lua | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 16e4ac286..1a686d393 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -149,7 +149,7 @@ function export_more_legends_xml() file:write("\t\t\t\t"..buildingV.religion.."\n") end if (buildingV:getType() == df.abstract_building_type.DUNGEON) then - file:write("\t\t\t\t"..dfhack.df2utf(dfhack.TranslateName(buildingV.name)).."\n") + file:write("\t\t\t\t"..buildingV.dungeon_type.."\n") end for inhabitabntK,inhabitabntV in pairs(buildingV.inhabitants) do file:write("\t\t\t\t"..inhabitabntV.anon_2.."\n") @@ -252,6 +252,15 @@ function export_more_legends_xml() if positionV.spouse_female[0] ~= "" then file:write("\t\t\t"..positionV.spouse_female[0].."\n") end file:write("\t\t\n") end + for assignmentK,assignmentV in pairs(entityV.positions.assignments) do + file:write("\t\t\n") + for k, v in pairs(assignmentV) do + if (k == "id" or k == "histfig" or k == "position_id" or k == "squad_id") then + file:write("\t\t\t<"..k..">"..v.."\n") + end + end + file:write("\t\t\n") + end for idx,id in pairs(entityV.histfig_ids) do file:write("\t\t"..id.."\n") end From 8c031aa14ea580ca9900c7cd8e1d06230efa7377 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 14:20:48 +0100 Subject: [PATCH 190/222] export hf sex and races in readable form --- scripts/exportlegends.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 1a686d393..fbf018fc3 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -199,7 +199,15 @@ function export_more_legends_xml() end file:write("\n") - file:write("\n\n") + file:write("\n") + for hfK, hfV in ipairs(df.global.world.history.figures) do + file:write("\t\n") + file:write("\t\t"..hfV.id.."\n") + file:write("\t\t"..hfV.sex.."\n") + if hfV.race >= 0 then file:write("\t\t"..df.global.world.raws.creatures.all[hfV.race].name[0].."\n") end + file:write("\t\n") + end + file:write("\n") file:write("\n") for entityPopK, entityPopV in ipairs(df.global.world.entity_populations) do @@ -347,6 +355,7 @@ function export_more_legends_xml() or event:getType() == df.history_event_type.TOPICAGREEMENT_REJECTED or event:getType() == df.history_event_type.TOPICAGREEMENT_MADE or event:getType() == df.history_event_type.BODY_ABUSED + or event:getType() == df.history_event_type.CHANGE_CREATURE_TYPE or event:getType() == df.history_event_type.CHANGE_HF_JOB or event:getType() == df.history_event_type.CREATED_BUILDING or event:getType() == df.history_event_type.CREATURE_DEVOURED @@ -539,7 +548,7 @@ function export_more_legends_xml() end elseif k == "race" then if v > -1 then - file:write("\t\t"..(df.global.world.raws.creatures.all[v].creature_id):lower().."\n") + file:write("\t\t"..df.global.world.raws.creatures.all[v].name[0].."\n") end elseif k == "caste" then if v > -1 then @@ -621,6 +630,8 @@ function export_more_legends_xml() file:write("\t\t<"..k..">"..df.death_type[v]:lower().."\n") elseif event:getType() == df.history_event_type.CHANGE_HF_JOB and (k == "new_job" or k == "old_job") then file:write("\t\t<"..k..">"..df.profession[v]:lower().."\n") + elseif event:getType() == df.history_event_type.CHANGE_CREATURE_TYPE and (k == "old_race" or k == "new_race") and v >= 0 then + file:write("\t\t<"..k..">"..df.global.world.raws.creatures.all[v].name[0].."\n") else file:write("\t\t<"..k..">"..tostring(v).."\n") end From 5c6bcbdf0f22dc9a11794c1d74dbe27463937b1d Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 14:52:13 +0100 Subject: [PATCH 191/222] fixed line ending --- scripts/exportlegends.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index fbf018fc3..8a153c2b8 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -315,7 +315,7 @@ function export_more_legends_xml() file:write("\t\t"..wcV.page_end.."\n") for refK, refV in pairs(wcV.refs) do file:write("\t\t\n") - file:write("\t\t\t"..df.general_ref_type[refV:getType()].."\n") + file:write("\t\t\t"..df.general_ref_type[refV:getType()].."\n") if refV:getType() == df.general_ref_type.ARTIFACT then file:write("\t\t\t"..refV.artifact_id.."\n") -- artifact elseif refV:getType() == df.general_ref_type.ENTITY then file:write("\t\t\t"..refV.entity_id.."\n") -- entity elseif refV:getType() == df.general_ref_type.HISTORICAL_EVENT then file:write("\t\t\t"..refV.event_id.."\n") -- event From 9715211a890742d53aa233927220c8e04fc6e710 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Mon, 11 Jan 2016 15:31:50 +0100 Subject: [PATCH 192/222] export all worships and fix group for HIST_FIGURE_REACH_SUMMIT fixes #782 --- scripts/exportlegends.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 8a153c2b8..257f2a2c3 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -231,11 +231,10 @@ function export_more_legends_xml() end file:write("\t\t"..(df.historical_entity_type[entityV.type]):lower().."\n") if entityV.type == df.historical_entity_type.Religion then -- Get worshipped figure - if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nil and - #entityV.unknown1b.worship == 1) then - file:write("\t\t"..entityV.unknown1b.worship[0].."\n") - else - print(entityV.unknown1b, entityV.unknown1b.worship, #entityV.unknown1b.worship) + if (entityV.unknown1b ~= nil and entityV.unknown1b.worship ~= nil) then + for k,v in pairs(entityV.unknown1b.worship) do + file:write("\t\t"..v.."\n") + end end end for id, link in pairs(entityV.entity_links) do @@ -503,8 +502,8 @@ function export_more_legends_xml() file:write("\t\t"..tostring(df.meeting_topic[v]):lower().."\n") elseif event:getType() == df.history_event_type.MASTERPIECE_CREATED_ITEM_IMPROVEMENT and k == "improvement_type" then file:write("\t\t"..df.improvement_type[v]:lower().."\n") - elseif ((event:getType() == df.history_event_type.HIST_FIGURE_REACH_SUMMIT and k == "figures") or - (event:getType() == df.history_event_type.HIST_FIGURE_NEW_PET and k == "group") + elseif ((event:getType() == df.history_event_type.HIST_FIGURE_REACH_SUMMIT and k == "group") + or (event:getType() == df.history_event_type.HIST_FIGURE_NEW_PET and k == "group") or (event:getType() == df.history_event_type.BODY_ABUSED and k == "bodies")) then for detailK,detailV in pairs(v) do file:write("\t\t<"..k..">"..detailV.."\n") From f02a504a0087be23258b7ccf021b6991d510fae2 Mon Sep 17 00:00:00 2001 From: Japa Date: Tue, 12 Jan 2016 00:10:16 +0530 Subject: [PATCH 193/222] Added tree coords to remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 40 ++++++++++++++ plugins/remotefortressreader.cpp | 68 ++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 3dc96cabd..bd53d5464 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -164,6 +164,10 @@ message MapBlock repeated bool water_salt = 17; repeated MatPair construction_items = 18; repeated BuildingInstance buildings = 19; + repeated int32 tree_percent = 20; + repeated int32 tree_x = 21; + repeated int32 tree_y = 22; + repeated int32 tree_z = 23; } message MatPair { @@ -407,3 +411,39 @@ message ArmyList { repeated Army armies = 1; } + +message GrowthPrint +{ + optional int32 priority = 1; + optional int32 color = 2; + optional int32 timing_start = 3; + optional int32 timing_end = 4; +} + +message TreeGrowth +{ + optional int32 index = 1; + optional string id = 2; + optional string name = 3; + optional MatPair mat = 4; + repeated GrowthPrint prints = 5; + optional int32 timing_start = 6; + optional int32 timing_end = 7; + optional bool twigs = 8; + optional bool light_branches = 9; + optional bool heavy_branches = 10; + optional bool trunk = 11; + optional bool roots = 12; + optional bool cap = 13; + optional bool sapling = 14; + optional int32 trunk_height_start = 15; + optional int32 trunk_height_end = 16; +} + +message PlantRaw +{ + optional int32 index = 1; + optional string id = 2; + repeated string name = 3; + repeated TreeGrowth growths = 4; +} \ No newline at end of file diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 04d8f6c8a..199f111ce 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -26,7 +26,9 @@ #include "df/plant.h" #if DF_VERSION > 40001 #include "df/plant_tree_info.h" +#include "df/plant_tree_tile.h" #include "df/plant_growth.h" +#include "df/plant_growth_print.h" #endif #include "df/itemdef.h" #include "df/building_def_workshopst.h" @@ -1018,6 +1020,68 @@ void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc NetBlock->set_map_z(DfBlock->map_pos.z); MapExtras::Block * block = MC->BlockAtTile(DfBlock->map_pos); + + int trunk_percent[16][16]; + int tree_x[16][16]; + int tree_y[16][16]; + int tree_z[16][16]; + for (int xx = 0; xx < 16; xx++) + for (int yy = 0; yy < 16; yy++) + { + trunk_percent[xx][yy] = 255; + tree_x[xx][yy] = -3000; + tree_y[xx][yy] = -3000; + tree_z[xx][yy] = -3000; + } + + df::map_block_column * column = df::global::world->map.column_index[(DfBlock->map_pos.x / 48) * 3][(DfBlock->map_pos.y / 48) * 3]; + for (int i = 0; i < column->plants.size(); i++) + { + df::plant* plant = column->plants[i]; + if (plant->tree_info == NULL) + continue; + df::plant_tree_info * tree_info = plant->tree_info; + if ( + plant->pos.z - tree_info->roots_depth > DfBlock->map_pos.z + || (plant->pos.z + tree_info->body_height) <= DfBlock->map_pos.z + || (plant->pos.x - tree_info->dim_x / 2) > (DfBlock->map_pos.x + 16) + || (plant->pos.x + tree_info->dim_x / 2) < (DfBlock->map_pos.x) + || (plant->pos.y - tree_info->dim_y / 2) > (DfBlock->map_pos.y + 16) + || (plant->pos.y + tree_info->dim_y / 2) < (DfBlock->map_pos.y) + ) + continue; + DFCoord localPos = plant->pos - DfBlock->map_pos; + for (int xx = 0; xx < tree_info->dim_x; xx++) + for (int yy = 0; yy < tree_info->dim_y; yy++) + { + int xxx = localPos.x - (tree_info->dim_x / 2) + xx; + int yyy = localPos.y - (tree_info->dim_y / 2) + yy; + if (xxx < 0 + || yyy < 0 + || xxx >= 16 + || yyy >= 16 + ) + continue; + df::plant_tree_tile tile; + if (-localPos.z < 0) + { + tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; + } + else + { + tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; + } + if (!tile.whole || tile.bits.blocked) + continue; + if (tree_info->body_height <= 1) + trunk_percent[xxx][yyy] = 0; + else + trunk_percent[xxx][yyy] = -localPos.z * 100 / (tree_info->body_height - 1); + tree_x[xxx][yyy] = xx - tree_info->dim_x / 2; + tree_y[xxx][yyy] = yy - tree_info->dim_y / 2; + tree_z[xxx][yyy] = localPos.z; + } + } for (int yy = 0; yy < 16; yy++) for (int xx = 0; xx < 16; xx++) { @@ -1059,6 +1123,10 @@ void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc constructionItem->set_mat_index(con->item_subtype); } } + NetBlock->add_tree_percent(trunk_percent[xx][yy]); + NetBlock->add_tree_x(tree_x[xx][yy]); + NetBlock->add_tree_y(tree_y[xx][yy]); + NetBlock->add_tree_z(tree_z[xx][yy]); } } From a0836ac7b74a95a8e312fa0516f30d10633d311c Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Tue, 12 Jan 2016 14:14:46 +0100 Subject: [PATCH 194/222] export substates (45=fled, 46/47=moved to study) from CHANGE_HF_STATE event --- scripts/exportlegends.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 257f2a2c3..952accf8e 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -356,6 +356,7 @@ function export_more_legends_xml() or event:getType() == df.history_event_type.BODY_ABUSED or event:getType() == df.history_event_type.CHANGE_CREATURE_TYPE or event:getType() == df.history_event_type.CHANGE_HF_JOB + or event:getType() == df.history_event_type.CHANGE_HF_STATE or event:getType() == df.history_event_type.CREATED_BUILDING or event:getType() == df.history_event_type.CREATURE_DEVOURED or event:getType() == df.history_event_type.HF_DOES_INTERACTION From 8ad71aae623e8b4935fa5e78e462478d477d3a94 Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Tue, 12 Jan 2016 14:59:13 +0100 Subject: [PATCH 195/222] export contents of scrolls and books --- scripts/exportlegends.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 952accf8e..a7c6ca2ca 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -188,6 +188,18 @@ function export_more_legends_xml() if (artifactV.item:getSubtype() ~= -1) then file:write("\t\t"..artifactV.item.subtype.name.."\n") end + for improvementK,impovementV in pairs(artifactV.item.improvements) do + if impovementV:getType() == df.improvement_type.WRITING then + for writingk,writingV in pairs(impovementV["itemimprovement_writingst.anon_1"]) do + file:write("\t\t"..writingV.."\n") + end + elseif impovementV:getType() == df.improvement_type.PAGES then + file:write("\t\t"..impovementV.count.."\n") + for writingk,writingV in pairs(impovementV.contents) do + file:write("\t\t"..writingV.."\n") + end + end + end end if (table.containskey(artifactV.item,"description")) then file:write("\t\t"..dfhack.df2utf(artifactV.item.description:lower()).."\n") From 45121ce3ad00d6b37527427eba78526ceb3e23be Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Tue, 12 Jan 2016 16:47:44 +0100 Subject: [PATCH 196/222] race for HIST_FIGURE_NEW_PET event --- scripts/exportlegends.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index a7c6ca2ca..d1fc3c4f6 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -523,7 +523,7 @@ function export_more_legends_xml() end elseif event:getType() == df.history_event_type.HIST_FIGURE_NEW_PET and k == "pets" then for detailK,detailV in pairs(v) do - file:write("\t\t<"..k..">"..(df.global.world.raws.creatures.all[detailV].creature_id):lower().."\n") + file:write("\t\t<"..k..">"..df.global.world.raws.creatures.all[detailV].name[0].."\n") end elseif event:getType() == df.history_event_type.BODY_ABUSED and (k == "props") then file:write("\t\t<"..k.."_item_type>"..tostring(df.item_type[event.props.item.item_type]):lower().."\n") From aab5996d7ce458638dc6c4f6b7387853305d33ff Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Tue, 12 Jan 2016 18:48:14 +0100 Subject: [PATCH 197/222] export landmasses, mountains and entity claims --- scripts/exportlegends.lua | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index d1fc3c4f6..2fb95d382 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -100,6 +100,28 @@ function export_more_legends_xml() file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name)).."\n") file:write(""..dfhack.df2utf(dfhack.TranslateName(df.global.world.world_data.name,1)).."\n") + file:write("\n") + for landmassK, landmassV in ipairs(df.global.world.world_data.landmasses) do + file:write("\t\n") + file:write("\t\t"..landmassV.index.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(landmassV.name,1)).."\n") + file:write("\t\t"..landmassV.min_x..","..landmassV.min_y.."\n") + file:write("\t\t"..landmassV.max_x..","..landmassV.max_y.."\n") + file:write("\t\n") + end + file:write("\n") + + file:write("\n") + for mountainK, mountainV in ipairs(df.global.world.world_data.mountain_peaks) do + file:write("\t\n") + file:write("\t\t"..mountainK.."\n") + file:write("\t\t"..dfhack.df2utf(dfhack.TranslateName(mountainV.name,1)).."\n") + file:write("\t\t"..mountainV.pos.x..","..mountainV.pos.y.."\n") + file:write("\t\t"..mountainV.height.."\n") + file:write("\t\n") + end + file:write("\n") + file:write("\n") for regionK, regionV in ipairs(df.global.world.world_data.regions) do file:write("\t\n") @@ -286,6 +308,11 @@ function export_more_legends_xml() for id, link in ipairs(entityV.children) do file:write("\t\t"..link.."\n") end + file:write("\t\t") + for xK, xVal in ipairs(entityV.claims.unk2.x) do + file:write(xVal..","..entityV.claims.unk2.y[xK].."|") + end + file:write("\n") file:write("\t\n") end file:write("\n") From 15a9d7f491d9df3e8ce8c54d2823b4d956817232 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 14 Jan 2016 20:13:46 -0500 Subject: [PATCH 198/222] Fix whitespace --- plugins/proto/RemoteFortressReader.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index bd53d5464..8f804a02a 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -441,7 +441,7 @@ message TreeGrowth } message PlantRaw -{ +{ optional int32 index = 1; optional string id = 2; repeated string name = 3; From ba3731016b71c24be0649989b8fafea78676054d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 16 Jan 2016 11:12:36 -0500 Subject: [PATCH 199/222] Only show prerelease warning once --- scripts/gui/prerelease-warning.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/gui/prerelease-warning.lua b/scripts/gui/prerelease-warning.lua index 7eb6094c3..e902f3353 100644 --- a/scripts/gui/prerelease-warning.lua +++ b/scripts/gui/prerelease-warning.lua @@ -7,6 +7,8 @@ Shows a warning on world load for pre-release builds. =end]] +shown = shown or false +if shown then return end if not dfhack.isPrerelease() then qerror('not a prerelease build') end -- Don't fire during worldgen if dfhack.internal.getAddress('gametype') and df.global.gametype == df.game_type.NONE then @@ -54,3 +56,4 @@ dfhack.color(COLOR_RESET) dfhack.print('\n\n') dlg.showMessage('Warning', message, COLOR_YELLOW) +shown = true From 514ae890bed0d260bf0511c99a5e43514a56a336 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 16 Jan 2016 11:34:12 -0500 Subject: [PATCH 200/222] exportlegends-related documentation updates --- NEWS.rst | 1 + docs/Authors.rst | 1 + scripts/exportlegends.lua | 10 +++++----- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 065efeee7..73f42b46f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -54,6 +54,7 @@ New Scripts New Features ------------ - `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: - location occupation assignment diff --git a/docs/Authors.rst b/docs/Authors.rst index 92ed1a9d4..f6c74d8c1 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -77,6 +77,7 @@ Raoul XQ raoulxq reverb Rinin Rinin Robert Heinrich rh73 +Robert Janetzko robertjanetzko rofl0r rofl0r root Roses Pheosics diff --git a/scripts/exportlegends.lua b/scripts/exportlegends.lua index 2fb95d382..82cdf0ab1 100644 --- a/scripts/exportlegends.lua +++ b/scripts/exportlegends.lua @@ -12,11 +12,11 @@ The 'info' option exports more data than is possible in vanilla, to a Options: -:info: Exports the world/gen info, the legends XML, and a custom XML with more information -:custom Exports a custom XML with more information -:sites: Exports all available site maps -:maps: Exports all seventeen detailed maps -:all: Equivalent to calling all of the above, in that order +:info: Exports the world/gen info, the legends XML, and a custom XML with more information +:custom: Exports a custom XML with more information +:sites: Exports all available site maps +:maps: Exports all seventeen detailed maps +:all: Equivalent to calling all of the above, in that order =end]] From a7b2d5e38fed1bed40b4c042686cb07682579e3c Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 16 Jan 2016 11:45:04 -0500 Subject: [PATCH 201/222] Fix autogems typedefs for MSVC and log errors to stderr --- plugins/autogems.cpp | 72 ++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp index 099a0e570..1079dff44 100644 --- a/plugins/autogems.cpp +++ b/plugins/autogems.cpp @@ -31,8 +31,8 @@ DFHACK_PLUGIN_IS_ENABLED(enabled); REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(world); -typedef decltype(df::item::id) item_id; -typedef decltype(df::job_item::mat_index) mat_index; +typedef int32_t item_id; +typedef int32_t mat_index; typedef std::map gem_map; bool running = false; @@ -54,40 +54,40 @@ const char *usage = ( void add_task(mat_index gem_type, df::building_workshopst *workshop) { // Create a single task in the specified workshop. // Partly copied from Buildings::linkForConstruct(); perhaps a refactor is in order. - + auto ref = df::allocate(); if (!ref) { - //Core::printerr("Could not allocate general_ref_building_holderst\n"); + std::cerr << "Could not allocate general_ref_building_holderst" << std::endl; return; } - + ref->building_id = workshop->id; - + auto item = new df::job_item(); if (!item) { - //Core::printerr("Could not allocate job_item\n"); + std::cerr << "Could not allocate job_item" << std::endl; return; } - + item->item_type = df::item_type::ROUGH; item->mat_type = df::builtin_mats::INORGANIC; item->mat_index = gem_type; item->quantity = 1; item->vector_id = df::job_item_vector_id::ROUGH; - + auto job = new df::job(); if (!job) { - //Core::printerr("Could not allocate job\n"); + std::cerr << "Could not allocate job" << std::endl; return; } - + job->job_type = df::job_type::CutGems; job->pos = df::coord(workshop->centerx, workshop->centery, workshop->z); job->mat_type = df::builtin_mats::INORGANIC; job->mat_index = gem_type; job->general_refs.push_back(ref); job->job_items.push_back(item); - + workshop->jobs.push_back(job); Job::linkIntoWorld(job); } @@ -97,7 +97,7 @@ void add_tasks(gem_map &gem_types, df::building_workshopst *workshop) { if (slots <= 0) { return; } - + for (auto g = gem_types.begin(); g != gem_types.end() && slots > 0; ++g) { while (g->second > 0 && slots > 0) { add_task(g->first, workshop); @@ -114,26 +114,26 @@ void create_jobs() { std::set unlinked; gem_map available; auto workshops = &world->buildings.other[df::buildings_other_id::WORKSHOP_JEWELER]; - + for (auto w = workshops->begin(); w != workshops->end(); ++w) { auto workshop = virtual_cast(*w); auto links = workshop->links.take_from_pile; - + if (workshop->construction_stage < 3) { // Construction in progress. continue; } - + if (workshop->jobs.size() == 1 && workshop->jobs[0]->job_type == df::job_type::DestroyBuilding) { // Queued for destruction. continue; } - + if (links.size() > 0) { for (auto l = links.begin(); l != links.end() && workshop->jobs.size() <= MAX_WORKSHOP_JOBS; ++l) { auto stockpile = virtual_cast(*l); gem_map piled; - + Buildings::StockpileIterator stored; for (stored.begin(stockpile); !stored.done(); ++stored) { auto item = *stored; @@ -142,7 +142,7 @@ void create_jobs() { piled[item->getMaterialIndex()] += 1; } } - + // Decrement current jobs from all linked workshops, not just this one. auto outbound = stockpile->links.give_to_workshop; for (auto ws = outbound.begin(); ws != outbound.end(); ++ws) { @@ -158,7 +158,7 @@ void create_jobs() { } } } - + add_tasks(piled, workshop); } } else { @@ -169,13 +169,13 @@ void create_jobs() { available[job->mat_index] -= job->flags.bits.repeat? 100: 1; } } - + if (workshop->jobs.size() <= MAX_WORKSHOP_JOBS) { unlinked.insert(workshop); } } } - + if (unlinked.size() > 0) { // Count how many gems of each type are available to be cut. // Gems in stockpiles linked to specific workshops don't count. @@ -187,7 +187,7 @@ void create_jobs() { available[item->getMaterialIndex()] += 1; } } - + for (auto w = unlinked.begin(); w != unlinked.end(); ++w) { add_tasks(available, *w); } @@ -199,7 +199,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) { last_frame_count = world->frame_counter; create_jobs(); } - + return CR_OK; } @@ -209,37 +209,37 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) { */ struct autogem_hook : public df::viewscreen_dwarfmodest { typedef df::viewscreen_dwarfmodest interpose_base; - + bool in_menu() { // Determines whether we're looking at the Workshop Orders screen. return ui->main.mode == ui_sidebar_mode::OrdersWorkshop; } - + bool handleInput(std::set *input) { if (!in_menu()) { return false; } - + if (input->count(interface_key::CUSTOM_G)) { // Toggle whether gems are auto-cut for this fort. auto config = World::GetPersistentData(CONFIG_KEY, NULL); if (config.isValid()) { config.ival(0) = running; } - + running = !running; return true; } - + return false; } - + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) { if (!handleInput(input)) { INTERPOSE_NEXT(feed)(input); } } - + DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)(); if (in_menu()) { @@ -247,11 +247,11 @@ struct autogem_hook : public df::viewscreen_dwarfmodest { int x = dims.menu_x1 + 1; int y = dims.y1 + 12; Screen::Pen pen = Screen::readTile(x, y); - + while (pen.valid() && pen.ch != ' ') { pen = Screen::readTile(x, ++y); } - + if (pen.valid()) { OutputHotkeyString(x, y, (running? "Auto Cut Gems": "No Auto Cut Gems"), "g", false, x, COLOR_WHITE, COLOR_LIGHTRED); } @@ -274,7 +274,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan } else if (event == DFHack::SC_MAP_UNLOADED) { running = false; } - + return CR_OK; } @@ -284,11 +284,11 @@ DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { out.printerr("Could not %s autogem hooks!\n", enable? "insert": "remove"); return CR_FAILURE; } - + enabled = enable; running = enabled && World::isFortressMode(); } - + return CR_OK; } From 63e5b5bc0fac254323564bc51f87e2bb4a6ebe16 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 17 Jan 2016 23:04:08 -0500 Subject: [PATCH 202/222] Fix ZLIB_ROOT on Windows --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 891a130db..1464306e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,8 +175,9 @@ endif() # find and make available libz if(NOT UNIX) SET(ZLIB_ROOT depends/zlib/) +else() + set(ZLIB_ROOT /usr/lib/i386-linux-gnu) endif() -set(ZLIB_ROOT /usr/lib/i386-linux-gnu) find_package(ZLIB REQUIRED) include_directories(depends/protobuf) include_directories(depends/lua/include) From c15cf5f4158704615c2d72542fe09fd1236133b9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 18 Jan 2016 09:18:32 -0500 Subject: [PATCH 203/222] Rename libstdc++ automatically in Linux launcher script --- package/linux/dfhack | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/package/linux/dfhack b/package/linux/dfhack index c75620077..2b2d04465 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -15,6 +15,7 @@ # DF_VALGRIND_OPTS: Options to pass to valgrind, if it's being run # DF_HELGRIND_OPTS: Options to pass to helgrind, if it's being run # DF_POST_CMD: Shell command to be run at very end of script +# DFHACK_NO_RENAME_LIBSTDCXX: Non-empty to prevent automatically renaming libstdc++ DF_DIR=$(dirname "$0") cd "${DF_DIR}" @@ -31,6 +32,22 @@ if [ -r "./$RC" ]; then . "./$RC" fi +# Disable bundled libstdc++ +libcxx_orig="libs/libstdc++.so.6" +libcxx_backup="libs/libstdc++.so.6.backup" +if [ -z "${DFHACK_NO_RENAME_LIBSTDCXX:-}" ] && [ -e "$libcxx_orig" ] && [ ! -e "$libcxx_backup" ]; then + mv "$libcxx_orig" "$libcxx_backup" + cat < Date: Mon, 18 Jan 2016 09:22:08 -0500 Subject: [PATCH 204/222] Also exclude libprotoc when cross-compiling (unused) --- depends/protobuf/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index f8a1bdab8..4fec34125 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -232,17 +232,17 @@ install(TARGETS protobuf-lite LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) -# Protobuf compiler shared library +IF(NOT CMAKE_CROSSCOMPILING) + # Protobuf compiler shared library -ADD_LIBRARY(protoc SHARED ${LIBPROTOC_SRCS} ${LIBPROTOC_HDRS}) -IDE_FOLDER(protoc "Depends") + ADD_LIBRARY(protoc SHARED ${LIBPROTOC_SRCS} ${LIBPROTOC_HDRS}) + IDE_FOLDER(protoc "Depends") -SET_TARGET_PROPERTIES(protoc PROPERTIES COMPILE_DEFINITIONS LIBPROTOC_EXPORTS) -TARGET_LINK_LIBRARIES(protoc protobuf) + SET_TARGET_PROPERTIES(protoc PROPERTIES COMPILE_DEFINITIONS LIBPROTOC_EXPORTS) + TARGET_LINK_LIBRARIES(protoc protobuf) -# Protobuf compiler executable + # Protobuf compiler executable -IF(NOT CMAKE_CROSSCOMPILING) ADD_EXECUTABLE(protoc-bin google/protobuf/compiler/main.cc google/protobuf/compiler/command_line_interface.h google/protobuf/compiler/cpp/cpp_generator.h) IDE_FOLDER(protoc-bin "Depends") From ab8cce2a86f4d139a2c03bf8c3ada1af31b80ee2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 18 Jan 2016 10:13:16 -0500 Subject: [PATCH 205/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index d952e79b6..138348a46 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d952e79b684f518b04eae5f973fa39679a2a4fa0 +Subproject commit 138348a467f6e31b4c379dedf057a1b2f7d27a25 From 1498eae4b5db1299c3e02d017f0f829ef6bbd856 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 18 Jan 2016 10:40:12 -0500 Subject: [PATCH 206/222] save-version: 0.42.05 (1537) --- scripts/devel/save-version.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/devel/save-version.lua b/scripts/devel/save-version.lua index 5b346c1d5..d06745577 100644 --- a/scripts/devel/save-version.lua +++ b/scripts/devel/save-version.lua @@ -86,6 +86,7 @@ versions = { [1532] = "0.42.02", [1533] = "0.42.03", [1534] = "0.42.04", + [1537] = "0.42.05", } min_version = math.huge From c78a1391e1f8e32872d4fd27175a27f4b729acd9 Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 18 Jan 2016 10:55:21 -0500 Subject: [PATCH 207/222] Update version to 0.42.05 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1464306e7..392b5ddb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,12 +98,12 @@ endif() # make sure all the necessary submodules have been set up if (NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/CMakeLists.txt) - message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in Compile.rst or Compile.html)") + message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/Compile.rst)") endif() # set up versioning. -set(DF_VERSION "0.42.04") -SET(DFHACK_RELEASE "alpha2") +set(DF_VERSION "0.42.05") +SET(DFHACK_RELEASE "alpha0") SET(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 0b2ba377be517ad7b21a3467c90422d192d20dfc Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 18 Jan 2016 11:49:37 -0500 Subject: [PATCH 208/222] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 138348a46..49eff8dca 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 138348a467f6e31b4c379dedf057a1b2f7d27a25 +Subproject commit 49eff8dca662bff83ff2191ac5b611504c72ae1c From 675d173266df9261df74915d75e6c16bfb8e58d2 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 18 Jan 2016 14:41:57 -0600 Subject: [PATCH 209/222] set civzone number when constructing a civzone --- library/modules/Buildings.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 0ceaeb819..58c1a87f9 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -887,6 +887,21 @@ static int getMaxStockpileId() return max_id; } +static int getMaxCivzoneId() +{ + auto &vec = world->buildings.other[buildings_other_id::ANY_ZONE]; + int max_id = 0; + + for (size_t i = 0; i < vec.size(); i++) + { + auto bld = strict_virtual_cast(vec[i]); + if (bld) + max_id = std::max(max_id, bld->zone_num); + } + + return max_id; +} + bool Buildings::constructAbstract(df::building *bld) { CHECK_NULL_POINTER(bld); @@ -903,6 +918,11 @@ bool Buildings::constructAbstract(df::building *bld) stock->stockpile_number = getMaxStockpileId() + 1; break; + case building_type::Civzone: + if (auto zone = strict_virtual_cast(bld)) + zone->zone_num = getMaxCivzoneId() + 1; + break; + default: break; } From d36bb20d91934db42c450bbfcd1170be32ccaa2f Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 18 Jan 2016 15:07:09 -0600 Subject: [PATCH 210/222] Add brew, mill, and thread to ban-cooking. See #796. brew: bans cooking of plants and fruits that can be made into alcohol (assuming default brewing reaction) mill: bans cooking of plants that can be milled. thread: bans cooking of plants that can be turned into thread. --- scripts/ban-cooking.rb | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/scripts/ban-cooking.rb b/scripts/ban-cooking.rb index 906469ea5..78d026019 100644 --- a/scripts/ban-cooking.rb +++ b/scripts/ban-cooking.rb @@ -5,7 +5,8 @@ ban-cooking =========== A more convenient way to ban cooking various categories of foods than the kitchen interface. Usage: ``ban-cooking ``. Valid types are ``booze``, -``honey``, ``tallow``, ``oil``, and ``seeds`` (non-tree plants with seeds). +``honey``, ``tallow``, ``oil``, ``seeds`` (non-tree plants with seeds), +``brew``, ``mill``, and ``thread``. =end @@ -87,11 +88,35 @@ $script_args.each do |arg| end end + when 'brew' + df.world.raws.plants.all.each do |p| + m = df.decode_mat(p.material_defs.type_basic_mat, p.material_defs.idx_basic_mat).material + ban_cooking[p.material_defs.type_basic_mat, p.material_defs.idx_basic_mat, :PLANT] if m.reaction_product and m.reaction_product.id and m.reaction_product.id.include?('DRINK_MAT') + + p.growths.each do |g| + m = df.decode_mat(g).material + ban_cooking[g.mat_type, g.mat_index, :PLANT_GROWTH] if m.reaction_product and m.reaction_product.id and m.reaction_product.id.include?('DRINK_MAT') + end + end + + when 'mill' + df.world.raws.plants.all.each do |p| + ban_cooking[p.material_defs.type_basic_mat, p.material_defs.idx_basic_mat, :PLANT] if m.flags[:MILL] + end + + when 'thread' + df.world.raws.plants.all.each do |p| + ban_cooking[p.material_defs.type_basic_mat, p.material_defs.idx_basic_mat, :PLANT] if m.flags[:THREAD] + end + else puts "ban-cooking booze - bans cooking of drinks" puts "ban-cooking honey - bans cooking of honey bee honey" puts "ban-cooking tallow - bans cooking of tallow" puts "ban-cooking oil - bans cooking of oil" puts "ban-cooking seeds - bans cooking of plants that have seeds (tree seeds don't count)" + puts "ban-cooking brew - bans cooking of plants that can be brewed into alcohol" + puts "ban-cooking mill - bans cooking of plants that can be milled into powder" + puts "ban-cooking thread - bans cooking of plants that can be turned into thread" end end From a1d557c4872754b06fd9bc4f4c5955889645a176 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 18 Jan 2016 15:29:49 -0600 Subject: [PATCH 211/222] Add ban-cooking milk. See #795. --- scripts/ban-cooking.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/ban-cooking.rb b/scripts/ban-cooking.rb index 78d026019..535f39126 100644 --- a/scripts/ban-cooking.rb +++ b/scripts/ban-cooking.rb @@ -6,7 +6,7 @@ ban-cooking A more convenient way to ban cooking various categories of foods than the kitchen interface. Usage: ``ban-cooking ``. Valid types are ``booze``, ``honey``, ``tallow``, ``oil``, ``seeds`` (non-tree plants with seeds), -``brew``, ``mill``, and ``thread``. +``brew``, ``mill``, ``thread``, and ``milk``. =end @@ -109,6 +109,15 @@ $script_args.each do |arg| ban_cooking[p.material_defs.type_basic_mat, p.material_defs.idx_basic_mat, :PLANT] if m.flags[:THREAD] end + when 'milk' + df.world.raws.creatures.all.each_with_index do |c, i| + c.material.each_with_index do |m, j| + if m.reaction_product and m.reaction_product.id and m.reaction_product.id.include?('CHEESE_MAT') + ban_cooking[j + DFHack::MaterialInfo::CREATURE_BASE, i, :LIQUID_MISC] + end + end + end + else puts "ban-cooking booze - bans cooking of drinks" puts "ban-cooking honey - bans cooking of honey bee honey" @@ -118,5 +127,6 @@ $script_args.each do |arg| puts "ban-cooking brew - bans cooking of plants that can be brewed into alcohol" puts "ban-cooking mill - bans cooking of plants that can be milled into powder" puts "ban-cooking thread - bans cooking of plants that can be turned into thread" + puts "ban-cooking milk - bans cooking of creature liquids that can be turned into cheese" end end From 80ecbbd369415f08e4bb5f2d6e6c7489f4b26189 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 21 Jan 2016 16:49:16 -0500 Subject: [PATCH 212/222] get rid of "private" comment in BitArray.h --- library/include/BitArray.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 +} From 61d4c9da9c8ff0e884c5438d6ebbebd48a9269d2 Mon Sep 17 00:00:00 2001 From: James Gilles Date: Tue, 26 Jan 2016 20:37:27 -0500 Subject: [PATCH 213/222] Enable ycmd for project --- .ycm_extra_conf.py | 130 +++++++++++++++++++++++++++++++++++++++++++++ CMakeLists.txt | 3 ++ 2 files changed, 133 insertions(+) create mode 100644 .ycm_extra_conf.py 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.") From 4c4eda44f94dc11a22e475d7c7cabacf016b3735 Mon Sep 17 00:00:00 2001 From: Japa Date: Wed, 27 Jan 2016 18:49:30 +0530 Subject: [PATCH 214/222] Added plant raw list to RemoteFortressReader.proto --- plugins/proto/RemoteFortressReader.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 8f804a02a..65fb910f2 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -446,4 +446,9 @@ message PlantRaw optional string id = 2; repeated string name = 3; repeated TreeGrowth growths = 4; +} + +message PlanRawList +{ + repeated PlantRaw plant_raws = 1; } \ No newline at end of file From 7f3191352cd9b79db6e6186fafc8610d1c61e339 Mon Sep 17 00:00:00 2001 From: Japa Date: Thu, 28 Jan 2016 00:06:10 +0530 Subject: [PATCH 215/222] send growth info through remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 4 +- plugins/remotefortressreader.cpp | 51 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 65fb910f2..04836be97 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -444,11 +444,11 @@ message PlantRaw { optional int32 index = 1; optional string id = 2; - repeated string name = 3; + optional string name = 3; repeated TreeGrowth growths = 4; } -message PlanRawList +message PlantRawList { repeated PlantRaw plant_raws = 1; } \ No newline at end of file diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 199f111ce..4ef1fc3c6 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -112,6 +112,7 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessage *in, WorldMap *out); static command_result GetRegionMaps(color_ostream &stream, const EmptyMessage *in, RegionMaps *out); static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage *in, CreatureRawList *out); +static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out); void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBlock, MapExtras::MapCache * MC, DFCoord pos); @@ -164,6 +165,7 @@ DFhackCExport RPCService *plugin_rpcconnect(color_ostream &) svc->addFunction("GetRegionMaps", GetRegionMaps); svc->addFunction("GetCreatureRaws", GetCreatureRaws); svc->addFunction("GetWorldMapCenter", GetWorldMapCenter); + svc->addFunction("GetPlantRaws", GetPlantRaws); return svc; } @@ -1943,3 +1945,52 @@ static command_result GetCreatureRaws(color_ostream &stream, const EmptyMessage return CR_OK; } + +static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in, PlantRawList *out) +{ + if (!df::global::world) + return CR_FAILURE; + + df::world * world = df::global::world; + + for (int i = 0; i < world->raws.plants.all.size(); i++) + { + df::plant_raw* plant_local = world->raws.plants.all[i]; + PlantRaw* plant_remote = out->add_plant_raws(); + + plant_remote->set_index(i); + plant_remote->set_id(plant_local->id); + plant_remote->set_name(plant_local->name); + for (int j = 0; j < plant_local->growths.size(); j++) + { + df::plant_growth* growth_local = plant_local->growths[j]; + TreeGrowth * growth_remote = plant_remote->add_growths(); + growth_remote->set_index(j); + growth_remote->set_id(growth_local->id); + growth_remote->set_name(growth_local->name); + for (int k = 0; k < growth_local->prints.size(); k++) + { + df::plant_growth_print* print_local = growth_local->prints[k]; + GrowthPrint* print_remote = growth_remote->add_prints(); + print_remote->set_priority(print_local->priority); + print_remote->set_color(print_local->color[0] + (print_local->color[1] * 8)); + print_remote->set_timing_start(print_local->timing_start); + print_remote->set_timing_end(print_local->timing_end); + } + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_twigs(growth_local->locations.bits.twigs); + growth_remote->set_light_branches(growth_local->locations.bits.light_branches); + growth_remote->set_heavy_branches(growth_local->locations.bits.heavy_branches); + growth_remote->set_trunk(growth_local->locations.bits.trunk); + growth_remote->set_roots(growth_local->locations.bits.roots); + growth_remote->set_cap(growth_local->locations.bits.cap); + growth_remote->set_sapling(growth_local->locations.bits.sapling); + growth_remote->set_timing_start(growth_local->timing_1); + growth_remote->set_timing_end(growth_local->timing_2); + growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); + growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); + } + } + return CR_OK; +} From a316dfa074400b1f9d51f1b13dcc919e174a7dca Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Fri, 29 Jan 2016 14:50:29 -0600 Subject: [PATCH 216/222] set floodgate flags correctly when allocating it in lua or c++ https://github.com/DFHack/dfhack/blob/0.42.04-alpha2/plugins/ruby/building.rb#L63 --- library/modules/Buildings.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 58c1a87f9..cc4af8d95 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -73,6 +73,7 @@ using namespace DFHack; #include "df/building_water_wheelst.h" #include "df/building_wellst.h" #include "df/building_rollersst.h" +#include "df/building_floodgatest.h" using namespace df::enums; using df::global::ui; @@ -369,6 +370,12 @@ df::building *Buildings::allocInstance(df::coord pos, df::building_type type, in obj->ready_timeout = 500; break; } + case building_type::Floodgate: + { + auto obj = (df::building_floodgatest*)bld; + obj->gate_flags.bits.closed = true; + break; + } default: break; } From aab5c61923dbf247977454bf7edf2a9257dfaa76 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Fri, 29 Jan 2016 14:51:32 -0600 Subject: [PATCH 217/222] set well bucket z correctly when allocating it in ruby https://github.com/DFHack/dfhack/blob/0.42.04-alpha2/library/modules/Buildings.cpp#L347-L352 --- plugins/ruby/building.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ruby/building.rb b/plugins/ruby/building.rb index 492d5249d..861feeb7d 100644 --- a/plugins/ruby/building.rb +++ b/plugins/ruby/building.rb @@ -57,6 +57,7 @@ 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 From 197e5ca2d960d84d55945528fd7cf40b0762be1a Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sat, 30 Jan 2016 08:46:16 -0600 Subject: [PATCH 218/222] update the name of the pressure plate field in ruby https://github.com/DFHack/dfhack/blob/0.42.04-alpha2/library/modules/Buildings.cpp#L365-L371 --- plugins/ruby/building.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ruby/building.rb b/plugins/ruby/building.rb index 861feeb7d..f749d51ae 100644 --- a/plugins/ruby/building.rb +++ b/plugins/ruby/building.rb @@ -60,7 +60,7 @@ module DFHack 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 end bld From e49745d338566158eaf8888a35ba2dbf56bbba8e Mon Sep 17 00:00:00 2001 From: Japa Date: Mon, 1 Feb 2016 00:41:13 +0530 Subject: [PATCH 219/222] Added tile and material to growths in remotefortressreader.cpp --- plugins/proto/RemoteFortressReader.proto | 2 ++ plugins/remotefortressreader.cpp | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/proto/RemoteFortressReader.proto index 04836be97..4bfc26c8e 100644 --- a/plugins/proto/RemoteFortressReader.proto +++ b/plugins/proto/RemoteFortressReader.proto @@ -418,6 +418,7 @@ message GrowthPrint optional int32 color = 2; optional int32 timing_start = 3; optional int32 timing_end = 4; + optional int32 tile = 5; } message TreeGrowth @@ -446,6 +447,7 @@ message PlantRaw optional string id = 2; optional string name = 3; repeated TreeGrowth growths = 4; + optional int32 tile = 5; } message PlantRawList diff --git a/plugins/remotefortressreader.cpp b/plugins/remotefortressreader.cpp index 4ef1fc3c6..9a7bda73a 100644 --- a/plugins/remotefortressreader.cpp +++ b/plugins/remotefortressreader.cpp @@ -24,6 +24,7 @@ #include "df/builtin_mats.h" #include "df/map_block_column.h" #include "df/plant.h" +#include "df/plant_raw_flags.h" #if DF_VERSION > 40001 #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" @@ -1961,6 +1962,10 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in plant_remote->set_index(i); plant_remote->set_id(plant_local->id); plant_remote->set_name(plant_local->name); + if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) + plant_remote->set_tile(plant_local->tiles.shrub_tile); + else + plant_remote->set_tile(plant_local->tiles.tree_tile); for (int j = 0; j < plant_local->growths.size(); j++) { df::plant_growth* growth_local = plant_local->growths[j]; @@ -1976,6 +1981,7 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in print_remote->set_color(print_local->color[0] + (print_local->color[1] * 8)); print_remote->set_timing_start(print_local->timing_start); print_remote->set_timing_end(print_local->timing_end); + print_remote->set_tile(print_local->tile_growth); } growth_remote->set_timing_start(growth_local->timing_1); growth_remote->set_timing_end(growth_local->timing_2); @@ -1990,6 +1996,9 @@ static command_result GetPlantRaws(color_ostream &stream, const EmptyMessage *in growth_remote->set_timing_end(growth_local->timing_2); growth_remote->set_trunk_height_start(growth_local->trunk_height_perc_1); growth_remote->set_trunk_height_end(growth_local->trunk_height_perc_2); + auto growthMat = growth_remote->mutable_mat(); + growthMat->set_mat_index(growth_local->mat_index); + growthMat->set_mat_type(growth_local->mat_type); } } return CR_OK; From ea9261f5b5910890d9c4328c14e6dbea86948b22 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 18 Jan 2016 19:24:00 -0600 Subject: [PATCH 220/222] allow dfhack to run inside valgrind valgrind replaces the readlink system call, but not the open system call. By calling readlink first, we guarantee that /proc/self/exe is the actual Dwarf Fortress executable and not the valgrind executable. See also: https://bugs.kde.org/show_bug.cgi?id=86921 --- library/Process-linux.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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) From 248331a1967d2527a13bcf259f35bffe4dec86b8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 31 Jan 2016 14:50:07 -0500 Subject: [PATCH 221/222] buildingplan: Support floodgates, grates, bars See #808 --- NEWS.rst | 1 + library/modules/Buildings.cpp | 102 ++++++++++++++++++++++------------ plugins/buildingplan-lib.cpp | 19 +++---- 3 files changed, 76 insertions(+), 46 deletions(-) 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/modules/Buildings.cpp b/library/modules/Buildings.cpp index cc4af8d95..a6589bac1 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -49,31 +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_floodgatest.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; @@ -346,36 +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: - { - auto obj = (df::building_floodgatest*)bld; + { + if (VIRTUAL_CAST_VAR(obj, df::building_floodgatest, bld)) obj->gate_flags.bits.closed = true; - break; - } + 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 From afa1199f98acbfa9d8eabcab06d84808fd3d7124 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Sun, 31 Jan 2016 15:19:58 -0600 Subject: [PATCH 222/222] Add support for grates and bars to Ruby. See also: DFHack@248331a1967d2527a13bcf259f35bffe4dec86b8, DFHack#808 --- plugins/ruby/building.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/ruby/building.rb b/plugins/ruby/building.rb index f749d51ae..7a85e9314 100644 --- a/plugins/ruby/building.rb +++ b/plugins/ruby/building.rb @@ -62,6 +62,10 @@ module DFHack when :Coffin; bld.initBurialFlags 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