diff --git a/LUA_API.rst b/LUA_API.rst index 38b0e2025..d2afacd42 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -795,6 +795,16 @@ Maps module Returns the local feature object with the given region coords and index. +* ``dfhack.maps.canWalkBetween(pos1, pos2)`` + + Checks if a dwarf may be able to walk between the two tiles, + using a pathfinding cache maintained by the game. Note that + this cache is only updated when the game is unpaused, and thus + can get out of date if doors are forbidden or unforbidden, or + tools like liquids or tiletypes are used. It also cannot possibly + take into account anything that depends on the actual units, like + burrows, or the presence of invaders. + Burrows module -------------- diff --git a/Lua API.html b/Lua API.html index 3e08b3bef..fd2004b8d 100644 --- a/Lua API.html +++ b/Lua API.html @@ -1015,6 +1015,15 @@ Returns false in case of error.

  • dfhack.maps.getLocalInitFeature(region_coord2d,index)

    Returns the local feature object with the given region coords and index.

  • +
  • dfhack.maps.canWalkBetween(pos1, pos2)

    +

    Checks if a dwarf may be able to walk between the two tiles, +using a pathfinding cache maintained by the game. Note that +this cache is only updated when the game is unpaused, and thus +can get out of date if doors are forbidden or unforbidden, or +tools like liquids or tiletypes are used. It also cannot possibly +take into account anything that depends on the actual units, like +burrows, or the presence of invaders.

    +
  • diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 507494669..8855a50da 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -80,6 +80,17 @@ distribution. using namespace DFHack; using namespace DFHack::LuaWrapper; +void Lua::Push(lua_State *state, const Units::NoblePosition &pos) +{ + lua_createtable(state, 0, 3); + Lua::PushDFObject(state, pos.entity); + lua_setfield(state, -2, "entity"); + Lua::PushDFObject(state, pos.assignment); + lua_setfield(state, -2, "assignment"); + Lua::PushDFObject(state, pos.position); + lua_setfield(state, -2, "position"); +} + int Lua::PushPosXYZ(lua_State *state, df::coord pos) { if (!pos.isValid()) @@ -558,11 +569,15 @@ static void OpenModule(lua_State *state, const char *mname, #define WRAP(function) { #function, df::wrap_function(function,true) } #define WRAPN(name, function) { #name, df::wrap_function(function,true) } +/***** Translation module *****/ + static const LuaWrapper::FunctionReg dfhack_module[] = { WRAPM(Translation, TranslateName), { NULL, NULL } }; +/***** Gui module *****/ + static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, getSelectedWorkshopJob), WRAPM(Gui, getSelectedJob), @@ -573,6 +588,8 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { { NULL, NULL } }; +/***** Job module *****/ + static bool jobEqual(df::job *job1, df::job *job2) { return *job1 == *job2; } static bool jobItemEqual(df::job_item *job1, df::job_item *job2) { return *job1 == *job2; } @@ -609,6 +626,7 @@ static const luaL_Reg dfhack_job_funcs[] = { { NULL, NULL } }; +/***** Units module *****/ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getContainer), @@ -635,21 +653,7 @@ 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); - } - } + Lua::PushVector(state, np); else lua_pushnil(state); @@ -662,6 +666,8 @@ static const luaL_Reg dfhack_units_funcs[] = { { NULL, NULL } }; +/***** Items module *****/ + static bool items_moveToGround(df::item *item, df::coord pos) { MapExtras::MapCache mc; @@ -702,12 +708,15 @@ static const luaL_Reg dfhack_items_funcs[] = { { NULL, NULL } }; +/***** Maps module *****/ + static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), WRAPN(getTileBlock, (df::map_block* (*)(df::coord))Maps::getTileBlock), WRAPM(Maps, getRegionBiome), WRAPM(Maps, getGlobalInitFeature), WRAPM(Maps, getLocalInitFeature), + WRAPM(Maps, canWalkBetween), { NULL, NULL } }; @@ -715,6 +724,8 @@ static const luaL_Reg dfhack_maps_funcs[] = { { NULL, NULL } }; +/***** Burrows module *****/ + static bool burrows_isAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y) { return Burrows::isAssignedBlockTile(burrow, block, df::coord2d(x,y)); diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index a41b58d1c..1ca79d331 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -36,6 +36,10 @@ distribution. namespace DFHack { class function_identity_base; + + namespace Units { + struct NoblePosition; + } } namespace DFHack {namespace Lua { @@ -243,6 +247,7 @@ namespace DFHack {namespace Lua { } inline void Push(lua_State *state, df::coord &obj) { PushDFObject(state, &obj); } inline void Push(lua_State *state, df::coord2d &obj) { PushDFObject(state, &obj); } + void Push(lua_State *state, const Units::NoblePosition &pos); template inline void Push(lua_State *state, T *ptr) { PushDFObject(state, ptr); } diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index b6077a85e..332954cda 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -255,6 +255,8 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, /// remove a block event from the block by address extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event * which ); + +DFHACK_EXPORT bool canWalkBetween(df::coord pos1, df::coord pos2); } } #endif diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index e7d49deda..ddf5d5069 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -387,6 +387,20 @@ bool Maps::ReadGeology(vector > *layer_mats, vector return true; } +bool Maps::canWalkBetween(df::coord pos1, df::coord pos2) +{ + auto block1 = getTileBlock(pos1); + auto block2 = getTileBlock(pos2); + + if (!block1 || !block2) + return false; + + auto tile1 = MapExtras::index_tile(block1->walkable, pos1); + auto tile2 = MapExtras::index_tile(block2->walkable, pos2); + + return tile1 && tile1 == tile2; +} + #define COPY(a,b) memcpy(&a,&b,sizeof(a)) MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 8ca66daf5..f644398f5 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -388,6 +388,7 @@ command_result df_liquids_execute(color_ostream &out) mcache.setTemp2At(*iter,10015); df::tile_designation des = mcache.designationAt(*iter); des.bits.flow_size = 0; + des.bits.flow_forbid = false; mcache.setDesignationAt(*iter, des); iter ++; } @@ -494,6 +495,9 @@ command_result df_liquids_execute(color_ostream &out) mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } + // mark the tile passable or impassable like the game does + des.bits.flow_forbid = des.bits.flow_size && + (des.bits.liquid_type == tile_liquid::Magma || des.bits.flow_size > 3); mcache.setDesignationAt(current,des); } seen_blocks.insert(mcache.BlockAt(current / 16));