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 up versioning.
set(DF_VERSION "0.47.04") set(DF_VERSION "0.47.04")
set(DFHACK_RELEASE "r1") set(DFHACK_RELEASE "r2")
set(DFHACK_PRERELEASE FALSE) set(DFHACK_PRERELEASE FALSE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")

@ -60,7 +60,6 @@ Ian S kremlin-
IndigoFenix IndigoFenix
James Gilles kazimuth James Gilles kazimuth
James Logsdon jlogsdon James Logsdon jlogsdon
Japa JapaMala
Jared Adams Jared Adams
Jeremy Apthorp nornagon Jeremy Apthorp nornagon
Jim Lisi stonetoad Jim Lisi stonetoad
@ -136,12 +135,14 @@ Robert Janetzko robertjanetzko
RocheLimit RocheLimit
rofl0r rofl0r rofl0r rofl0r
root root
Rose RosaryMala
Roses Pheosics Roses Pheosics
Ross M RossM Ross M RossM
rout rout
rubybrowncoat rubybrowncoat rubybrowncoat rubybrowncoat
Rumrusher rumrusher Rumrusher rumrusher
RusAnon RusAnon RusAnon RusAnon
Ryan Bennitt ryanbennitt
sami sami
scamtank scamtank scamtank scamtank
Sebastian Wolfertz Enkrod Sebastian Wolfertz Enkrod
@ -172,7 +173,7 @@ U-glouglou\\simon
Valentin Ochs Cat-Ion Valentin Ochs Cat-Ion
Vitaly Pronkin pronvit mifki Vitaly Pronkin pronvit mifki
ViTuRaS ViTuRaS ViTuRaS ViTuRaS
Vjek Vjek vjek
Warmist warmist Warmist warmist
Wes Malone wesQ3 Wes Malone wesQ3
Will Rogers wjrogers Will Rogers wjrogers

@ -1277,6 +1277,30 @@ Units module
Retrieves the profession color for the given race/caste using raws. 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)`` * ``dfhack.units.getStressCategory(unit)``
Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. 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 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`` it probably also works on macOS. It can be built with the ``BUILD_SIZECHECK``
`CMake option <compile-build-options>`, which produces a ``libsizecheck`` `CMake option <compile-build-options>`, which produces a ``libsizecheck``
library installed in the ``hack`` folder. You will need to preload this library library installed in the ``hack`` folder. On Linux, passing ``--sc`` as the
manually, by setting ``PRELOAD_LIB`` on Linux (or ``LD_PRELOAD`` if editing first argument to the ``dfhack`` launcher script will load this library on
the ``dfhack`` launcher script directly), or by editing the ``dfhack`` startup. On other platforms, or when passing a different argument to the
launcher script and adding the library to ``DYLD_INSERT_LIBRARIES`` on macOS. 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 There is also an older sizecheck implementation by Mifki available on
`GitHub <https://github.com/mifki/df-sizecheck>`__ (``b.cpp`` is the main `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/>`_ See the `official GDB documentation <https://www.gnu.org/software/gdb/documentation/>`_
for more details. 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 df-structures GUI
----------------- -----------------

@ -33,6 +33,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# Future # Future
# 0.47.04-r2
## New Tweaks ## New Tweaks
- `tweak` do-job-now: adds a job priority toggle to the jobs list - `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 - `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 - 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) - `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 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. - `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 - 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 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 ## 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 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 - `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 - `confirm`: added a confirmation dialog for convicting dwarves of crimes
- `manipulator`: added a new column option to display units' goals
## API ## API
- Added ``Filesystem::mkdir_recursive`` - Added ``Filesystem::mkdir_recursive``
- Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory - Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory
- ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()``
## Internals ## 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` - Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls`
## Lua ## Lua
- Added a ``ref_target`` field to primitive field references, corresponding to the ``ref-target`` XML attribute - 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 ## Ruby
- Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens - 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 # 0.47.04-r1
## Fixes ## Fixes

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

@ -1604,6 +1604,9 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getCasteProfessionName), WRAPM(Units, getCasteProfessionName),
WRAPM(Units, getProfessionColor), WRAPM(Units, getProfessionColor),
WRAPM(Units, getCasteProfessionColor), WRAPM(Units, getCasteProfessionColor),
WRAPM(Units, getGoalType),
WRAPM(Units, getGoalName),
WRAPM(Units, isGoalAchieved),
WRAPM(Units, getSquadName), WRAPM(Units, getSquadName),
WRAPM(Units, isWar), WRAPM(Units, isWar),
WRAPM(Units, isHunter), WRAPM(Units, isHunter),
@ -1614,8 +1617,11 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getPhysicalDescription), WRAPM(Units, getPhysicalDescription),
WRAPM(Units, getRaceName), WRAPM(Units, getRaceName),
WRAPM(Units, getRaceNamePlural), WRAPM(Units, getRaceNamePlural),
WRAPM(Units, getRaceNameById),
WRAPM(Units, getRaceBabyName), WRAPM(Units, getRaceBabyName),
WRAPM(Units, getRaceBabyNameById),
WRAPM(Units, getRaceChildName), WRAPM(Units, getRaceChildName),
WRAPM(Units, getRaceChildNameById),
WRAPM(Units, isBaby), WRAPM(Units, isBaby),
WRAPM(Units, isChild), WRAPM(Units, isChild),
WRAPM(Units, isAdult), WRAPM(Units, isAdult),

@ -32,6 +32,7 @@ distribution.
#include "DataDefs.h" #include "DataDefs.h"
#include "df/caste_raw_flags.h" #include "df/caste_raw_flags.h"
#include "df/goal_type.h"
#include "df/job_skill.h" #include "df/job_skill.h"
#include "df/mental_attribute_type.h" #include "df/mental_attribute_type.h"
#include "df/misc_trait_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 getProfessionColor(df::unit *unit, bool ignore_noble = false);
DFHACK_EXPORT int8_t getCasteProfessionColor(int race, int caste, df::profession pid); 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 std::string getSquadName(df::unit *unit);
DFHACK_EXPORT df::activity_entry *getMainSocialActivity(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/identity_type.h"
#include "df/game_mode.h" #include "df/game_mode.h"
#include "df/histfig_entity_link_positionst.h" #include "df/histfig_entity_link_positionst.h"
#include "df/histfig_relationship_type.h"
#include "df/historical_entity.h" #include "df/historical_entity.h"
#include "df/historical_figure.h" #include "df/historical_figure.h"
#include "df/historical_figure_info.h" #include "df/historical_figure_info.h"
@ -1438,6 +1439,47 @@ int8_t Units::getCasteProfessionColor(int race, int casteid, df::profession pid)
return 3; 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) std::string Units::getSquadName(df::unit *unit)
{ {
CHECK_NULL_POINTER(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 "$@" exec setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@"
# script does not resume # 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 "$@" setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@"
ret=$? ret=$?

@ -313,9 +313,23 @@ public:
return workshop_build_labor[ws->type]; return workshop_build_labor[ws->type];
} }
break; 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: case df::building_type::Construction:
return df::unit_labor::BUILD_CONSTRUCTION; return df::unit_labor::BUILD_CONSTRUCTION;
case df::building_type::Furnace:
case df::building_type::TradeDepot: case df::building_type::TradeDepot:
case df::building_type::Bridge: case df::building_type::Bridge:
case df::building_type::ArcheryTarget: case df::building_type::ArcheryTarget:
@ -418,15 +432,26 @@ public:
return workshop_build_labor[ws->type]; return workshop_build_labor[ws->type];
} }
break; 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: case df::building_type::Construction:
return df::unit_labor::REMOVE_CONSTRUCTION; return df::unit_labor::REMOVE_CONSTRUCTION;
case df::building_type::Furnace:
case df::building_type::TradeDepot: case df::building_type::TradeDepot:
case df::building_type::Wagon: case df::building_type::Wagon:
case df::building_type::Bridge: case df::building_type::Bridge:
case df::building_type::ScrewPump: case df::building_type::ScrewPump:
case df::building_type::ArcheryTarget: case df::building_type::ArcheryTarget:
case df::building_type::RoadPaved:
case df::building_type::Shop: case df::building_type::Shop:
case df::building_type::Support: case df::building_type::Support:
case df::building_type::WaterWheel: case df::building_type::WaterWheel:
@ -437,6 +462,8 @@ public:
return construction_build_labor(b); return construction_build_labor(b);
} }
break; break;
case df::building_type::RoadPaved:
return df::unit_labor::BUILD_ROAD;
case df::building_type::FarmPlot: case df::building_type::FarmPlot:
return df::unit_labor::PLANT; return df::unit_labor::PLANT;
case df::building_type::Trap: case df::building_type::Trap:

@ -32,6 +32,8 @@
#include "df/caste_raw.h" #include "df/caste_raw.h"
#include "df/historical_entity.h" #include "df/historical_entity.h"
#include "df/entity_raw.h" #include "df/entity_raw.h"
#include "df/goal_type.h"
#include "df/unit_personality.h"
#include "uicommon.h" #include "uicommon.h"
#include "listcolumn.h" #include "listcolumn.h"
@ -287,6 +289,9 @@ struct UnitInfo
string name; string name;
string transname; string transname;
string profession; string profession;
string goal;
df::pronoun_type goal_gender;
bool achieved_goal;
int8_t color; int8_t color;
int active_index; int active_index;
string squad_effective_name; string squad_effective_name;
@ -310,7 +315,8 @@ struct UnitInfo
enum detail_cols { enum detail_cols {
DETAIL_MODE_PROFESSION, DETAIL_MODE_PROFESSION,
DETAIL_MODE_SQUAD, DETAIL_MODE_SQUAD,
DETAIL_MODE_JOB DETAIL_MODE_JOB,
DETAIL_MODE_GOAL
}; };
enum altsort_mode { enum altsort_mode {
ALTSORT_NAME, ALTSORT_NAME,
@ -348,6 +354,21 @@ bool sortByProfession (const UnitInfo *d1, const UnitInfo *d2)
return (d1->profession < d2->profession); 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 sortBySquad (const UnitInfo *d1, const UnitInfo *d2)
{ {
bool gt = false; bool gt = false;
@ -583,6 +604,8 @@ namespace unit_ops {
} }
string get_profname(UnitInfo *u) string get_profname(UnitInfo *u)
{ return Units::getProfessionName(u->unit); } { return Units::getProfessionName(u->unit); }
string get_goalname(UnitInfo *u)
{ return Units::getGoalName(u->unit); }
string get_real_profname(UnitInfo *u) string get_real_profname(UnitInfo *u)
{ {
string tmp = u->unit->custom_profession; string tmp = u->unit->custom_profession;
@ -1237,6 +1260,14 @@ void viewscreen_unitlaborsst::refreshNames()
cur->name = Translation::TranslateName(Units::getVisibleName(unit), false); cur->name = Translation::TranslateName(Units::getVisibleName(unit), false);
cur->transname = Translation::TranslateName(Units::getVisibleName(unit), true); cur->transname = Translation::TranslateName(Units::getVisibleName(unit), true);
cur->profession = Units::getProfessionName(unit); 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) { if (unit->job.current_job == NULL) {
df::activity_event *event = Units::getMainSocialEvent(unit); df::activity_event *event = Units::getMainSocialEvent(unit);
@ -1298,8 +1329,10 @@ void viewscreen_unitlaborsst::calcSize()
detail_cmp = units[i]->squad_info.size(); detail_cmp = units[i]->squad_info.size();
} else if (detail_mode == DETAIL_MODE_JOB) { } else if (detail_mode == DETAIL_MODE_JOB) {
detail_cmp = units[i]->job_desc.size(); detail_cmp = units[i]->job_desc.size();
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
detail_cmp = units[i]->profession.size(); detail_cmp = units[i]->profession.size();
} else {
detail_cmp = units[i]->goal.size();
} }
if (size_t(col_maxwidth[DISP_COLUMN_DETAIL]) < detail_cmp) if (size_t(col_maxwidth[DISP_COLUMN_DETAIL]) < detail_cmp)
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); std::stable_sort(units.begin(), units.end(), sortBySquad);
} else if (detail_mode == DETAIL_MODE_JOB) { } else if (detail_mode == DETAIL_MODE_JOB) {
std::stable_sort(units.begin(), units.end(), sortByJob); std::stable_sort(units.begin(), units.end(), sortByJob);
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
std::stable_sort(units.begin(), units.end(), sortByProfession); std::stable_sort(units.begin(), units.end(), sortByProfession);
} else {
std::stable_sort(units.begin(), units.end(), sortByGoal);
} }
break; break;
case ALTSORT_STRESS: case ALTSORT_STRESS:
@ -1777,10 +1812,13 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
if (detail_mode == DETAIL_MODE_SQUAD) { if (detail_mode == DETAIL_MODE_SQUAD) {
detail_mode = DETAIL_MODE_JOB; detail_mode = DETAIL_MODE_JOB;
} else if (detail_mode == DETAIL_MODE_JOB) { } else if (detail_mode == DETAIL_MODE_JOB) {
detail_mode = DETAIL_MODE_PROFESSION; detail_mode = DETAIL_MODE_GOAL;
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
detail_mode = DETAIL_MODE_SQUAD; detail_mode = DETAIL_MODE_SQUAD;
} else {
detail_mode = DETAIL_MODE_PROFESSION;
} }
calcSize();
} }
if (events->count(interface_key::CUSTOM_SHIFT_X)) if (events->count(interface_key::CUSTOM_SHIFT_X))
@ -1888,8 +1926,10 @@ void viewscreen_unitlaborsst::render()
detail_str = "Squad"; detail_str = "Squad";
} else if (detail_mode == DETAIL_MODE_JOB) { } else if (detail_mode == DETAIL_MODE_JOB) {
detail_str = "Job"; detail_str = "Job";
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
detail_str = "Profession"; detail_str = "Profession";
} else {
detail_str = "Goal";
} }
Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_DETAIL], 2, detail_str); Screen::paintString(Screen::Pen(' ', 7, 0), col_offsets[DISP_COLUMN_DETAIL], 2, detail_str);
@ -1978,9 +2018,32 @@ void viewscreen_unitlaborsst::render()
} else { } else {
fg = COLOR_LIGHTCYAN; fg = COLOR_LIGHTCYAN;
} }
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
fg = cur->color; fg = cur->color;
detail_str = cur->profession; 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]); detail_str.resize(col_widths[DISP_COLUMN_DETAIL]);
Screen::paintString(Screen::Pen(' ', fg, bg), col_offsets[DISP_COLUMN_DETAIL], 4 + row, detail_str); 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"); OutputString(15, x, y, "Squad");
} else if (detail_mode == DETAIL_MODE_JOB) { } else if (detail_mode == DETAIL_MODE_JOB) {
OutputString(15, x, y, "Job"); OutputString(15, x, y, "Job");
} else { } else if (detail_mode == DETAIL_MODE_PROFESSION) {
OutputString(15, x, y, "Profession"); OutputString(15, x, y, "Profession");
} else {
OutputString(15, x, y, "Goal");
} }
break; break;
case ALTSORT_STRESS: case ALTSORT_STRESS:

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