diff --git a/LUA_API.rst b/LUA_API.rst index 32716fbf8..acbba3272 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -728,9 +728,15 @@ Units module 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])`` +* ``dfhack.units.getNoblePositions(unit)`` - Retrieves the profession name using custom profession or raws. + Returns a list of tables describing noble position assignments, or *nil*. + Every table has fields ``entity``, ``assignment`` and ``position``. + +* ``dfhack.units.getProfessionName(unit[,ignore_noble,plural])`` + + Retrieves the profession name using custom profession, noble assignments + or raws. The ``ignore_noble`` boolean disables the use of noble positions. * ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])`` diff --git a/Lua API.html b/Lua API.html index 916c6eef8..def3790c9 100644 --- a/Lua API.html +++ b/Lua API.html @@ -959,8 +959,13 @@ a lua list containing them.

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.getNoblePositions(unit)

    +

    Returns a list of tables describing noble position assignments, or nil. +Every table has fields entity, assignment and position.

    +
  • +
  • dfhack.units.getProfessionName(unit[,ignore_noble,plural])

    +

    Retrieves the profession name using custom profession, noble assignments +or raws. The ignore_noble boolean disables the use of noble positions.

  • dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])

    Retrieves the profession name for the given race/caste using raws.

    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 71df50e22..8c56379a7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -61,6 +61,10 @@ distribution. #include "df/assumed_identity.h" #include "df/nemesis_record.h" #include "df/historical_figure.h" +#include "df/historical_entity.h" +#include "df/entity_position.h" +#include "df/entity_position_assignment.h" +#include "df/histfig_entity_link_positionst.h" #include "df/plant_raw.h" #include "df/creature_raw.h" #include "df/inorganic_raw.h" @@ -628,8 +632,35 @@ static int units_getPosition(lua_State *state) return Lua::PushPosXYZ(state, Units::getPosition(Lua::CheckDFObject(state,1))); } +static int units_getNoblePositions(lua_State *state) +{ + std::vector np; + + if (Units::getNoblePositions(&np, Lua::CheckDFObject(state,1))) + { + lua_createtable(state, np.size(), 0); + + for (size_t i = 0; i < np.size(); i++) + { + lua_createtable(state, 0, 3); + Lua::PushDFObject(state, np[i].entity); + lua_setfield(state, -2, "entity"); + Lua::PushDFObject(state, np[i].assignment); + lua_setfield(state, -2, "assignment"); + Lua::PushDFObject(state, np[i].position); + lua_setfield(state, -2, "position"); + lua_rawseti(state, -2, i+1); + } + } + else + lua_pushnil(state); + + return 1; +} + static const luaL_Reg dfhack_units_funcs[] = { { "getPosition", units_getPosition }, + { "getNoblePositions", units_getNoblePositions }, { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 8e4fe2ade..e1f8baa12 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -38,6 +38,9 @@ namespace df struct nemesis_record; struct burrow; struct assumed_identity; + struct historical_entity; + struct entity_position_assignment; + struct entity_position; } /** @@ -218,7 +221,15 @@ DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); -DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool plural = false); +struct NoblePosition { + df::historical_entity *entity; + df::entity_position_assignment *assignment; + df::entity_position *position; +}; + +DFHACK_EXPORT bool getNoblePositions(std::vector *pvec, df::unit *unit); + +DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool ignore_noble = false, bool plural = false); DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profession pid, bool plural = false); } } diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a691dc5d9..4ea225ade 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -55,6 +55,9 @@ using namespace std; #include "df/historical_entity.h" #include "df/historical_figure.h" #include "df/historical_figure_info.h" +#include "df/entity_position.h" +#include "df/entity_position_assignment.h" +#include "df/histfig_entity_link_positionst.h" #include "df/assumed_identity.h" #include "df/burrow.h" #include "df/creature_raw.h" @@ -762,14 +765,85 @@ double DFHack::Units::getAge(df::unit *unit, bool true_age) return cur_time - birth_time; } -std::string DFHack::Units::getProfessionName(df::unit *unit, bool plural) +static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NoblePosition &b) +{ + if (a.position->precedence < b.position->precedence) + return true; + if (a.position->precedence > b.position->precedence) + return false; + return a.position->id < b.position->id; +} + +bool DFHack::Units::getNoblePositions(std::vector *pvec, df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + + pvec->clear(); + + auto histfig = df::historical_figure::find(unit->hist_figure_id); + if (!histfig) + return false; + + for (size_t i = 0; i < histfig->entity_links.size(); i++) + { + auto link = histfig->entity_links[i]; + auto epos = strict_virtual_cast(link); + if (!epos) + continue; + + NoblePosition pos; + + pos.entity = df::historical_entity::find(epos->entity_id); + if (!pos.entity) + continue; + + pos.assignment = binsearch_in_vector(pos.entity->positions.assignments, epos->assignment_id); + if (!pos.assignment) + continue; + + pos.position = binsearch_in_vector(pos.entity->positions.own, pos.assignment->position_id); + if (!pos.position) + continue; + + pvec->push_back(pos); + } + + if (pvec->empty()) + return false; + + std::sort(pvec->begin(), pvec->end(), noble_pos_compare); + return true; +} + +std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural) { std::string prof = unit->custom_profession; + if (!prof.empty()) + return prof; - if (prof.empty()) - prof = getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); + std::vector np; + + if (!ignore_noble && getNoblePositions(&np, unit)) + { + switch (unit->sex) + { + case 0: + prof = np[0].position->name_female[plural ? 1 : 0]; + break; + case 1: + prof = np[0].position->name_male[plural ? 1 : 0]; + break; + default: + break; + } + + if (prof.empty()) + prof = np[0].position->name[plural ? 1 : 0]; + if (!prof.empty()) + return prof; + } - return prof; + return getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); } std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural) diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index 7a332d094..35795502d 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -52,6 +52,15 @@ local function findRaceCaste(unit) return rraw, safe_index(rraw, 'caste', unit.caste) end +orders.noble = { + key = function(unit) + local info = dfhack.units.getNoblePositions(unit) + if info then + return info[1].position.precedence + end + end +} + orders.profession = { key = function(unit) local cp = dfhack.units.getProfessionName(unit)