Merge remote-tracking branch 'upstream/develop' into quickfort_userguide

develop
Myk Taylor 2020-08-09 08:56:30 -07:00
commit a6c0d8f196
14 changed files with 223 additions and 21 deletions

@ -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}")

@ -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,12 +135,14 @@ Robert Janetzko robertjanetzko
RocheLimit
rofl0r rofl0r
root
Rose RosaryMala
Roses Pheosics
Ross M RossM
rout
rubybrowncoat rubybrowncoat
Rumrusher rumrusher
RusAnon RusAnon
Ryan Bennitt ryanbennitt
sami
scamtank scamtank
Sebastian Wolfertz Enkrod
@ -172,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

@ -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.

@ -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 <compile-build-options>`, 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 <https://github.com/mifki/df-sizecheck>`__ (``b.cpp`` is the main
@ -129,6 +132,14 @@ Some basic GDB commands:
See the `official GDB documentation <https://www.gnu.org/software/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
-----------------

@ -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
@ -43,29 +45,42 @@ 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``)
- `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``
- 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)
- Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls`
## 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
## 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

@ -29,6 +29,7 @@ CHANGELOG_SECTIONS = [
'Lua',
'Ruby',
'Structures',
'Documentation',
]
REPLACEMENTS = {

@ -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),
@ -1614,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),

@ -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, 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);
DFHACK_EXPORT df::activity_entry *getMainSocialActivity(df::unit *unit);

@ -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"
@ -1438,6 +1439,47 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid)
return 3;
}
df::goal_type Units::getGoalType(df::unit *unit, size_t 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, size_t goalIndex)
{
CHECK_NULL_POINTER(unit);
df::goal_type goal = getGoalType(unit, goalIndex);
bool achieved_goal = isGoalAchieved(unit, goalIndex);
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, size_t 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);

@ -1 +1 @@
Subproject commit 9fca46ccca28e0948014b9d56a096ad7343473f1
Subproject commit 036b662a1bbc96b4911f3cbe74dfa1243b6459bc

@ -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=$?

@ -313,9 +313,23 @@ 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:
@ -418,15 +432,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:
@ -437,6 +462,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::Trap:

@ -32,6 +32,8 @@
#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"
@ -287,6 +289,9 @@ struct UnitInfo
string name;
string transname;
string profession;
string goal;
df::pronoun_type goal_gender;
bool achieved_goal;
int8_t color;
int active_index;
string squad_effective_name;
@ -310,7 +315,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 +354,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 +604,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 +1260,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 = unit->sex;
} else {
cur->goal_gender = df::pronoun_type::it;
}
cur->achieved_goal = Units::isGoalAchieved(unit);
if (unit->job.current_job == NULL) {
df::activity_event *event = Units::getMainSocialEvent(unit);
@ -1298,8 +1329,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 +1769,10 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *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,10 +1812,13 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *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;
}
calcSize();
}
if (events->count(interface_key::CUSTOM_SHIFT_X))
@ -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 == df::pronoun_type::it) {
if (cur->achieved_goal) {
fg = COLOR_LIGHTGREEN;
} else {
fg = COLOR_BROWN;
}
} else if (cur->goal_gender == df::pronoun_type::she) {
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:

@ -1 +1 @@
Subproject commit 823d47c4d181ac5b754dce5d605f3e7f242aed26
Subproject commit 568c586ce2474af89c64a4cc7c876edb35931d43