diff --git a/docs/changelog.txt b/docs/changelog.txt index eb5ba2710..14c78883b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,11 +55,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API - ``Buildings::containsTile()``: no longer takes a ``room`` parameter since that's not how rooms work anymore. If the building has extents, the extents will be checked. otherwise, the result just depends on whether the tile is within the building's bounding box. +- ``Units::getCitizens()``: gets a list of citizens, which otherwise you'd have to iterate over all units the world to discover ## Lua - `helpdb`: new function: ``helpdb.refresh()`` to force a refresh of the database. Call if you are a developer adding new scripts, loading new plugins, or changing help text during play - `helpdb`: changed from auto-refreshing every 60 seconds to only refreshing on explicit call to ``helpdb.refresh()``. docs very rarely change during a play session, and the automatic database refreshes were slowing down the startup of `gui/launcher` - ``widgets.Label``: ``label.scroll()`` now understands ``home`` and ``end`` keywords for scrolling to the top or bottom +- ``dfhack.units.getCitizens()``: gets a list of citizens ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index a21ed0aba..555b7b1a9 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1412,6 +1412,11 @@ Units module Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to the arguments required by this function. +* ``dfhack.units.getCitizens([ignore_sanity])`` + + Returns a table (list) of all citizens, which you would otherwise have to loop over all + units in world and test against ``isCitizen()`` to discover. + * ``dfhack.units.teleport(unit, pos)`` Moves the specified unit and any riders to the target coordinates, setting diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 421821c05..8641e8aaf 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1883,6 +1883,17 @@ static int units_getUnitsInBox(lua_State *state) return 2; } +static int units_getCitizens(lua_State *L) { + bool ignore_sanity = lua_toboolean(L, -1); // defaults to false + + std::vector citizens; + if (Units::getCitizens(citizens, ignore_sanity)) { + Lua::PushVector(L, citizens); + return 1; + } + return 0; +} + static int units_getStressCutoffs(lua_State *L) { lua_newtable(L); @@ -1896,6 +1907,7 @@ static const luaL_Reg dfhack_units_funcs[] = { { "getOuterContainerRef", units_getOuterContainerRef }, { "getNoblePositions", units_getNoblePositions }, { "getUnitsInBox", units_getUnitsInBox }, + { "getCitizens", units_getCitizens }, { "getStressCutoffs", units_getStressCutoffs }, { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 3cdc9264a..442f3d009 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -145,6 +145,7 @@ DFHACK_EXPORT df::unit *getUnit(const int32_t index); DFHACK_EXPORT bool getUnitsInBox(std::vector &units, int16_t x1, int16_t y1, int16_t z1, int16_t x2, int16_t y2, int16_t z2); +DFHACK_EXPORT bool getCitizens(std::vector &citizens, bool ignore_sanity = false); DFHACK_EXPORT int32_t findIndexById(int32_t id); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a60803800..abb35b9e0 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -756,6 +756,14 @@ bool Units::getUnitsInBox (std::vector &units, return true; } +bool Units::getCitizens(std::vector &citizens, bool ignore_sanity) { + for (auto &unit : world->units.active) { + if (isCitizen(unit, ignore_sanity)) + citizens.emplace_back(unit); + } + return true; +} + int32_t Units::findIndexById(int32_t creature_id) { return df::unit::binsearch_index(world->units.all, creature_id);