Add a few more lua api functions, documentation, and unit sort orders.

Units::getProfessionName appears to work correctly for
everything except nobles.
develop
Alexander Gavrilov 2012-04-23 21:30:53 +04:00
parent 125cd6622a
commit 763a301b4f
9 changed files with 449 additions and 80 deletions

@ -594,41 +594,44 @@ C++ function wrappers
=====================
Thin wrappers around C++ functions, similar to the ones for virtual methods.
One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted.
* ``dfhack.TranslateName(name,in_english,only_last_name)``
* ``dfhack.TranslateName(name[,in_english,only_last_name])``
Convert a language_name or only the last name part to string.
Gui module
----------
* ``dfhack.gui.getSelectedWorkshopJob(silent)``
* ``dfhack.gui.getSelectedWorkshopJob([silent])``
When a job is selected in *'q'* mode, returns the job, else
prints error unless silent and returns *nil*.
* ``dfhack.gui.getSelectedJob(silent)``
* ``dfhack.gui.getSelectedJob([silent])``
Returns the job selected in a workshop or unit/jobs screen.
* ``dfhack.gui.getSelectedUnit(silent)``
* ``dfhack.gui.getSelectedUnit([silent])``
Returns the unit selected via *'v'*, *'k'*, unit/jobs, or
a full-screen item view of a cage or suchlike.
* ``dfhack.gui.getSelectedItem(silent)``
* ``dfhack.gui.getSelectedItem([silent])``
Returns the item selected via *'v'* ->inventory, *'k'*, *'t'*, or
a full-screen item view of a container. Note that in the
last case, the highlighted *contained item* is returned, not
the container itself.
* ``dfhack.gui.showAnnouncement(text,color,is_bright)``
* ``dfhack.gui.showAnnouncement(text,color[,is_bright])``
Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.
* ``dfhack.gui.showPopupAnnouncement(text,color,is_bright)``
* ``dfhack.gui.showPopupAnnouncement(text,color[,is_bright])``
Pops up a titan-style modal announcement window.
@ -688,6 +691,10 @@ Units module
Returns the language_name object visible in game, accounting for false identities.
* ``dfhack.units.getIdentity(unit)``
Returns the false identity of the unit if it has one, or *nil*.
* ``dfhack.units.getNemesis(unit)``
Returns the nemesis record of the unit if it has one, or *nil*.
@ -716,6 +723,19 @@ Units module
Adds or removes the unit from the burrow.
* ``dfhack.units.getAge(unit[,true_age])``
Returns the age of the unit in years as a floating-point value.
If ``true_age`` is true, ignores false identities.
* ``dfhack.units.getProfessionName(unit[,plural])``
Retrieves the profession name using custom profession or raws.
* ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])``
Retrieves the profession name for the given race/caste using raws.
Items module
------------
@ -856,3 +876,66 @@ Features:
Invokes all listeners contained in the event in an arbitrary
order using ``dfhack.safecall``.
=======
Plugins
=======
DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
``mkmodule('plugins.<name>')``; this means that a lua
module file is still necessary for ``require`` to read.
The following plugins have lua support.
burrows
=======
Implements extended burrow manipulations.
Events:
* ``onBurrowRename.foo = function(burrow)``
Emitted when a burrow might have been renamed either through
the game UI, or ``renameBurrow()``.
* ``onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)``
Emitted when a tile might have been dug out. Only tracked if the
auto-growing burrows feature is enabled.
Native functions:
* ``renameBurrow(burrow,name)``
Renames the burrow, emitting ``onBurrowRename`` and updating auto-grow state properly.
* ``findByName(burrow,name)``
Finds a burrow by name, using the same rules as the plugin command line interface.
Namely, trailing ``'+'`` characters marking auto-grow burrows are ignored.
* ``copyUnits(target,source,enable)``
Applies units from ``source`` burrow to ``target``. The ``enable``
parameter specifies if they are to be added or removed.
* ``copyTiles(target,source,enable)``
Applies tiles from ``source`` burrow to ``target``. The ``enable``
parameter specifies if they are to be added or removed.
* ``setTilesByKeyword(target,keyword,enable)``
Adds or removes tiles matching a predefined keyword. The keyword
set is the same as used by the command line.
The lua module file also re-exports or wraps some of the
functions implemented by the dfhack core for convenience.
sort
====
Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.

@ -350,6 +350,11 @@ ul.auto-toc {
</li>
</ul>
</li>
<li><a class="reference internal" href="#plugins" id="id21">Plugins</a><ul>
<li><a class="reference internal" href="#burrows" id="id22">burrows</a></li>
<li><a class="reference internal" href="#sort" id="id23">sort</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="df-structure-wrapper">
@ -842,37 +847,40 @@ Accept dfhack_material_category auto-assign table.</p>
</div>
<div class="section" id="c-function-wrappers">
<h2><a class="toc-backref" href="#id13">C++ function wrappers</a></h2>
<p>Thin wrappers around C++ functions, similar to the ones for virtual methods.</p>
<p>Thin wrappers around C++ functions, similar to the ones for virtual methods.
One notable difference is that these explicit wrappers allow argument count
adjustment according to the usual lua rules, so trailing false/nil arguments
can be omitted.</p>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.TranslateName(name,in_english,only_last_name)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.TranslateName(name[,in_english,only_last_name])</span></tt></p>
<p>Convert a language_name or only the last name part to string.</p>
</li>
</ul>
<div class="section" id="gui-module">
<h3><a class="toc-backref" href="#id14">Gui module</a></h3>
<ul>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedWorkshopJob(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedWorkshopJob([silent])</span></tt></p>
<p>When a job is selected in <em>'q'</em> mode, returns the job, else
prints error unless silent and returns <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedJob(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedJob([silent])</span></tt></p>
<p>Returns the job selected in a workshop or unit/jobs screen.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedUnit(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedUnit([silent])</span></tt></p>
<p>Returns the unit selected via <em>'v'</em>, <em>'k'</em>, unit/jobs, or
a full-screen item view of a cage or suchlike.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.getSelectedItem(silent)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.getSelectedItem([silent])</span></tt></p>
<p>Returns the item selected via <em>'v'</em> -&gt;inventory, <em>'k'</em>, <em>'t'</em>, or
a full-screen item view of a container. Note that in the
last case, the highlighted <em>contained item</em> is returned, not
the container itself.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.showAnnouncement(text,color,is_bright)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Adds a regular announcement with given text, color, and brightness.
The is_bright boolean actually seems to invert the brightness.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.gui.showPopupAnnouncement(text,color,is_bright)</tt></p>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.gui.showPopupAnnouncement(text,color[,is_bright])</span></tt></p>
<p>Pops up a titan-style modal announcement window.</p>
</li>
</ul>
@ -923,6 +931,9 @@ a lua list containing them.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.getVisibleName(unit)</tt></p>
<p>Returns the language_name object visible in game, accounting for false identities.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getIdentity(unit)</tt></p>
<p>Returns the false identity of the unit if it has one, or <em>nil</em>.</p>
</li>
<li><p class="first"><tt class="docutils literal">dfhack.units.getNemesis(unit)</tt></p>
<p>Returns the nemesis record of the unit if it has one, or <em>nil</em>.</p>
</li>
@ -944,6 +955,16 @@ a lua list containing them.</p>
<li><p class="first"><tt class="docutils literal">dfhack.units.setInBurrow(unit,burrow,enable)</tt></p>
<p>Adds or removes the unit from the burrow.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getAge(unit[,true_age])</span></tt></p>
<p>Returns the age of the unit in years as a floating-point value.
If <tt class="docutils literal">true_age</tt> is true, ignores false identities.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getProfessionName(unit[,plural])</span></tt></p>
<p>Retrieves the profession name using custom profession or raws.</p>
</li>
<li><p class="first"><tt class="docutils literal"><span class="pre">dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])</span></tt></p>
<p>Retrieves the profession name for the given race/caste using raws.</p>
</li>
</ul>
</div>
<div class="section" id="items-module">
@ -1061,6 +1082,58 @@ order using <tt class="docutils literal">dfhack.safecall</tt>.</p>
</div>
</div>
</div>
<div class="section" id="plugins">
<h1><a class="toc-backref" href="#id21">Plugins</a></h1>
<p>DFHack plugins may export native functions and events
to lua contexts. They are automatically imported by
<tt class="docutils literal"><span class="pre">mkmodule('plugins.&lt;name&gt;')</span></tt>; this means that a lua
module file is still necessary for <tt class="docutils literal">require</tt> to read.</p>
<p>The following plugins have lua support.</p>
<div class="section" id="burrows">
<h2><a class="toc-backref" href="#id22">burrows</a></h2>
<p>Implements extended burrow manipulations.</p>
<p>Events:</p>
<ul>
<li><p class="first"><tt class="docutils literal">onBurrowRename.foo = function(burrow)</tt></p>
<p>Emitted when a burrow might have been renamed either through
the game UI, or <tt class="docutils literal">renameBurrow()</tt>.</p>
</li>
<li><p class="first"><tt class="docutils literal">onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)</tt></p>
<p>Emitted when a tile might have been dug out. Only tracked if the
auto-growing burrows feature is enabled.</p>
</li>
</ul>
<p>Native functions:</p>
<ul>
<li><p class="first"><tt class="docutils literal">renameBurrow(burrow,name)</tt></p>
<p>Renames the burrow, emitting <tt class="docutils literal">onBurrowRename</tt> and updating auto-grow state properly.</p>
</li>
<li><p class="first"><tt class="docutils literal">findByName(burrow,name)</tt></p>
<p>Finds a burrow by name, using the same rules as the plugin command line interface.
Namely, trailing <tt class="docutils literal">'+'</tt> characters marking auto-grow burrows are ignored.</p>
</li>
<li><p class="first"><tt class="docutils literal">copyUnits(target,source,enable)</tt></p>
<p>Applies units from <tt class="docutils literal">source</tt> burrow to <tt class="docutils literal">target</tt>. The <tt class="docutils literal">enable</tt>
parameter specifies if they are to be added or removed.</p>
</li>
<li><p class="first"><tt class="docutils literal">copyTiles(target,source,enable)</tt></p>
<p>Applies tiles from <tt class="docutils literal">source</tt> burrow to <tt class="docutils literal">target</tt>. The <tt class="docutils literal">enable</tt>
parameter specifies if they are to be added or removed.</p>
</li>
<li><p class="first"><tt class="docutils literal">setTilesByKeyword(target,keyword,enable)</tt></p>
<p>Adds or removes tiles matching a predefined keyword. The keyword
set is the same as used by the command line.</p>
</li>
</ul>
<p>The lua module file also re-exports or wraps some of the
functions implemented by the dfhack core for convenience.</p>
</div>
<div class="section" id="sort">
<h2><a class="toc-backref" href="#id23">sort</a></h2>
<p>Does not export any native functions as of now. Instead, it
calls lua code to perform the actual ordering of list items.</p>
</div>
</div>
</div>
</body>
</html>

@ -58,6 +58,7 @@ distribution.
#include "df/unit.h"
#include "df/item.h"
#include "df/material.h"
#include "df/assumed_identity.h"
#include "df/nemesis_record.h"
#include "df/historical_figure.h"
#include "df/plant_raw.h"
@ -608,6 +609,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, getContainer),
WRAPM(Units, setNickname),
WRAPM(Units, getVisibleName),
WRAPM(Units, getIdentity),
WRAPM(Units, getNemesis),
WRAPM(Units, isDead),
WRAPM(Units, isAlive),
@ -616,6 +618,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = {
WRAPM(Units, isInBurrow),
WRAPM(Units, setInBurrow),
WRAPM(Units, getAge),
WRAPM(Units, getProfessionName),
WRAPM(Units, getCasteProfessionName),
{ NULL, NULL }
};

@ -52,6 +52,8 @@ DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * tar
DFHACK_EXPORT void setNickname(df::language_name *name, std::string nick);
DFHACK_EXPORT std::string capitalize(const std::string &str, bool all_words = false);
// translate a name using the loaded dictionaries
DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true,
bool onlyLastPart = false);

@ -37,6 +37,7 @@ namespace df
{
struct nemesis_record;
struct burrow;
struct assumed_identity;
}
/**
@ -201,6 +202,7 @@ DFHACK_EXPORT df::item *getContainer(df::unit *unit);
DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick);
DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit);
DFHACK_EXPORT df::assumed_identity *getIdentity(df::unit *unit);
DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit);
DFHACK_EXPORT bool isDead(df::unit *unit);
@ -214,8 +216,10 @@ DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow);
DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow);
DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable);
DFHACK_EXPORT double getAge(df::unit *unit);
DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false);
DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool plural = false);
DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profession pid, bool plural = false);
}
}
#endif

@ -125,6 +125,23 @@ function xyz2pos(x,y,z)
end
end
function safe_index(obj,idx,...)
if obj == nil or idx == nil then
return nil
end
if type(idx) == 'number' and (idx < 0 or idx >= #obj) then
return nil
end
obj = obj[idx]
if select('#',...) > 0 then
return safe_index(obj,...)
else
return obj
end
end
-- String conversions
function dfhack.event:__tostring()
return "<event>"
end
@ -168,12 +185,14 @@ function dfhack.interpreter(prompt,hfile,env)
end
local prompt_str = "["..(prompt or 'lua').."]# "
local prompt_cont = string.rep(' ',#prompt_str-4)..">>> "
local prompt_env = {}
local t_prompt
local cmdlinelist = {}
local t_prompt = nil
local vcnt = 1
setmetatable(prompt_env, { __index = env or _G })
local cmdlinelist={}
while true do
local cmdline = dfhack.lineedit(t_prompt or prompt_str, hfile)
@ -182,23 +201,26 @@ function dfhack.interpreter(prompt,hfile,env)
elseif cmdline ~= '' then
local pfix = string.sub(cmdline,1,1)
if pfix == '!' or pfix == '=' then
if not t_prompt and (pfix == '!' or pfix == '=') then
cmdline = 'return '..string.sub(cmdline,2)
else
pfix = nil
end
table.insert(cmdlinelist,cmdline)
local code,err = load(table.concat(cmdlinelist,'\n'), '=(interactive)', 't', prompt_env)
cmdline = table.concat(cmdlinelist,'\n')
if code == nil then
if err:sub(-5)=="<eof>" then
t_prompt="[cont]"
local code,err = load(cmdline, '=(interactive)', 't', prompt_env)
if code == nil then
if not pfix and err:sub(-5)=="<eof>" then
t_prompt=prompt_cont
else
dfhack.printerr(err)
cmdlinelist={}
t_prompt=nil
end
else
cmdlinelist={}
t_prompt=nil

@ -81,15 +81,32 @@ bool Translation::copyName(df::language_name * source, df::language_name * targe
return true;
}
std::string Translation::capitalize(const std::string &str, bool all_words)
{
string upper = str;
if (!upper.empty())
{
upper[0] = toupper(upper[0]);
if (all_words)
{
for (size_t i = 1; i < upper.size(); i++)
if (isspace(upper[i-1]))
upper[i] = toupper(upper[i]);
}
}
return upper;
}
void addNameWord (string &out, const string &word)
{
if (word.empty())
return;
string upper = word;
upper[0] = toupper(upper[0]);
if (out.length() > 0)
out.append(" ");
out.append(upper);
out.append(Translation::capitalize(word));
}
void Translation::setNickname(df::language_name *name, std::string nick)

@ -57,6 +57,8 @@ using namespace std;
#include "df/historical_figure_info.h"
#include "df/assumed_identity.h"
#include "df/burrow.h"
#include "df/creature_raw.h"
#include "df/caste_raw.h"
using namespace DFHack;
using namespace df::enums;
@ -529,6 +531,23 @@ df::item *Units::getContainer(df::unit *unit)
return NULL;
}
static df::assumed_identity *getFigureIdentity(df::historical_figure *figure)
{
if (figure && figure->info && figure->info->reputation)
return df::assumed_identity::find(figure->info->reputation->cur_identity);
return NULL;
}
df::assumed_identity *Units::getIdentity(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
return getFigureIdentity(figure);
}
void Units::setNickname(df::unit *unit, std::string nick)
{
CHECK_NULL_POINTER(unit);
@ -547,12 +566,7 @@ void Units::setNickname(df::unit *unit, std::string nick)
{
Translation::setNickname(&figure->name, nick);
// v0.34.01: added the vampire's assumed identity
if (figure->info && figure->info->reputation)
{
auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity);
if (identity)
if (auto identity = getFigureIdentity(figure))
{
auto id_hfig = df::historical_figure::find(identity->histfig_id);
@ -567,23 +581,13 @@ void Units::setNickname(df::unit *unit, std::string nick)
Translation::setNickname(&identity->name, nick);
}
}
}
}
df::language_name *Units::getVisibleName(df::unit *unit)
{
CHECK_NULL_POINTER(unit);
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
if (figure)
{
// v0.34.01: added the vampire's assumed identity
if (figure->info && figure->info->reputation)
{
auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity);
if (identity)
if (auto identity = getIdentity(unit))
{
auto id_hfig = df::historical_figure::find(identity->histfig_id);
@ -592,8 +596,6 @@ df::language_name *Units::getVisibleName(df::unit *unit)
return &identity->name;
}
}
}
return &unit->name;
}
@ -734,7 +736,7 @@ void DFHack::Units::setInBurrow(df::unit *unit, df::burrow *burrow, bool enable)
}
}
double DFHack::Units::getAge(df::unit *unit)
double DFHack::Units::getAge(df::unit *unit, bool true_age)
{
using df::global::cur_year;
using df::global::cur_year_tick;
@ -748,5 +750,139 @@ double DFHack::Units::getAge(df::unit *unit)
double birth_time = unit->relations.birth_year + unit->relations.birth_time/year_ticks;
double cur_time = *cur_year + *cur_year_tick / year_ticks;
if (!true_age && unit->relations.curse_year >= 0)
{
if (auto identity = getIdentity(unit))
{
if (identity->histfig_id < 0)
birth_time = identity->birth_year + identity->birth_second/year_ticks;
}
}
return cur_time - birth_time;
}
std::string DFHack::Units::getProfessionName(df::unit *unit, bool plural)
{
std::string prof = unit->custom_profession;
if (prof.empty())
prof = getCasteProfessionName(unit->race, unit->caste, unit->profession, plural);
return prof;
}
std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural)
{
std::string prof, race_prefix;
if (pid < 0 || !is_valid_enum_item(pid))
return "";
bool use_race_prefix = (race >= 0 && race != df::global::ui->race_id);
if (auto creature = df::creature_raw::find(race))
{
if (auto caste = vector_get(creature->caste, casteid))
{
race_prefix = caste->caste_name[0];
if (plural)
prof = caste->caste_profession_name.plural[pid];
else
prof = caste->caste_profession_name.singular[pid];
if (prof.empty())
{
switch (pid)
{
case profession::CHILD:
prof = caste->child_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
case profession::BABY:
prof = caste->baby_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
default:
break;
}
}
}
if (race_prefix.empty())
race_prefix = creature->name[0];
if (prof.empty())
{
if (plural)
prof = creature->profession_name.plural[pid];
else
prof = creature->profession_name.singular[pid];
if (prof.empty())
{
switch (pid)
{
case profession::CHILD:
prof = creature->general_child_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
case profession::BABY:
prof = creature->general_baby_name[plural ? 1 : 0];
if (!prof.empty())
use_race_prefix = false;
break;
default:
break;
}
}
}
}
if (race_prefix.empty())
race_prefix = "Animal";
if (prof.empty())
{
switch (pid)
{
case profession::TRAINED_WAR:
prof = "War " + (use_race_prefix ? race_prefix : "Peasant");
use_race_prefix = false;
break;
case profession::TRAINED_HUNTER:
prof = "Hunting " + (use_race_prefix ? race_prefix : "Peasant");
use_race_prefix = false;
break;
case profession::STANDARD:
if (!use_race_prefix)
prof = "Peasant";
break;
default:
if (auto caption = ENUM_ATTR(profession, caption, pid))
prof = caption;
else
prof = ENUM_KEY_STR(profession, pid);
}
}
if (use_race_prefix)
{
if (!prof.empty())
race_prefix += " ";
prof = race_prefix + prof;
}
return Translation::capitalize(prof, true);
}

@ -13,8 +13,9 @@ orders.exists = {
orders.name = {
key = function(unit)
if unit.name.has_name then
return dfhack.TranslateName(unit.name)
local name = dfhack.units.getVisibleName(unit)
if name and name.has_name then
return dfhack.TranslateName(name)
end
end,
compare = utils.compare_name
@ -29,28 +30,55 @@ orders.age = {
-- This assumes that units are added to active in arrival order
orders.arrival = {
key_table = function(units)
local tmp={}
for i,v in ipairs(units) do
tmp[v.id] = i
local size = units.n or #units
local lookup={}
for i=1,size do
if units[i] then
lookup[units[i].id] = i
end
end
local idx={}
for i,v in ipairs(df.global.world.units.active) do
local ix = tmp[v.id]
if ix ~= nil then
idx[ix] = i
if lookup[v.id] then
idx[lookup[v.id]] = i
end
end
return idx
end
}
local function findRaceCaste(unit)
local rraw = df.creature_raw.find(unit.race)
return rraw, safe_index(rraw, 'caste', unit.caste)
end
orders.profession = {
key = function(unit)
local cp = unit.custom_profession
if cp == '' then
cp = df.profession.attrs[unit.profession].caption
local cp = dfhack.units.getProfessionName(unit)
if cp and cp ~= '' then
return string.lower(cp)
end
end
}
orders.profession_class = {
key = function(unit)
local pid = unit.profession
local parent = df.profession.attrs[pid].parent
if parent >= 0 then
return parent
else
return pid
end
end
}
orders.race = {
key = function(unit)
local rraw = findRaceCaste(unit)
if rraw then
return rraw.name[0]
end
return cp
end
}