From 7a34a89f53071a8368ec5bd064accb10354b6d56 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 14 Apr 2012 14:12:59 +0400 Subject: [PATCH] Add burrow subcommands to modify burrow unit and tile sets. --- LUA_API.rst | 8 + Lua API.html | 6 + library/LuaApi.cpp | 2 + .../df/custom/block_burrow.methods.inc | 9 +- .../block_square_event_mineralst.methods.inc | 9 +- library/include/modules/Maps.h | 8 + library/include/modules/Units.h | 4 + library/modules/Maps.cpp | 71 +++++ library/modules/Units.cpp | 45 +++ plugins/burrows.cpp | 262 +++++++++++++++++- 10 files changed, 413 insertions(+), 11 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index 673053189..d5af5e7a4 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -695,6 +695,10 @@ Units module The unit is capable of rational action, i.e. not dead, insane or zombie. +* ``dfhack.units.clearBurrowMembers(burrow)`` + + Removes all units from the burrow. + * ``dfhack.units.isInBurrow(unit,burrow)`` Checks if the unit is in the burrow. @@ -776,6 +780,10 @@ Maps module Returns a table of map block pointers. +* ``dfhack.maps.clearBurrowTiles(burrow)`` + + Removes all tiles from the burrow. + * ``dfhack.maps.isBurrowTile(burrow,tile_coord)`` Checks if the tile is in burrow. diff --git a/Lua API.html b/Lua API.html index 32a3b7f04..66385840b 100644 --- a/Lua API.html +++ b/Lua API.html @@ -924,6 +924,9 @@ a lua list containing them.

  • dfhack.units.isSane(unit)

    The unit is capable of rational action, i.e. not dead, insane or zombie.

  • +
  • dfhack.units.clearBurrowMembers(burrow)

    +

    Removes all units from the burrow.

    +
  • dfhack.units.isInBurrow(unit,burrow)

    Checks if the unit is in the burrow.

  • @@ -989,6 +992,9 @@ Returns false in case of error.

  • dfhack.maps.listBurrowBlocks(burrow)

    Returns a table of map block pointers.

  • +
  • dfhack.maps.clearBurrowTiles(burrow)

    +

    Removes all tiles from the burrow.

    +
  • dfhack.maps.isBurrowTile(burrow,tile_coord)

    Checks if the tile is in burrow.

  • diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 6792c921e..917e44d38 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -634,6 +634,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), + WRAPM(Units, clearBurrowMembers), WRAPM(Units, isInBurrow), WRAPM(Units, setInBurrow), { NULL, NULL } @@ -707,6 +708,7 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPM(Maps, getGlobalInitFeature), WRAPM(Maps, getLocalInitFeature), WRAPM(Maps, findBurrowByName), + WRAPM(Maps, clearBurrowTiles), WRAPN(isBlockBurrowTile, maps_isBlockBurrowTile), WRAPN(setBlockBurrowTile, maps_setBlockBurrowTile), WRAPM(Maps, isBurrowTile), diff --git a/library/include/df/custom/block_burrow.methods.inc b/library/include/df/custom/block_burrow.methods.inc index 7754ab0db..216a58662 100644 --- a/library/include/df/custom/block_burrow.methods.inc +++ b/library/include/df/custom/block_burrow.methods.inc @@ -16,4 +16,11 @@ inline void setassignment( int x, int y, bool bit ) tile_bitmask[y] |= (1 << x); else tile_bitmask[y] &= ~(1 << x); -} \ No newline at end of file +} +bool has_assignments() +{ + for (int i = 0; i < 16; i++) + if (tile_bitmask[i]) + return true; + return false; +} diff --git a/library/include/df/custom/block_square_event_mineralst.methods.inc b/library/include/df/custom/block_square_event_mineralst.methods.inc index 7754ab0db..216a58662 100644 --- a/library/include/df/custom/block_square_event_mineralst.methods.inc +++ b/library/include/df/custom/block_square_event_mineralst.methods.inc @@ -16,4 +16,11 @@ inline void setassignment( int x, int y, bool bit ) tile_bitmask[y] |= (1 << x); else tile_bitmask[y] &= ~(1 << x); -} \ No newline at end of file +} +bool has_assignments() +{ + for (int i = 0; i < 16; i++) + if (tile_bitmask[i]) + return true; + return false; +} diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 3cd1187a5..b7341f87c 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -263,8 +263,16 @@ extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, d DFHACK_EXPORT df::burrow *findBurrowByName(std::string name); DFHACK_EXPORT void listBurrowBlocks(std::vector *pvec, df::burrow *burrow); +DFHACK_EXPORT void clearBurrowTiles(df::burrow *burrow); DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false); +DFHACK_EXPORT bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask); + +inline bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block) +{ + return deleteBlockBurrowMask(burrow, block, getBlockBurrowMask(burrow, block)); +} + DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile); DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable); diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index d7dadb21b..e093ed1ef 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -206,6 +206,10 @@ DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit); DFHACK_EXPORT bool isDead(df::unit *unit); DFHACK_EXPORT bool isAlive(df::unit *unit); DFHACK_EXPORT bool isSane(df::unit *unit); +DFHACK_EXPORT bool isCitizen(df::unit *unit); +DFHACK_EXPORT bool isDwarf(df::unit *unit); + +DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow); DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow); DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index fce80d775..327e26986 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -715,6 +715,42 @@ void Maps::listBurrowBlocks(std::vector *pvec, df::burrow *burro } } +static void destroyBurrowMask(df::block_burrow *mask) +{ + if (!mask) return; + + auto link = mask->link; + + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + delete link; + + delete mask; +} + +void Maps::clearBurrowTiles(df::burrow *burrow) +{ + CHECK_NULL_POINTER(burrow); + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + + for (size_t i = 0; i < burrow->block_x.size(); i++) + { + df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); + + auto block = getBlock(pos - base); + if (!block) + continue; + + destroyBurrowMask(getBlockBurrowMask(burrow, block)); + } + + burrow->block_x.clear(); + burrow->block_y.clear(); + burrow->block_z.clear(); +} + df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create) { CHECK_NULL_POINTER(burrow); @@ -754,6 +790,36 @@ df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *bl return NULL; } +bool Maps::deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask) +{ + CHECK_NULL_POINTER(burrow); + CHECK_NULL_POINTER(block); + + if (!mask) + return false; + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + df::coord pos = base + block->map_pos/16; + + destroyBurrowMask(mask); + + for (size_t i = 0; i < burrow->block_x.size(); i++) + { + df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); + + if (cur == pos) + { + vector_erase_at(burrow->block_x, i); + vector_erase_at(burrow->block_y, i); + vector_erase_at(burrow->block_z, i); + + break; + } + } + + return true; +} + bool Maps::isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile) { CHECK_NULL_POINTER(burrow); @@ -774,8 +840,13 @@ bool Maps::setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coor auto mask = getBlockBurrowMask(burrow, block, enable); if (mask) + { mask->setassignment(tile & 15, enable); + if (!enable && !mask->has_assignments()) + deleteBlockBurrowMask(burrow, block, mask); + } + return true; } diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 7dbb40c97..8b44d4cf9 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -653,6 +653,51 @@ bool DFHack::Units::isSane(df::unit *unit) return true; } +bool DFHack::Units::isCitizen(df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + + return unit->civ_id == ui->civ_id && + !unit->flags1.bits.merchant && + !unit->flags1.bits.diplomat && + !unit->flags2.bits.resident && + !unit->flags1.bits.dead && + !unit->flags3.bits.ghostly; +} + +bool DFHack::Units::isDwarf(df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + + return unit->race == ui->race_id; +} + +void DFHack::Units::clearBurrowMembers(df::burrow *burrow) +{ + CHECK_NULL_POINTER(burrow); + + for (size_t i = 0; i < burrow->units.size(); i++) + { + auto unit = df::unit::find(burrow->units[i]); + + if (unit) + erase_from_vector(unit->burrows, burrow->id); + } + + burrow->units.clear(); + + // Sync ui if active + if (ui && ui->main.mode == ui_sidebar_mode::Burrows && + ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) + { + auto &sel = ui->burrows.sel_units; + + for (size_t i = 0; i < sel.size(); i++) + sel[i] = false; + } +} + + bool DFHack::Units::isInBurrow(df::unit *unit, df::burrow *burrow) { CHECK_NULL_POINTER(unit); diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index a559573ac..c973405ee 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -8,6 +8,7 @@ #include "modules/Maps.h" #include "modules/MapCache.h" #include "modules/World.h" +#include "modules/Units.h" #include "TileTypes.h" #include "DataDefs.h" @@ -16,6 +17,7 @@ #include "df/unit.h" #include "df/burrow.h" #include "df/map_block.h" +#include "df/block_burrow.h" #include "df/job.h" #include "df/job_list_link.h" @@ -52,11 +54,28 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector grow_burrows; DFhackCExport command_result plugin_onupdate(color_ostream &out) { - if (!active || !auto_grow) + if (!active) return CR_OK; detect_burrow_renames(out); - detect_digging(out); + + if (auto_grow) + detect_digging(out); + return CR_OK; } @@ -213,24 +235,39 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) * Config and processing */ +static std::map name_lookup; + static void parse_names() { auto &list = ui->burrows.list; grow_burrows.clear(); + name_lookup.clear(); for (size_t i = 0; i < list.size(); i++) { auto burrow = list[i]; - if (!burrow->name.empty() && burrow->name[burrow->name.size()-1] == '+') - grow_burrows.push_back(burrow->id); + std::string name = burrow->name; + + if (!name.empty()) + { + name_lookup[name] = burrow->id; + + if (name[name.size()-1] == '+') + { + grow_burrows.push_back(burrow->id); + name.resize(name.size()-1); + } + + if (!name.empty()) + name_lookup[name] = burrow->id; + } } } static void reset_tracking() { - name_burrow_id = -1; diggers.clear(); next_job_id_save = 0; } @@ -244,6 +281,8 @@ static void init_map(color_ostream &out) } parse_names(); + name_burrow_id = -1; + reset_tracking(); active = true; @@ -286,10 +325,7 @@ static void enable_auto_grow(color_ostream &out, bool enable) auto_grow = enable; if (enable) - { - parse_names(); reset_tracking(); - } } static void handle_burrow_rename(color_ostream &out, df::burrow *burrow) @@ -371,6 +407,137 @@ static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord } } +static df::burrow *findByName(color_ostream &out, std::string name, bool silent = false) +{ + int id = -1; + if (name_lookup.count(name)) + id = name_lookup[name]; + auto rv = df::burrow::find(id); + if (!rv && !silent) + out.printerr("Burrow not found: '%s'\n", name.c_str()); + return rv; +} + +static void copyUnits(df::burrow *target, df::burrow *source, bool enable) +{ + if (source == target) + { + if (!enable) + Units::clearBurrowMembers(target); + + return; + } + + for (size_t i = 0; i < source->units.size(); i++) + { + auto unit = df::unit::find(source->units[i]); + + if (unit) + Units::setInBurrow(unit, target, enable); + } +} + +static void copyTiles(df::burrow *target, df::burrow *source, bool enable) +{ + if (source == target) + { + if (!enable) + Maps::clearBurrowTiles(target); + + return; + } + + std::vector pvec; + Maps::listBurrowBlocks(&pvec, source); + + for (size_t i = 0; i < pvec.size(); i++) + { + auto block = pvec[i]; + auto smask = Maps::getBlockBurrowMask(source, block); + if (!smask) + continue; + + auto tmask = Maps::getBlockBurrowMask(target, block, enable); + if (!tmask) + continue; + + if (enable) + { + for (int j = 0; j < 16; j++) + tmask->tile_bitmask[j] |= smask->tile_bitmask[j]; + } + else + { + for (int j = 0; j < 16; j++) + tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j]; + + if (!tmask->has_assignments()) + Maps::deleteBlockBurrowMask(target, block, tmask); + } + } +} + +static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, + df::tile_designation d_value, bool enable) +{ + auto &blocks = world->map.map_blocks; + + for (size_t i = 0; i < blocks.size(); i++) + { + auto block = blocks[i]; + df::block_burrow *mask = NULL; + + for (int x = 0; x < 16; x++) + { + for (int y = 0; y < 16; y++) + { + if ((block->designation[x][y].whole & d_mask.whole) != d_value.whole) + continue; + + if (!mask) + mask = Maps::getBlockBurrowMask(target, block, enable); + if (!mask) + goto next_block; + + mask->setassignment(x, y, enable); + } + } + + if (mask && !enable && !mask->has_assignments()) + Maps::deleteBlockBurrowMask(target, block, mask); + + next_block:; + } +} + +static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) +{ + df::tile_designation mask(0); + df::tile_designation value(0); + + if (name == "ABOVE_GROUND") + mask.bits.subterranean = true; + else if (name == "SUBTERRANEAN") + mask.bits.subterranean = value.bits.subterranean = true; + else if (name == "LIGHT") + mask.bits.light = value.bits.light = true; + else if (name == "DARK") + mask.bits.light = true; + else if (name == "OUTSIDE") + mask.bits.outside = value.bits.outside = true; + else if (name == "INSIDE") + mask.bits.outside = true; + else if (name == "HIDDEN") + mask.bits.hidden = value.bits.hidden = true; + else if (name == "REVEALED") + mask.bits.hidden = true; + else + return false; + + setTilesByDesignation(target, mask, value, enable); + return true; +} + static command_result burrow(color_ostream &out, vector ¶meters) { CoreSuspender suspend; @@ -402,6 +569,83 @@ static command_result burrow(color_ostream &out, vector ¶meters) return CR_WRONG_USAGE; } } + else if (cmd == "clear-units") + { + if (parameters.size() < 2) + return CR_WRONG_USAGE; + + for (int i = 1; i < parameters.size(); i++) + { + auto target = findByName(out, parameters[i]); + if (!target) + return CR_WRONG_USAGE; + + Units::clearBurrowMembers(target); + } + } + else if (cmd == "set-units" || cmd == "add-units" || cmd == "remove-units") + { + if (parameters.size() < 3) + return CR_WRONG_USAGE; + + auto target = findByName(out, parameters[1]); + if (!target) + return CR_WRONG_USAGE; + + if (cmd == "set-units") + Units::clearBurrowMembers(target); + + bool enable = (cmd != "remove-units"); + + for (int i = 2; i < parameters.size(); i++) + { + auto source = findByName(out, parameters[i]); + if (!source) + return CR_WRONG_USAGE; + + copyUnits(target, source, enable); + } + } + else if (cmd == "clear-tiles") + { + if (parameters.size() < 2) + return CR_WRONG_USAGE; + + for (int i = 1; i < parameters.size(); i++) + { + auto target = findByName(out, parameters[i]); + if (!target) + return CR_WRONG_USAGE; + + Maps::clearBurrowTiles(target); + } + } + else if (cmd == "set-tiles" || cmd == "add-tiles" || cmd == "remove-tiles") + { + if (parameters.size() < 3) + return CR_WRONG_USAGE; + + auto target = findByName(out, parameters[1]); + if (!target) + return CR_WRONG_USAGE; + + if (cmd == "set-tiles") + Maps::clearBurrowTiles(target); + + bool enable = (cmd != "remove-tiles"); + + for (int i = 2; i < parameters.size(); i++) + { + if (setTilesByKeyword(target, parameters[i], enable)) + continue; + + auto source = findByName(out, parameters[i]); + if (!source) + return CR_WRONG_USAGE; + + copyTiles(target, source, enable); + } + } else { if (!parameters.empty() && cmd != "?")