From ebd450af0eaebfc1c4fb66f6a0d1b2d43b6e4c31 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Sat, 12 Nov 2022 14:42:41 -0800 Subject: [PATCH] Adds isUnitInBox to Units module --- docs/Lua API.rst | 4 ++++ docs/changelog.txt | 1 + library/LuaApi.cpp | 3 +++ library/include/modules/Units.h | 3 +++ library/modules/Units.cpp | 31 +++++++++++++++++++------------ 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index 6b8290d12..33e133162 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -1192,6 +1192,10 @@ Units module Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged. +* ``dfhack.units.isUnitInBox(unit,x1,y1,z1,x2,y2,z2)`` + + Returns true if the unit is within the specified coordinates. + * ``dfhack.units.getUnitsInBox(x1,y1,z1,x2,y2,z2[,filter])`` Returns a table of all units within the specified coordinates. If the ``filter`` diff --git a/docs/changelog.txt b/docs/changelog.txt index a5a7f84a2..0497f2f64 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -73,6 +73,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``Lua::PushInterfaceKeys()``: transforms viewscreen ``feed()`` keys into something that can be interpreted by lua-based widgets - ``Lua::Push()``: now handles maps with otherwise supported keys and values - Units module: added new checks + - ``isUnitInBox()`` - ``isAnimal()`` - ``isVisiting()`` any visiting unit (diplomat, merchant, visitor) - ``isVisitor()`` ie. not merchants or diplomats diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index f99d65c65..b5a1cd754 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1559,6 +1559,7 @@ static const luaL_Reg dfhack_job_funcs[] = { /***** Units module *****/ static const LuaWrapper::FunctionReg dfhack_units_module[] = { + WRAPM(Units, isUnitInBox), WRAPM(Units, teleport), WRAPM(Units, getGeneralRef), WRAPM(Units, getSpecificRef), @@ -1716,6 +1717,8 @@ static int units_getUnitsInBox(lua_State *state) { luaL_checktype(state, 7, LUA_TFUNCTION); units.erase(std::remove_if(units.begin(), units.end(), [&state](df::unit *unit) -> bool { + // todo: merging this filter into the base function would be welcomed by plugins + // (it would also be faster, and less obfuscated than this [ie. erase(remove_if)]) lua_dup(state); // copy function Lua::PushDFObject(state, unit); lua_call(state, 1, 1); diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 84fcf5bfc..c001b6a5a 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -73,6 +73,9 @@ static const int MAX_COLORS = 15; // found. Call repeatedly do get all units in a specified box (uses tile coords) DFHACK_EXPORT int32_t getNumUnits(); DFHACK_EXPORT df::unit *getUnit(const int32_t index); +DFHACK_EXPORT bool isUnitInBox(df::unit* u, + int16_t x1, int16_t y1, int16_t z1, + int16_t x2, int16_t y2, int16_t z2); 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); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index b0aad49fb..5dc41da02 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -98,6 +98,23 @@ df::unit *Units::getUnit (const int32_t index) return vector_get(world->units.all, index); } +bool Units::isUnitInBox(df::unit* u, + int16_t x1, int16_t y1, int16_t z1, + int16_t x2, int16_t y2, int16_t z2) { + + if (x1 > x2) swap(x1, x2); + if (y1 > y2) swap(y1, y2); + if (z1 > z2) swap(z1, z2); + if (u->pos.x >= x1 && u->pos.x <= x2) { + if (u->pos.y >= y1 && u->pos.y <= y2) { + if (u->pos.z >= z1 && u->pos.z <= z2) { + return true; + } + } + } + return false; +} + // returns index of creature actually read or -1 if no creature can be found bool Units::getUnitsInBox (std::vector &units, int16_t x1, int16_t y1, int16_t z1, @@ -106,22 +123,12 @@ bool Units::getUnitsInBox (std::vector &units, if (!world) return false; - if (x1 > x2) swap(x1, x2); - if (y1 > y2) swap(y1, y2); - if (z1 > z2) swap(z1, z2); - units.clear(); for (df::unit *u : world->units.all) { - if (u->pos.x >= x1 && u->pos.x <= x2) + if (isUnitInBox(u, x1, y1, z1, x2, y2, z2)) { - if (u->pos.y >= y1 && u->pos.y <= y2) - { - if (u->pos.z >= z1 && u->pos.z <= z2) - { - units.push_back(u); - } - } + units.push_back(u); } } return true;