diff --git a/Lua API.html b/Lua API.html
index 06fa5418e..125687110 100644
--- a/Lua API.html
+++ b/Lua API.html
@@ -932,6 +932,21 @@ Returns entry, did_create_new
and automatically stored in the save game, these save and retrieval
functions can just copy values in memory without doing any actual I/O.
However, currently every entry has a 180+-byte dead-weight overhead.
+It is also possible to associate one bit per map tile with an entry,
+using these two methods:
+
+entry:getTilemask(block[, create])
+Retrieves the tile bitmask associated with this entry in the given map
+block. If create is true, an empty mask is created if none exists;
+otherwise the function returns nil, which must be assumed to be the same
+as an all-zero mask.
+
+entry:deleteTilemask(block)
+Deletes the associated tile mask from the given map block.
+
+
+Note that these masks are only saved in fortress mode, and also that deleting
+the persistent entry will NOT delete the associated masks.
@@ -1286,6 +1301,18 @@ 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.
+
dfhack.maps.hasTileAssignment(tilemask)
+Checks if the tile_bitmask object is not nil and contains any set bits; returns true or false.
+
+
dfhack.maps.getTileAssignment(tilemask,x,y)
+Checks if the tile_bitmask object is not nil and has the relevant bit set; returns true or false.
+
+
dfhack.maps.setTileAssignment(tilemask,x,y,enable)
+Sets the relevant bit in the tile_bitmask object to the enable argument.
+
+
dfhack.maps.resetTileAssignment(tilemask[,enable])
+Sets all bits in the mask to the enable argument.
+
diff --git a/Lua API.rst b/Lua API.rst
index fbb4b7d82..7ad6aec23 100644
--- a/Lua API.rst
+++ b/Lua API.rst
@@ -646,6 +646,24 @@ and automatically stored in the save game, these save and retrieval
functions can just copy values in memory without doing any actual I/O.
However, currently every entry has a 180+-byte dead-weight overhead.
+It is also possible to associate one bit per map tile with an entry,
+using these two methods:
+
+* ``entry:getTilemask(block[, create])``
+
+ Retrieves the tile bitmask associated with this entry in the given map
+ block. If ``create`` is *true*, an empty mask is created if none exists;
+ otherwise the function returns *nil*, which must be assumed to be the same
+ as an all-zero mask.
+
+* ``entry:deleteTilemask(block)``
+
+ Deletes the associated tile mask from the given map block.
+
+Note that these masks are only saved in fortress mode, and also that deleting
+the persistent entry will **NOT** delete the associated masks.
+
+
Material info lookup
--------------------
@@ -1079,6 +1097,22 @@ Maps module
take into account anything that depends on the actual units, like
burrows, or the presence of invaders.
+* ``dfhack.maps.hasTileAssignment(tilemask)``
+
+ Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*.
+
+* ``dfhack.maps.getTileAssignment(tilemask,x,y)``
+
+ Checks if the tile_bitmask object is not *nil* and has the relevant bit set; returns *true* or *false*.
+
+* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)``
+
+ Sets the relevant bit in the tile_bitmask object to the *enable* argument.
+
+* ``dfhack.maps.resetTileAssignment(tilemask[,enable])``
+
+ Sets all bits in the mask to the *enable* argument.
+
Burrows module
--------------
diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp
index 0df96f066..ef571bcb7 100644
--- a/library/LuaApi.cpp
+++ b/library/LuaApi.cpp
@@ -30,6 +30,7 @@ distribution.
#include "MemAccess.h"
#include "Core.h"
+#include "Error.h"
#include "VersionInfo.h"
#include "tinythread.h"
// must be last due to MS stupidity
@@ -311,12 +312,12 @@ static PersistentDataItem get_persistent(lua_State *state)
if (lua_istable(state, 1))
{
+ Lua::StackUnwinder frame(state);
+
if (!lua_getmetatable(state, 1) ||
!lua_rawequal(state, -1, lua_upvalueindex(1)))
luaL_argerror(state, 1, "invalid table type");
- lua_settop(state, 1);
-
return persistent_by_struct(state, 1);
}
else
@@ -446,11 +447,38 @@ static int dfhack_persistent_save(lua_State *state)
return 2;
}
+static int dfhack_persistent_getTilemask(lua_State *state)
+{
+ CoreSuspender suspend;
+
+ lua_settop(state, 3);
+ auto ref = get_persistent(state);
+ auto block = Lua::CheckDFObject(state, 2);
+ bool create = lua_toboolean(state, 3);
+
+ Lua::PushDFObject(state, World::getPersistentTilemask(ref, block, create));
+ return 1;
+}
+
+static int dfhack_persistent_deleteTilemask(lua_State *state)
+{
+ CoreSuspender suspend;
+
+ lua_settop(state, 2);
+ auto ref = get_persistent(state);
+ auto block = Lua::CheckDFObject(state, 2);
+
+ lua_pushboolean(state, World::deletePersistentTilemask(ref, block));
+ return 1;
+}
+
static const luaL_Reg dfhack_persistent_funcs[] = {
{ "get", dfhack_persistent_get },
{ "delete", dfhack_persistent_delete },
{ "get_all", dfhack_persistent_get_all },
{ "save", dfhack_persistent_save },
+ { "getTilemask", dfhack_persistent_getTilemask },
+ { "deleteTilemask", dfhack_persistent_deleteTilemask },
{ NULL, NULL }
};
@@ -937,6 +965,22 @@ static const luaL_Reg dfhack_items_funcs[] = {
/***** Maps module *****/
+static bool hasTileAssignment(df::tile_bitmask *bm) {
+ return bm && bm->has_assignments();
+}
+static bool getTileAssignment(df::tile_bitmask *bm, int x, int y) {
+ return bm && bm->getassignment(x,y);
+}
+static void setTileAssignment(df::tile_bitmask *bm, int x, int y, bool val) {
+ CHECK_NULL_POINTER(bm);
+ bm->setassignment(x,y,val);
+}
+static void resetTileAssignment(df::tile_bitmask *bm, bool val) {
+ CHECK_NULL_POINTER(bm);
+ if (val) bm->set_all();
+ else bm->clear();
+}
+
static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock),
WRAPM(Maps, enableBlockUpdates),
@@ -944,6 +988,10 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = {
WRAPM(Maps, getLocalInitFeature),
WRAPM(Maps, canWalkBetween),
WRAPM(Maps, spawnFlow),
+ WRAPN(hasTileAssignment, hasTileAssignment),
+ WRAPN(getTileAssignment, getTileAssignment),
+ WRAPN(setTileAssignment, setTileAssignment),
+ WRAPN(resetTileAssignment, resetTileAssignment),
{ NULL, NULL }
};
diff --git a/library/include/df/custom/tile_bitmask.methods.inc b/library/include/df/custom/tile_bitmask.methods.inc
index 18b312a08..e3414e334 100644
--- a/library/include/df/custom/tile_bitmask.methods.inc
+++ b/library/include/df/custom/tile_bitmask.methods.inc
@@ -16,7 +16,7 @@ inline bool getassignment( const df::coord2d &xy )
}
inline bool getassignment( int x, int y )
{
- return (bits[y] & (1 << x));
+ return (bits[(y&15)] & (1 << (x&15)));
}
inline void setassignment( const df::coord2d &xy, bool bit )
{
@@ -25,9 +25,9 @@ inline void setassignment( const df::coord2d &xy, bool bit )
inline void setassignment( int x, int y, bool bit )
{
if(bit)
- bits[y] |= (1 << x);
+ bits[(y&15)] |= (1 << (x&15));
else
- bits[y] &= ~(1 << x);
+ bits[(y&15)] &= ~(1 << (x&15));
}
bool has_assignments()
{
diff --git a/library/include/modules/World.h b/library/include/modules/World.h
index f4c31dcf3..a945c4e72 100644
--- a/library/include/modules/World.h
+++ b/library/include/modules/World.h
@@ -37,6 +37,12 @@ distribution.
#include "DataDefs.h"
+namespace df
+{
+ struct tile_bitmask;
+ struct map_block;
+}
+
namespace DFHack
{
typedef df::game_mode GameMode;
@@ -120,6 +126,9 @@ namespace DFHack
DFHACK_EXPORT bool DeletePersistentData(const PersistentDataItem &item);
DFHACK_EXPORT void ClearPersistentCache();
+
+ DFHACK_EXPORT df::tile_bitmask *getPersistentTilemask(const PersistentDataItem &item, df::map_block *block, bool create = false);
+ DFHACK_EXPORT bool deletePersistentTilemask(const PersistentDataItem &item, df::map_block *block);
}
}
#endif
diff --git a/library/modules/World.cpp b/library/modules/World.cpp
index 65d0c7cb8..f3283c3a3 100644
--- a/library/modules/World.cpp
+++ b/library/modules/World.cpp
@@ -38,13 +38,18 @@ using namespace std;
#include "ModuleFactory.h"
#include "Core.h"
+#include "modules/Maps.h"
+
#include "MiscUtils.h"
#include "DataDefs.h"
#include "df/world.h"
#include "df/historical_figure.h"
+#include "df/map_block.h"
+#include "df/block_square_event_world_constructionst.h"
using namespace DFHack;
+using namespace df::enums;
using df::global::world;
@@ -312,3 +317,63 @@ bool World::DeletePersistentData(const PersistentDataItem &item)
return false;
}
+
+df::tile_bitmask *World::getPersistentTilemask(const PersistentDataItem &item, df::map_block *block, bool create)
+{
+ if (!block)
+ return NULL;
+
+ int id = item.raw_id();
+ if (id > -100)
+ return NULL;
+
+ for (size_t i = 0; i < block->block_events.size(); i++)
+ {
+ auto ev = block->block_events[i];
+ if (ev->getType() != block_square_event_type::world_construction)
+ continue;
+ auto wcsev = strict_virtual_cast(ev);
+ if (!wcsev || wcsev->construction_id != id)
+ continue;
+ return &wcsev->tile_bitmask;
+ }
+
+ if (!create)
+ return NULL;
+
+ auto ev = df::allocate();
+ if (!ev)
+ return NULL;
+
+ ev->construction_id = id;
+ ev->tile_bitmask.clear();
+ vector_insert_at(block->block_events, 0, (df::block_square_event*)ev);
+
+ return &ev->tile_bitmask;
+}
+
+bool World::deletePersistentTilemask(const PersistentDataItem &item, df::map_block *block)
+{
+ if (!block)
+ return false;
+ int id = item.raw_id();
+ if (id > -100)
+ return false;
+
+ bool found = false;
+ for (int i = block->block_events.size()-1; i >= 0; i--)
+ {
+ auto ev = block->block_events[i];
+ if (ev->getType() != block_square_event_type::world_construction)
+ continue;
+ auto wcsev = strict_virtual_cast(ev);
+ if (!wcsev || wcsev->construction_id != id)
+ continue;
+
+ delete wcsev;
+ vector_erase_at(block->block_events, i);
+ found = true;
+ }
+
+ return found;
+}
diff --git a/library/xml b/library/xml
index 20c6d9c74..aec106cdc 160000
--- a/library/xml
+++ b/library/xml
@@ -1 +1 @@
-Subproject commit 20c6d9c743f1c5a20bb288f427b101e9b2a138d7
+Subproject commit aec106cdc32083bbcc6d6dd27d9e069f5525ea92