diff --git a/LUA_API.rst b/LUA_API.rst index 9925240dd..e2d336f7e 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -857,6 +857,11 @@ Buildings module Returns *width, height, centerx, centery*. +* ``dfhack.buildings.findAtTile(pos)`` + + Scans the buildings for the one located at the given tile. + Does not work on civzones. Warning: linear scan. + * ``dfhack.buildings.getCorrectSize(width, height, type, subtype, custom, direction)`` Computes correct dimensions for the specified building type and orientation, @@ -913,6 +918,16 @@ Low-level building creation functions; More high-level functions are implemented in lua and can be loaded by ``require('dfhack.buildings')``. See ``hack/lua/dfhack/buildings.lua``. +Constructions module +-------------------- + +* ``dfhack.constructions.designateNew(pos,type,item_type,mat_index)`` + + Designates a new construction at given position. If there already is + a planned but not completed construction there, changes its type. + Returns *true*, or *false* if obstructed. + Note that designated constructions are technically buildings. + Core interpreter context ======================== diff --git a/Lua API.html b/Lua API.html index 69a0ab120..ebfbe80ed 100644 --- a/Lua API.html +++ b/Lua API.html @@ -344,17 +344,18 @@ ul.auto-toc {
  • Maps module
  • Burrows module
  • Buildings module
  • +
  • Constructions module
  • -
  • Core interpreter context
  • -
  • Plugins @@ -1068,6 +1069,10 @@ burrows, or the presence of invaders.

  • dfhack.buildings.getSize(building)

    Returns width, height, centerx, centery.

  • +
  • dfhack.buildings.findAtTile(pos)

    +

    Scans the buildings for the one located at the given tile. +Does not work on civzones. Warning: linear scan.

    +
  • dfhack.buildings.getCorrectSize(width, height, type, subtype, custom, direction)

    Computes correct dimensions for the specified building type and orientation, using width and height for flexible dimensions. @@ -1118,9 +1123,20 @@ from the size of the building.

    More high-level functions are implemented in lua and can be loaded by require('dfhack.buildings'). See hack/lua/dfhack/buildings.lua.

    +
    +

    Constructions module

    + +
    -

    Core interpreter context

    +

    Core interpreter context

    While plugins can create any number of interpreter instances, there is one special context managed by dfhack core. It is the only context that can receive events from DF and plugins.

    @@ -1134,7 +1150,7 @@ only context that can receive events from DF and plugins.

  • -

    Event type

    +

    Event type

    An event is just a lua table with a predefined metatable that contains a __call metamethod. When it is invoked, it loops through the table with next and calls all contained values. @@ -1160,14 +1176,14 @@ order using dfhack.safecall.

    -

    Plugins

    +

    Plugins

    DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.

    The following plugins have lua support.

    -

    burrows

    +

    burrows

    Implements extended burrow manipulations.

    Events:

    -

    sort

    +

    sort

    Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items.

    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 11cf73c3f..0d0647183 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -48,6 +48,7 @@ distribution. #include "modules/MapCache.h" #include "modules/Burrows.h" #include "modules/Buildings.h" +#include "modules/Constructions.h" #include "LuaWrapper.h" #include "LuaTools.h" @@ -766,6 +767,7 @@ static const luaL_Reg dfhack_burrows_funcs[] = { /***** Buildings module *****/ static const LuaWrapper::FunctionReg dfhack_buildings_module[] = { + WRAPM(Buildings, findAtTile), WRAPM(Buildings, allocInstance), WRAPM(Buildings, checkFreeTiles), WRAPM(Buildings, countExtentTiles), @@ -822,6 +824,14 @@ static const luaL_Reg dfhack_buildings_funcs[] = { { NULL, NULL } }; +/***** Constructions module *****/ + +static const LuaWrapper::FunctionReg dfhack_constructions_module[] = { + WRAPM(Constructions, designateNew), + { NULL, NULL } +}; + + /************************ * Main Open function * ************************/ @@ -839,4 +849,5 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs); OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs); OpenModule(state, "buildings", dfhack_buildings_module, dfhack_buildings_funcs); + OpenModule(state, "constructions", dfhack_constructions_module); } diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index 610688187..9e529b6ca 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -91,6 +91,12 @@ DFHACK_EXPORT bool Read (const uint32_t index, t_building & building); */ DFHACK_EXPORT bool ReadCustomWorkshopTypes(std::map & btypes); +/* + * Find the building located at the specified tile. + * Does not work on civzones. + */ +DFHACK_EXPORT df::building *findAtTile(df::coord pos); + /** * Allocates a building object using this type and position. */ diff --git a/library/include/modules/Constructions.h b/library/include/modules/Constructions.h index e76cc7ba1..17da12711 100644 --- a/library/include/modules/Constructions.h +++ b/library/include/modules/Constructions.h @@ -31,6 +31,8 @@ distribution. #include "Export.h" #include "DataDefs.h" #include "df/construction.h" +#include "df/construction_type.h" +#include "df/item_type.h" /** * \defgroup grp_constructions Construction module parts @@ -57,6 +59,9 @@ DFHACK_EXPORT bool isValid(); DFHACK_EXPORT uint32_t getCount(); DFHACK_EXPORT bool copyConstruction (const int32_t index, t_construction &out); DFHACK_EXPORT df::construction * getConstruction (const int32_t index); + +DFHACK_EXPORT bool designateNew(df::coord pos, df::construction_type type, + df::item_type item = df::item_type::NONE, int mat_index = -1); } } #endif diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 332954cda..fc18ca7e1 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -241,6 +241,20 @@ extern DFHACK_EXPORT df::map_block * getTileBlock (int32_t x, int32_t y, int32_t inline df::map_block * getBlock (df::coord pos) { return getBlock(pos.x, pos.y, pos.z); } inline df::map_block * getTileBlock (df::coord pos) { return getTileBlock(pos.x, pos.y, pos.z); } +extern DFHACK_EXPORT df::tiletype *getTileType(int32_t x, int32_t y, int32_t z); +extern DFHACK_EXPORT df::tile_designation *getTileDesignation(int32_t x, int32_t y, int32_t z); +extern DFHACK_EXPORT df::tile_occupancy *getTileOccupancy(int32_t x, int32_t y, int32_t z); + +inline df::tiletype *getTileType(df::coord pos) { + return getTileType(pos.x, pos.y, pos.z); +} +inline df::tile_designation *getTileDesignation(df::coord pos) { + return getTileDesignation(pos.x, pos.y, pos.z); +} +inline df::tile_occupancy *getTileOccupancy(df::coord pos) { + return getTileOccupancy(pos.x, pos.y, pos.z); +} + DFHACK_EXPORT df::world_data::T_region_map *getRegionBiome(df::coord2d rgn_pos); /// sorts the block event vector into multiple vectors by type diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index bc062f980..e587a4916 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -72,6 +72,17 @@ using df::global::building_next_id; using df::global::process_jobs; using df::building_def; +static uint8_t *getExtentTile(df::building_extents &extent, df::coord2d tile) +{ + if (!extent.extents) + return NULL; + int dx = tile.x - extent.x; + int dy = tile.y - extent.y; + if (dx < 0 || dy < 0 || dx >= extent.width || dy >= extent.height) + return NULL; + return &extent.extents[dx + dy*extent.width]; +} + uint32_t Buildings::getNumBuildings() { return world->buildings.all.size(); @@ -110,6 +121,38 @@ bool Buildings::ReadCustomWorkshopTypes(map & btypes) return true; } +df::building *Buildings::findAtTile(df::coord pos) +{ + auto occ = Maps::getTileOccupancy(pos); + if (!occ || !occ->bits.building) + return NULL; + + auto &vec = df::building::get_vector(); + for (size_t i = 0; i < vec.size(); i++) + { + auto bld = vec[i]; + + if (pos.z != bld->z || + pos.x < bld->x1 || pos.x > bld->x2 || + pos.y < bld->y1 || pos.y > bld->y2) + continue; + + if (!bld->isSettingOccupancy()) + continue; + + if (bld->room.extents && bld->isExtentShaped()) + { + auto etile = getExtentTile(bld->room, pos); + if (!etile || !*etile) + continue; + } + + return bld; + } + + return NULL; +} + df::building *Buildings::allocInstance(df::coord pos, df::building_type type, int subtype, int custom) { if (!building_next_id) @@ -319,17 +362,6 @@ bool Buildings::getCorrectSize(df::coord2d &size, df::coord2d ¢er, } } -static uint8_t *getExtentTile(df::building_extents &extent, df::coord2d tile) -{ - if (!extent.extents) - return NULL; - int dx = tile.x - extent.x; - int dy = tile.y - extent.y; - if (dx < 0 || dy < 0 || dx >= extent.width || dy >= extent.height) - return NULL; - return &extent.extents[dx + dy*extent.width]; -} - bool Buildings::checkFreeTiles(df::coord pos, df::coord2d size, df::building_extents *ext, bool create_ext, bool allow_occupied) diff --git a/library/modules/Constructions.cpp b/library/modules/Constructions.cpp index 4c2bf8ec1..a38048391 100644 --- a/library/modules/Constructions.cpp +++ b/library/modules/Constructions.cpp @@ -35,9 +35,20 @@ using namespace std; #include "MemAccess.h" #include "Types.h" #include "Core.h" + #include "modules/Constructions.h" +#include "modules/Buildings.h" +#include "modules/Maps.h" + +#include "TileTypes.h" + #include "df/world.h" +#include "df/job_item.h" +#include "df/building_type.h" +#include "df/building_constructionst.h" + using namespace DFHack; +using namespace df::enums; using df::global::world; bool Constructions::isValid() @@ -73,3 +84,48 @@ bool Constructions::copyConstruction(const int32_t index, t_construction &out) out.original_tile = out.origin->original_tile; return true; } + +bool Constructions::designateNew(df::coord pos, df::construction_type type, + df::item_type item, int mat_index) +{ + auto ttype = Maps::getTileType(pos); + if (!ttype || tileMaterial(*ttype) == tiletype_material::CONSTRUCTION) + return false; + + auto current = Buildings::findAtTile(pos); + if (current) + { + auto cons = strict_virtual_cast(current); + if (!cons) + return false; + + cons->type = type; + return true; + } + + auto newinst = Buildings::allocInstance(pos, building_type::Construction); + if (!newinst) + return false; + + auto newcons = strict_virtual_cast(newinst); + newcons->type = type; + + df::job_item *filter = new df::job_item(); + filter->item_type = item; + filter->mat_index = mat_index; + filter->flags2.bits.building_material = true; + if (mat_index < 0) + filter->flags2.bits.non_economic = true; + + std::vector filters; + filters.push_back(filter); + + if (!Buildings::constructWithFilters(newinst, filters)) + { + delete newinst; + return false; + } + + return true; +} + diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index ddf5d5069..69f591a0f 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -145,6 +145,24 @@ df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z) return world->map.block_index[x >> 4][y >> 4][z]; } +df::tiletype *Maps::getTileType(int32_t x, int32_t y, int32_t z) +{ + df::map_block *block = getTileBlock(x,y,z); + return block ? &block->tiletype[x&15][y&15] : NULL; +} + +df::tile_designation *Maps::getTileDesignation(int32_t x, int32_t y, int32_t z) +{ + df::map_block *block = getTileBlock(x,y,z); + return block ? &block->designation[x&15][y&15] : NULL; +} + +df::tile_occupancy *Maps::getTileOccupancy(int32_t x, int32_t y, int32_t z) +{ + df::map_block *block = getTileBlock(x,y,z); + return block ? &block->occupancy[x&15][y&15] : NULL; +} + df::world_data::T_region_map *Maps::getRegionBiome(df::coord2d rgn_pos) { auto data = world->world_data;