From 7ddc3bb9187f7c9c74859a17ce977467f4151eb6 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 20 Jun 2020 23:05:55 -0500 Subject: [PATCH 01/18] fix labor inferences for custom furnaces Also clean up how paved roads are handled (the way it was was stupid) --- plugins/labormanager/joblabormapper.cpp | 40 ++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/plugins/labormanager/joblabormapper.cpp b/plugins/labormanager/joblabormapper.cpp index 7b4e77553..54ef9cceb 100644 --- a/plugins/labormanager/joblabormapper.cpp +++ b/plugins/labormanager/joblabormapper.cpp @@ -200,8 +200,6 @@ static df::building* get_building_from_job(df::job* j) static df::unit_labor construction_build_labor(df::building_actual* b) { - if (b->getType() == df::building_type::RoadPaved) - return df::unit_labor::BUILD_ROAD; // Find last item in building with use mode appropriate to the building's constructions state // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block // For wells 0 mechanism, 1 rope, 2 bucket, 3 block @@ -313,14 +311,27 @@ public: return workshop_build_labor[ws->type]; } break; + case df::building_type::Furnace: + { + df::building_furnacest* frn = (df::building_furnacest*) bld; + if (frn->design && !frn->design->flags.bits.designed) + return df::unit_labor::ARCHITECT; + if (frn->type == df::furnace_type::Custom) + { + df::building_def* def = df::building_def::find(frn->custom_type); + return def->build_labors[0]; + } + else + // cast to building_actual should be safe here because at this point the building has been designed + return construction_build_labor((df::building_actual*)bld); + } + break; case df::building_type::Construction: return df::unit_labor::BUILD_CONSTRUCTION; - case df::building_type::Furnace: case df::building_type::TradeDepot: case df::building_type::Bridge: case df::building_type::ArcheryTarget: case df::building_type::WaterWheel: - case df::building_type::RoadPaved: case df::building_type::Well: case df::building_type::ScrewPump: case df::building_type::Wagon: @@ -334,6 +345,8 @@ public: return construction_build_labor(b); } break; + case df::building_type::RoadPaved: + return df::unit_labor::BUILD_ROAD; case df::building_type::FarmPlot: return df::unit_labor::PLANT; case df::building_type::Chair: @@ -418,15 +431,26 @@ public: return workshop_build_labor[ws->type]; } break; + case df::building_type::Furnace: + { + df::building_furnacest* frn = (df::building_furnacest*) bld; + if (frn->type == df::furnace_type::Custom) + { + df::building_def* def = df::building_def::find(frn->custom_type); + return def->build_labors[0]; + } + else + // can't destroy a building if doesn't actually exist + return construction_build_labor((df::building_actual*)bld); + } + break; case df::building_type::Construction: return df::unit_labor::REMOVE_CONSTRUCTION; - case df::building_type::Furnace: case df::building_type::TradeDepot: case df::building_type::Wagon: case df::building_type::Bridge: case df::building_type::ScrewPump: case df::building_type::ArcheryTarget: - case df::building_type::RoadPaved: case df::building_type::Shop: case df::building_type::Support: case df::building_type::WaterWheel: @@ -436,7 +460,9 @@ public: auto b = (df::building_actual*) bld; return construction_build_labor(b); } - break; + break; + case df::building_type::RoadPaved: + return df::unit_labor::BUILD_ROAD; case df::building_type::FarmPlot: return df::unit_labor::PLANT; case df::building_type::Trap: From 61a00f78090adbfe7145907ce8817119acdb7940 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 20 Jun 2020 23:10:44 -0500 Subject: [PATCH 02/18] stupid whitespace --- plugins/labormanager/joblabormapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/labormanager/joblabormapper.cpp b/plugins/labormanager/joblabormapper.cpp index 54ef9cceb..4a71b40bf 100644 --- a/plugins/labormanager/joblabormapper.cpp +++ b/plugins/labormanager/joblabormapper.cpp @@ -460,7 +460,7 @@ public: auto b = (df::building_actual*) bld; return construction_build_labor(b); } - break; + break; case df::building_type::RoadPaved: return df::unit_labor::BUILD_ROAD; case df::building_type::FarmPlot: From 9510dd52e13c037b08ebecfa23dd46491f77737e Mon Sep 17 00:00:00 2001 From: Ryan Bennitt Date: Tue, 4 Aug 2020 23:01:28 +0100 Subject: [PATCH 03/18] Add Goal to Manipulator Detail Modes --- library/include/modules/Units.h | 5 ++ library/modules/Units.cpp | 67 +++++++++++++++++++++++++++ plugins/manipulator.cpp | 81 +++++++++++++++++++++++++++++---- 3 files changed, 145 insertions(+), 8 deletions(-) diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index f5995583b..c719a60a9 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -32,6 +32,7 @@ distribution. #include "DataDefs.h" #include "df/caste_raw_flags.h" +#include "df/goal_type.h" #include "df/job_skill.h" #include "df/mental_attribute_type.h" #include "df/misc_trait_type.h" @@ -180,6 +181,10 @@ DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profes DFHACK_EXPORT int8_t getProfessionColor(df::unit *unit, bool ignore_noble = false); DFHACK_EXPORT int8_t getCasteProfessionColor(int race, int caste, df::profession pid); +DFHACK_EXPORT df::goal_type getGoalType(df::unit *unit, int goalIndex = 0); +DFHACK_EXPORT std::string getGoalName(df::unit *unit, int goalIndex = 0); +DFHACK_EXPORT bool isGoalAchieved(df::unit *unit, int goalIndex = 0); + DFHACK_EXPORT std::string getSquadName(df::unit *unit); DFHACK_EXPORT df::activity_entry *getMainSocialActivity(df::unit *unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 422060803..87c71ac67 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1437,6 +1437,73 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid) return 3; } +df::goal_type Units::getGoalType(df::unit *unit, int goalIndex) +{ + CHECK_NULL_POINTER(unit); + + df::goal_type goal = df::goal_type::STAY_ALIVE; + if (unit->status.current_soul + && unit->status.current_soul->personality.dreams.size() > goalIndex) + { + goal = unit->status.current_soul->personality.dreams[goalIndex]->type; + } + return goal; +} + +std::string Units::getGoalName(df::unit *unit, int goalIndex) +{ + CHECK_NULL_POINTER(unit); + + df::goal_type goal = getGoalType(unit, goalIndex); + bool achieved_goal = isGoalAchieved(unit, goalIndex); + + switch (goal) + { + default: + case df::goal_type::STAY_ALIVE: + return achieved_goal ? "Stayed Alive" : "Stay Alive"; + case df::goal_type::MAINTAIN_ENTITY_STATUS: + return achieved_goal ? "Maintained Status" : "Maintain Status"; + case df::goal_type::START_A_FAMILY: + return isFemale(unit) ? + (achieved_goal ? "Is a Mother" : "Be a Mother") : + (achieved_goal ? "Is a Father" : "Be a Father"); + case df::goal_type::RULE_THE_WORLD: + return achieved_goal ? "Ruled the World" : "Rule the World"; + case df::goal_type::CREATE_A_GREAT_WORK_OF_ART: + return achieved_goal ? "Made Great Artwork" : "Create Great Artwork"; + case df::goal_type::CRAFT_A_MASTERWORK: + return achieved_goal ? "Crafted a Masterwork" : "Craft a Masterwork"; + case df::goal_type::BRING_PEACE_TO_THE_WORLD: + return achieved_goal ? "Brought World Peace" : "Bring Peace to World"; + case df::goal_type::BECOME_A_LEGENDARY_WARRIOR: + return achieved_goal ? "Is Legendary Warrior" : "Be Legendary Warrior"; + case df::goal_type::MASTER_A_SKILL: + return achieved_goal ? "Mastered a Skill" : "Master a Skill"; + case df::goal_type::FALL_IN_LOVE: + return achieved_goal ? "Fell in Love" : "Fall in Love"; + case df::goal_type::SEE_THE_GREAT_NATURAL_SITES: + return achieved_goal ? "Saw Natural Wonders" : "See Natural Wonders"; + case df::goal_type::IMMORTALITY: + return achieved_goal ? "Immortal" : "Immortality"; + case df::goal_type::MAKE_A_GREAT_DISCOVERY: + return achieved_goal ? "Made Great Discovery" : "Make Great Discovery"; + case df::goal_type::ATTAINING_RANK_IN_SOCIETY: + return achieved_goal ? "Attained Social Rank" : "Attain Social Rank"; + case df::goal_type::BATHING_THE_WORLD_IN_CHAOS: + return achieved_goal ? "World is in Chaos" : "Bathe World in Chaos"; + } +} + +bool Units::isGoalAchieved(df::unit *unit, int goalIndex) +{ + CHECK_NULL_POINTER(unit); + + return unit->status.current_soul + && unit->status.current_soul->personality.dreams.size() > goalIndex + && unit->status.current_soul->personality.dreams[goalIndex]->flags.whole != 0; +} + std::string Units::getSquadName(df::unit *unit) { CHECK_NULL_POINTER(unit); diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index a013df335..4bb285f0b 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -32,9 +32,12 @@ #include "df/caste_raw.h" #include "df/historical_entity.h" #include "df/entity_raw.h" +#include "df/goal_type.h" +#include "df/unit_personality.h" #include "uicommon.h" #include "listcolumn.h" +#include "manipulator.h" using std::stringstream; using std::set; @@ -287,6 +290,9 @@ struct UnitInfo string name; string transname; string profession; + string goal; + enum { NEUTRAL, MALE, FEMALE } goal_gender; + bool achieved_goal; int8_t color; int active_index; string squad_effective_name; @@ -310,7 +316,8 @@ struct UnitInfo enum detail_cols { DETAIL_MODE_PROFESSION, DETAIL_MODE_SQUAD, - DETAIL_MODE_JOB + DETAIL_MODE_JOB, + DETAIL_MODE_GOAL }; enum altsort_mode { ALTSORT_NAME, @@ -348,6 +355,21 @@ bool sortByProfession (const UnitInfo *d1, const UnitInfo *d2) return (d1->profession < d2->profession); } +bool sortByGoal (const UnitInfo *d1, const UnitInfo *d2) +{ + if (!d1->unit->status.current_soul) + return !descending; + if (!d2->unit->status.current_soul) + return descending; + + df::goal_type goal1 = Units::getGoalType(d1->unit); + df::goal_type goal2 = Units::getGoalType(d2->unit); + if (descending) + return (goal1 > goal2); + else + return (goal1 < goal2); +} + bool sortBySquad (const UnitInfo *d1, const UnitInfo *d2) { bool gt = false; @@ -583,6 +605,8 @@ namespace unit_ops { } string get_profname(UnitInfo *u) { return Units::getProfessionName(u->unit); } + string get_goalname(UnitInfo *u) + { return Units::getGoalName(u->unit); } string get_real_profname(UnitInfo *u) { string tmp = u->unit->custom_profession; @@ -1237,6 +1261,14 @@ void viewscreen_unitlaborsst::refreshNames() cur->name = Translation::TranslateName(Units::getVisibleName(unit), false); cur->transname = Translation::TranslateName(Units::getVisibleName(unit), true); cur->profession = Units::getProfessionName(unit); + cur->goal = Units::getGoalName(unit); + df::goal_type goal = Units::getGoalType(unit); + if (goal == df::goal_type::START_A_FAMILY) { + cur->goal_gender = Units::isFemale(unit) ? UnitInfo::FEMALE : UnitInfo::MALE; + } else { + cur->goal_gender = UnitInfo::NEUTRAL; + } + cur->achieved_goal = Units::isGoalAchieved(unit); if (unit->job.current_job == NULL) { df::activity_event *event = Units::getMainSocialEvent(unit); @@ -1298,8 +1330,10 @@ void viewscreen_unitlaborsst::calcSize() detail_cmp = units[i]->squad_info.size(); } else if (detail_mode == DETAIL_MODE_JOB) { detail_cmp = units[i]->job_desc.size(); - } else { + } else if (detail_mode == DETAIL_MODE_PROFESSION) { detail_cmp = units[i]->profession.size(); + } else { + detail_cmp = units[i]->goal.size(); } if (size_t(col_maxwidth[DISP_COLUMN_DETAIL]) < detail_cmp) col_maxwidth[DISP_COLUMN_DETAIL] = detail_cmp; @@ -1736,8 +1770,10 @@ void viewscreen_unitlaborsst::feed(set *events) std::stable_sort(units.begin(), units.end(), sortBySquad); } else if (detail_mode == DETAIL_MODE_JOB) { std::stable_sort(units.begin(), units.end(), sortByJob); - } else { + } else if (detail_mode == DETAIL_MODE_PROFESSION){ std::stable_sort(units.begin(), units.end(), sortByProfession); + } else { + std::stable_sort(units.begin(), units.end(), sortByGoal); } break; case ALTSORT_STRESS: @@ -1777,9 +1813,11 @@ void viewscreen_unitlaborsst::feed(set *events) if (detail_mode == DETAIL_MODE_SQUAD) { detail_mode = DETAIL_MODE_JOB; } else if (detail_mode == DETAIL_MODE_JOB) { - detail_mode = DETAIL_MODE_PROFESSION; - } else { + detail_mode = DETAIL_MODE_GOAL; + } else if (detail_mode == DETAIL_MODE_PROFESSION) { detail_mode = DETAIL_MODE_SQUAD; + } else { + detail_mode = DETAIL_MODE_PROFESSION; } } @@ -1888,8 +1926,10 @@ void viewscreen_unitlaborsst::render() detail_str = "Squad"; } else if (detail_mode == DETAIL_MODE_JOB) { detail_str = "Job"; - } else { + } else if (detail_mode == DETAIL_MODE_PROFESSION) { detail_str = "Profession"; + } else { + detail_str = "Goal"; } Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_DETAIL], 2, detail_str); @@ -1978,9 +2018,32 @@ void viewscreen_unitlaborsst::render() } else { fg = COLOR_LIGHTCYAN; } - } else { + } else if (detail_mode == DETAIL_MODE_PROFESSION) { fg = cur->color; detail_str = cur->profession; + } else { + if (cur->goal_gender == UnitInfo::NEUTRAL) { + if (cur->achieved_goal) { + fg = COLOR_LIGHTGREEN; + } else { + fg = COLOR_BROWN; + } + } else if (cur->goal_gender == UnitInfo::FEMALE) { + if (cur->achieved_goal) { + fg = COLOR_LIGHTRED; + } + else { + fg = COLOR_MAGENTA; + } + } else { + if (cur->achieved_goal) { + fg = COLOR_LIGHTCYAN; + } + else { + fg = COLOR_BLUE; + } + } + detail_str = cur->goal; } detail_str.resize(col_widths[DISP_COLUMN_DETAIL]); Screen::paintString(Screen::Pen(' ', fg, bg), col_offsets[DISP_COLUMN_DETAIL], 4 + row, detail_str); @@ -2140,8 +2203,10 @@ void viewscreen_unitlaborsst::render() OutputString(15, x, y, "Squad"); } else if (detail_mode == DETAIL_MODE_JOB) { OutputString(15, x, y, "Job"); - } else { + } else if (detail_mode == DETAIL_MODE_PROFESSION){ OutputString(15, x, y, "Profession"); + } else { + OutputString(15, x, y, "Goal"); } break; case ALTSORT_STRESS: From a85b77e6f156a75684d00a60911b060f00c631b8 Mon Sep 17 00:00:00 2001 From: Ryan Bennitt Date: Fri, 7 Aug 2020 22:07:48 +0100 Subject: [PATCH 04/18] Retrieve goal string values from enum attributes and add new Units methods to Lua API and docs --- docs/Lua API.rst | 24 +++++++++++++++++++++ library/LuaApi.cpp | 3 +++ library/modules/Units.cpp | 45 +++++++++------------------------------ plugins/manipulator.cpp | 1 - 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 8c3763245..45ccd46a9 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1277,6 +1277,30 @@ Units module Retrieves the profession color for the given race/caste using raws. +* ``dfhack.units.getGoalType(unit[,goalIndex])`` + + Retrieves the goal type of the dream that the given unit has. + By default the goal of the first dream is returned. + The goalIndex parameter may be used to retrieve additional dream goals. + Currently only one dream per unit is supported by Dwarf Fortress. + Support for multiple dreams may be added in future versions of Dwarf Fortress. + +* ``dfhack.units.getGoalName(unit[,goalIndex])`` + + Retrieves the short name describing the goal of the dream that the given unit has. + By default the goal of the first dream is returned. + The goalIndex parameter may be used to retrieve additional dream goals. + Currently only one dream per unit is supported by Dwarf Fortress. + Support for multiple dreams may be added in future versions of Dwarf Fortress. + +* ``dfhack.units.isGoalAchieved(unit[,goalIndex])`` + + Checks if given unit has achieved the goal of the dream. + By default the status of the goal of the first dream is returned. + The goalIndex parameter may be used to check additional dream goals. + Currently only one dream per unit is supported by Dwarf Fortress. + Support for multiple dreams may be added in future versions of Dwarf Fortress. + * ``dfhack.units.getStressCategory(unit)`` Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 25843875d..13c9386ff 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1604,6 +1604,9 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getCasteProfessionName), WRAPM(Units, getProfessionColor), WRAPM(Units, getCasteProfessionColor), + WRAPM(Units, getGoalType), + WRAPM(Units, getGoalName), + WRAPM(Units, isGoalAchieved), WRAPM(Units, getSquadName), WRAPM(Units, isWar), WRAPM(Units, isHunter), diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 87c71ac67..32fe3b5b9 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -61,6 +61,7 @@ using namespace std; #include "df/identity_type.h" #include "df/game_mode.h" #include "df/histfig_entity_link_positionst.h" +#include "df/histfig_relationship_type.h" #include "df/historical_entity.h" #include "df/historical_figure.h" #include "df/historical_figure_info.h" @@ -1457,42 +1458,16 @@ std::string Units::getGoalName(df::unit *unit, int goalIndex) df::goal_type goal = getGoalType(unit, goalIndex); bool achieved_goal = isGoalAchieved(unit, goalIndex); - switch (goal) - { - default: - case df::goal_type::STAY_ALIVE: - return achieved_goal ? "Stayed Alive" : "Stay Alive"; - case df::goal_type::MAINTAIN_ENTITY_STATUS: - return achieved_goal ? "Maintained Status" : "Maintain Status"; - case df::goal_type::START_A_FAMILY: - return isFemale(unit) ? - (achieved_goal ? "Is a Mother" : "Be a Mother") : - (achieved_goal ? "Is a Father" : "Be a Father"); - case df::goal_type::RULE_THE_WORLD: - return achieved_goal ? "Ruled the World" : "Rule the World"; - case df::goal_type::CREATE_A_GREAT_WORK_OF_ART: - return achieved_goal ? "Made Great Artwork" : "Create Great Artwork"; - case df::goal_type::CRAFT_A_MASTERWORK: - return achieved_goal ? "Crafted a Masterwork" : "Craft a Masterwork"; - case df::goal_type::BRING_PEACE_TO_THE_WORLD: - return achieved_goal ? "Brought World Peace" : "Bring Peace to World"; - case df::goal_type::BECOME_A_LEGENDARY_WARRIOR: - return achieved_goal ? "Is Legendary Warrior" : "Be Legendary Warrior"; - case df::goal_type::MASTER_A_SKILL: - return achieved_goal ? "Mastered a Skill" : "Master a Skill"; - case df::goal_type::FALL_IN_LOVE: - return achieved_goal ? "Fell in Love" : "Fall in Love"; - case df::goal_type::SEE_THE_GREAT_NATURAL_SITES: - return achieved_goal ? "Saw Natural Wonders" : "See Natural Wonders"; - case df::goal_type::IMMORTALITY: - return achieved_goal ? "Immortal" : "Immortality"; - case df::goal_type::MAKE_A_GREAT_DISCOVERY: - return achieved_goal ? "Made Great Discovery" : "Make Great Discovery"; - case df::goal_type::ATTAINING_RANK_IN_SOCIETY: - return achieved_goal ? "Attained Social Rank" : "Attain Social Rank"; - case df::goal_type::BATHING_THE_WORLD_IN_CHAOS: - return achieved_goal ? "World is in Chaos" : "Bathe World in Chaos"; + std::string goal_name = achieved_goal ? ENUM_ATTR(goal_type, achieved_short_name, goal) : ENUM_ATTR(goal_type, short_name, goal); + if (goal == df::goal_type::START_A_FAMILY) { + std::string parent = ENUM_KEY_STR(histfig_relationship_type, histfig_relationship_type::Parent); + size_t start_pos = goal_name.find(parent); + if (start_pos != std::string::npos) { + df::histfig_relationship_type parent_type = isFemale(unit) ? histfig_relationship_type::Mother : histfig_relationship_type::Father; + goal_name.replace(start_pos, parent.length(), ENUM_KEY_STR(histfig_relationship_type, parent_type)); + } } + return goal_name; } bool Units::isGoalAchieved(df::unit *unit, int goalIndex) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 4bb285f0b..ae7b3f800 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -37,7 +37,6 @@ #include "uicommon.h" #include "listcolumn.h" -#include "manipulator.h" using std::stringstream; using std::set; From c76f71cd461f12a7ef861326321fc076f660864b Mon Sep 17 00:00:00 2001 From: Ryan Bennitt Date: Fri, 7 Aug 2020 22:20:11 +0100 Subject: [PATCH 05/18] Update xml library submodule --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 9fca46ccc..51e237b9b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9fca46ccca28e0948014b9d56a096ad7343473f1 +Subproject commit 51e237b9b2e667d48fbb793ac29d782d7326c39a From f7fda8e7f52fbcecd18b0a7d5f87ef31797d8156 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 00:06:59 -0400 Subject: [PATCH 06/18] Update changelog, authors, xml (#1615) --- docs/Authors.rst | 1 + docs/changelog.txt | 1 + library/xml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Authors.rst b/docs/Authors.rst index 31789aa52..a9036a33c 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -142,6 +142,7 @@ rout rubybrowncoat rubybrowncoat Rumrusher rumrusher RusAnon RusAnon +Ryan Bennitt ryanbennitt sami scamtank scamtank Sebastian Wolfertz Enkrod diff --git a/docs/changelog.txt b/docs/changelog.txt index e7a01f4fe..f5bdb42b3 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,6 +55,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API - Added ``Filesystem::mkdir_recursive`` - Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory +- ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()`` ## Internals - Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) diff --git a/library/xml b/library/xml index 51e237b9b..daa353138 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 51e237b9b2e667d48fbb793ac29d782d7326c39a +Subproject commit daa3531384c6d222c7a28f6a73de3201a27f391d From ee8d1302980cf4e805a4f4ef170bd9f1411b3a27 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 00:12:59 -0400 Subject: [PATCH 07/18] Use existing pronoun_type enum --- plugins/manipulator.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index ae7b3f800..28b946be2 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -290,7 +290,7 @@ struct UnitInfo string transname; string profession; string goal; - enum { NEUTRAL, MALE, FEMALE } goal_gender; + df::pronoun_type goal_gender; bool achieved_goal; int8_t color; int active_index; @@ -1263,9 +1263,9 @@ void viewscreen_unitlaborsst::refreshNames() cur->goal = Units::getGoalName(unit); df::goal_type goal = Units::getGoalType(unit); if (goal == df::goal_type::START_A_FAMILY) { - cur->goal_gender = Units::isFemale(unit) ? UnitInfo::FEMALE : UnitInfo::MALE; + cur->goal_gender = unit->sex; } else { - cur->goal_gender = UnitInfo::NEUTRAL; + cur->goal_gender = df::pronoun_type::it; } cur->achieved_goal = Units::isGoalAchieved(unit); @@ -2021,13 +2021,13 @@ void viewscreen_unitlaborsst::render() fg = cur->color; detail_str = cur->profession; } else { - if (cur->goal_gender == UnitInfo::NEUTRAL) { + if (cur->goal_gender == df::pronoun_type::it) { if (cur->achieved_goal) { fg = COLOR_LIGHTGREEN; } else { fg = COLOR_BROWN; } - } else if (cur->goal_gender == UnitInfo::FEMALE) { + } else if (cur->goal_gender == df::pronoun_type::she) { if (cur->achieved_goal) { fg = COLOR_LIGHTRED; } From cb1b751988666bdca41d5e5e9ebb53f613a4decb Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 00:31:28 -0400 Subject: [PATCH 08/18] Update submodules --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index daa353138..ce21a92c0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit daa3531384c6d222c7a28f6a73de3201a27f391d +Subproject commit ce21a92c03a5a512c740917cdff85eadf5c4fdd0 diff --git a/scripts b/scripts index 823d47c4d..f732c1e4b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 823d47c4d181ac5b754dce5d605f3e7f242aed26 +Subproject commit f732c1e4b3c7c7577b2fc07e1655b81a24340ae3 From 6a1f046995391e383d28b590126c8367128892db Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 00:31:33 -0400 Subject: [PATCH 09/18] Add --sizecheck option to Linux launcher script, update docs --- docs/Memory-research.rst | 19 +++++++++++++++---- package/linux/dfhack | 5 +++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/Memory-research.rst b/docs/Memory-research.rst index 41aa437c8..3f615750a 100644 --- a/docs/Memory-research.rst +++ b/docs/Memory-research.rst @@ -86,10 +86,13 @@ You should not count on DF being stable when using this. DFHack's implementation of sizecheck is currently only tested on Linux, although it probably also works on macOS. It can be built with the ``BUILD_SIZECHECK`` `CMake option `, which produces a ``libsizecheck`` -library installed in the ``hack`` folder. You will need to preload this library -manually, by setting ``PRELOAD_LIB`` on Linux (or ``LD_PRELOAD`` if editing -the ``dfhack`` launcher script directly), or by editing the ``dfhack`` -launcher script and adding the library to ``DYLD_INSERT_LIBRARIES`` on macOS. +library installed in the ``hack`` folder. On Linux, passing ``--sc`` as the +first argument to the ``dfhack`` launcher script will load this library on +startup. On other platforms, or when passing a different argument to the +launcher (such as for `linux-gdb`), you will need to preload this library +manually, by setting ``PRELOAD_LIB`` on Linux (or ``LD_PRELOAD`` if editing the +``dfhack`` launcher script directly), or by editing the ``dfhack`` launcher +script and adding the library to ``DYLD_INSERT_LIBRARIES`` on macOS. There is also an older sizecheck implementation by Mifki available on `GitHub `__ (``b.cpp`` is the main @@ -129,6 +132,14 @@ Some basic GDB commands: See the `official GDB documentation `_ for more details. +Other analysis tools +-------------------- + +The ``dfhack`` launcher script on Linux has support for launching several other +tools alongside DFHack, including Valgrind (as well as Callgrind and Helgrind) +and strace. See the script for the exact command-line option to specify. Note +that currently only one tool at a time is supported, and must be specified +with the first argument to the script. df-structures GUI ----------------- diff --git a/package/linux/dfhack b/package/linux/dfhack index b63c3a253..6b542f405 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -146,6 +146,11 @@ case "$1" in exec setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" # script does not resume ;; + --sc | --sizecheck) + PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libsizecheck.so" + MALLOC_PERTURB_=45 setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" + ret=$? + ;; *) setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" ret=$? From a28e9393704d4de58760b06b87e564105df183d8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 00:45:57 -0400 Subject: [PATCH 10/18] Recalculate size after toggling columns (goals can be longer than professions) --- plugins/manipulator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index 28b946be2..b333afae5 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -1769,7 +1769,7 @@ void viewscreen_unitlaborsst::feed(set *events) std::stable_sort(units.begin(), units.end(), sortBySquad); } else if (detail_mode == DETAIL_MODE_JOB) { std::stable_sort(units.begin(), units.end(), sortByJob); - } else if (detail_mode == DETAIL_MODE_PROFESSION){ + } else if (detail_mode == DETAIL_MODE_PROFESSION) { std::stable_sort(units.begin(), units.end(), sortByProfession); } else { std::stable_sort(units.begin(), units.end(), sortByGoal); @@ -1818,6 +1818,7 @@ void viewscreen_unitlaborsst::feed(set *events) } else { detail_mode = DETAIL_MODE_PROFESSION; } + calcSize(); } if (events->count(interface_key::CUSTOM_SHIFT_X)) @@ -2202,7 +2203,7 @@ void viewscreen_unitlaborsst::render() OutputString(15, x, y, "Squad"); } else if (detail_mode == DETAIL_MODE_JOB) { OutputString(15, x, y, "Job"); - } else if (detail_mode == DETAIL_MODE_PROFESSION){ + } else if (detail_mode == DETAIL_MODE_PROFESSION) { OutputString(15, x, y, "Profession"); } else { OutputString(15, x, y, "Goal"); From 3b3b0be8c584eb7ba3ee33d4004ad1aadc3eb300 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 02:00:12 -0400 Subject: [PATCH 11/18] Update submodules, tweak changelog order --- docs/changelog.txt | 2 +- library/xml | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index f5bdb42b3..e033f393b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,6 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `RemoteFortressReader`: fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) ## Misc Improvements +- Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) - `blueprint`: now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder - `blueprint`: now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist - `confirm`: added a confirmation dialog for convicting dwarves of crimes @@ -58,7 +59,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()`` ## Internals -- Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) - Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls` ## Lua diff --git a/library/xml b/library/xml index ce21a92c0..23e076b70 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ce21a92c03a5a512c740917cdff85eadf5c4fdd0 +Subproject commit 23e076b7079a48b91c59451be64319dd36476994 diff --git a/scripts b/scripts index f732c1e4b..933849569 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f732c1e4b3c7c7577b2fc07e1655b81a24340ae3 +Subproject commit 9338495695c3892b8ce407b71a79059b39624334 From 13380008c4959fc21b94a91cf09961a785c48f63 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 13:28:31 -0400 Subject: [PATCH 12/18] Update scripts, authors, changelog --- docs/Authors.rst | 4 ++-- docs/changelog.txt | 10 ++++++++++ docs/sphinx_extensions/dfhack/changelog.py | 1 + scripts | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/Authors.rst b/docs/Authors.rst index a9036a33c..42fda0985 100644 --- a/docs/Authors.rst +++ b/docs/Authors.rst @@ -60,7 +60,6 @@ Ian S kremlin- IndigoFenix James Gilles kazimuth James Logsdon jlogsdon -Japa JapaMala Jared Adams Jeremy Apthorp nornagon Jim Lisi stonetoad @@ -136,6 +135,7 @@ Robert Janetzko robertjanetzko RocheLimit rofl0r rofl0r root +Rose RosaryMala Roses Pheosics Ross M RossM rout @@ -173,7 +173,7 @@ U-glouglou\\simon Valentin Ochs Cat-Ion Vitaly Pronkin pronvit mifki ViTuRaS ViTuRaS -Vjek +Vjek vjek Warmist warmist Wes Malone wesQ3 Will Rogers wjrogers diff --git a/docs/changelog.txt b/docs/changelog.txt index e033f393b..00c7fafcb 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -46,12 +46,17 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `embark-assistant`: fixed a couple of incursion handling bugs. - Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste - `RemoteFortressReader`: fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) +- `RemoteFortressReader`: fixed an issue that could cause block coordinates to be incorrect +- `rendermax`: fixed a hang that could occur when enabling some renderers, notably on Linux +- `stonesense`: fixed a crash when launching Stonesense +- `stonesense`: fixed some issues that could cause the splash screen to hang ## Misc Improvements - Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) - `blueprint`: now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder - `blueprint`: now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist - `confirm`: added a confirmation dialog for convicting dwarves of crimes +- `manipulator`: added a new column option to display units' goals ## API - Added ``Filesystem::mkdir_recursive`` @@ -67,6 +72,11 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Ruby - Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens +## Documentation +- Expanded the installation guide +- Added some new dev-facing pages, including dedicated pages about the remote API, memory research, and documentation +- Made a couple theme adjustments + # 0.47.04-r1 ## Fixes diff --git a/docs/sphinx_extensions/dfhack/changelog.py b/docs/sphinx_extensions/dfhack/changelog.py index 6f444d36f..d38f8c060 100644 --- a/docs/sphinx_extensions/dfhack/changelog.py +++ b/docs/sphinx_extensions/dfhack/changelog.py @@ -29,6 +29,7 @@ CHANGELOG_SECTIONS = [ 'Lua', 'Ruby', 'Structures', + 'Documentation', ] REPLACEMENTS = { diff --git a/scripts b/scripts index 933849569..155b00ab6 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 9338495695c3892b8ce407b71a79059b39624334 +Subproject commit 155b00ab65dd9a1efc56c34c1238a68dce80fe5d From 8f047530c49094545f580d250587c0b6cae5ba5a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:28:17 -0400 Subject: [PATCH 13/18] Make Units::getRaceNameById and other ID-related functions available to Lua --- docs/changelog.txt | 1 + library/LuaApi.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 00c7fafcb..f1c423da2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -68,6 +68,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - Added a ``ref_target`` field to primitive field references, corresponding to the ``ref-target`` XML attribute +- Made ``dfhack.units.getRaceNameById()``, ``dfhack.units.getRaceBabyNameById()``, and ``dfhack.units.getRaceChildNameById()`` available to Lua ## Ruby - Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 13c9386ff..78364083f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1617,8 +1617,11 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getPhysicalDescription), WRAPM(Units, getRaceName), WRAPM(Units, getRaceNamePlural), + WRAPM(Units, getRaceNameById), WRAPM(Units, getRaceBabyName), + WRAPM(Units, getRaceBabyNameById), WRAPM(Units, getRaceChildName), + WRAPM(Units, getRaceChildNameById), WRAPM(Units, isBaby), WRAPM(Units, isChild), WRAPM(Units, isAdult), From 7ee58ada7b976272e07af280a3567f1976088795 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:29:24 -0400 Subject: [PATCH 14/18] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 155b00ab6..385950715 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 155b00ab65dd9a1efc56c34c1238a68dce80fe5d +Subproject commit 385950715a4cd8b62d57bf35d7e25c4025fd3f25 From 8c5b21b7eec7f6d41e6156b4a011c92486c62505 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:34:47 -0400 Subject: [PATCH 15/18] Fix a couple warnings in the Units module (#1615) --- library/include/modules/Units.h | 6 +++--- library/modules/Units.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index c719a60a9..e2d34254d 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -181,9 +181,9 @@ DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profes DFHACK_EXPORT int8_t getProfessionColor(df::unit *unit, bool ignore_noble = false); DFHACK_EXPORT int8_t getCasteProfessionColor(int race, int caste, df::profession pid); -DFHACK_EXPORT df::goal_type getGoalType(df::unit *unit, int goalIndex = 0); -DFHACK_EXPORT std::string getGoalName(df::unit *unit, int goalIndex = 0); -DFHACK_EXPORT bool isGoalAchieved(df::unit *unit, int goalIndex = 0); +DFHACK_EXPORT df::goal_type getGoalType(df::unit *unit, size_t goalIndex = 0); +DFHACK_EXPORT std::string getGoalName(df::unit *unit, size_t goalIndex = 0); +DFHACK_EXPORT bool isGoalAchieved(df::unit *unit, size_t goalIndex = 0); DFHACK_EXPORT std::string getSquadName(df::unit *unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index d5c871f5b..a8f96b29f 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1439,7 +1439,7 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid) return 3; } -df::goal_type Units::getGoalType(df::unit *unit, int goalIndex) +df::goal_type Units::getGoalType(df::unit *unit, size_t goalIndex) { CHECK_NULL_POINTER(unit); @@ -1452,7 +1452,7 @@ df::goal_type Units::getGoalType(df::unit *unit, int goalIndex) return goal; } -std::string Units::getGoalName(df::unit *unit, int goalIndex) +std::string Units::getGoalName(df::unit *unit, size_t goalIndex) { CHECK_NULL_POINTER(unit); @@ -1471,7 +1471,7 @@ std::string Units::getGoalName(df::unit *unit, int goalIndex) return goal_name; } -bool Units::isGoalAchieved(df::unit *unit, int goalIndex) +bool Units::isGoalAchieved(df::unit *unit, size_t goalIndex) { CHECK_NULL_POINTER(unit); From 73ba692f15f35bf9e9ea2452b280e4bed694f9e6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:46:42 -0400 Subject: [PATCH 16/18] Fix road building (#1596) Paved roads need architecture before road building --- plugins/labormanager/joblabormapper.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/labormanager/joblabormapper.cpp b/plugins/labormanager/joblabormapper.cpp index 4a71b40bf..6a97aa75f 100644 --- a/plugins/labormanager/joblabormapper.cpp +++ b/plugins/labormanager/joblabormapper.cpp @@ -200,6 +200,8 @@ static df::building* get_building_from_job(df::job* j) static df::unit_labor construction_build_labor(df::building_actual* b) { + if (b->getType() == df::building_type::RoadPaved) + return df::unit_labor::BUILD_ROAD; // Find last item in building with use mode appropriate to the building's constructions state // For screw pumps contained_items[0] = pipe, 1 corkscrew, 2 block // For wells 0 mechanism, 1 rope, 2 bucket, 3 block @@ -332,6 +334,7 @@ public: case df::building_type::Bridge: case df::building_type::ArcheryTarget: case df::building_type::WaterWheel: + case df::building_type::RoadPaved: case df::building_type::Well: case df::building_type::ScrewPump: case df::building_type::Wagon: @@ -345,8 +348,6 @@ public: return construction_build_labor(b); } break; - case df::building_type::RoadPaved: - return df::unit_labor::BUILD_ROAD; case df::building_type::FarmPlot: return df::unit_labor::PLANT; case df::building_type::Chair: From 504b0c1ec7f748789b01773003afcb292a756727 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:47:59 -0400 Subject: [PATCH 17/18] Update changelog (#1596) --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index f1c423da2..f147e2a67 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -43,6 +43,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Linux: fixed ``dfhack.getDFPath()`` (Lua) and ``Process::getPath()`` (C++) to always return the DF root path, even if the working directory has changed - `getplants`: fixed issues causing plants to be collected even if they have no growths (or unripe growths) - `labormanager`: fixed handling of new jobs in 0.47 +- `labormanager`: fixed an issue preventing custom furnaces from being built - `embark-assistant`: fixed a couple of incursion handling bugs. - Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste - `RemoteFortressReader`: fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) From f2b0f012c9895aa3fd743ad50fab9e6fb78b479d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 8 Aug 2020 14:53:24 -0400 Subject: [PATCH 18/18] Bump to 0.47.04-r2 --- CMakeLists.txt | 2 +- docs/changelog.txt | 2 ++ library/xml | 2 +- scripts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 44d6a02ce..cd06587eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ endif() # set up versioning. set(DF_VERSION "0.47.04") -set(DFHACK_RELEASE "r1") +set(DFHACK_RELEASE "r2") set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index f147e2a67..9317df86e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -33,6 +33,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future +# 0.47.04-r2 + ## New Tweaks - `tweak` do-job-now: adds a job priority toggle to the jobs list - `tweak` reaction-gloves: adds an option to make reactions produce gloves in sets with correct handedness diff --git a/library/xml b/library/xml index 23e076b70..036b662a1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 23e076b7079a48b91c59451be64319dd36476994 +Subproject commit 036b662a1bbc96b4911f3cbe74dfa1243b6459bc diff --git a/scripts b/scripts index 385950715..568c586ce 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 385950715a4cd8b62d57bf35d7e25c4025fd3f25 +Subproject commit 568c586ce2474af89c64a4cc7c876edb35931d43