diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index 24f1b72d4..68556053b 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -85,10 +85,8 @@ Options ``-c``, ``--cursor `` Indicate the starting position of the box or flood fill. If not specified, the position of the keyboard cursor is used. -``-d``, ``--dry-run`` - Report what would be done, but don't actually change anything. ``-z``, ``--cur-zlevel`` - Restricts the operation to the currently visible z-level. + Restricts a flood fill operation to the currently visible z-level. Note ---- diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 5e6158de9..231cfdf43 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -10,6 +10,7 @@ #include "df/block_burrow.h" #include "df/burrow.h" +#include "df/map_block.h" #include "df/tile_designation.h" #include "df/unit.h" #include "df/world.h" @@ -196,10 +197,9 @@ static void get_bool_field(lua_State *L, int idx, const char *name, bool *dest) lua_pop(L, 1); } -static void get_opts(lua_State *L, int idx, bool &dry_run, bool &zlevel) { +static void get_opts(lua_State *L, int idx, bool &zlevel) { if (lua_gettop(L) < idx) return; - get_bool_field(L, idx, "dry_run", &dry_run); get_bool_field(L, idx, "zlevel", &zlevel); } @@ -234,29 +234,7 @@ static df::burrow* get_burrow(lua_State *L, int idx) { return burrow; } -static int burrow_tiles_clear(lua_State *L) { - color_ostream *out = Lua::GetOutput(L); - if (!out) - out = &Core::getInstance().getConsole(); - DEBUG(status,*out).print("entering burrow_tiles_clear\n"); - - int32_t count = 0; - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - df::burrow * burrow = get_burrow(L, -1); - if (burrow) { - count += burrow->block_x.size(); - Burrows::clearTiles(burrow); - } - lua_pop(L, 1); // remove value, leave key - } - - Lua::Push(L, count); - return 1; -} - -static void copyTiles(df::burrow *target, df::burrow *source, bool enable) -{ +static void copyTiles(df::burrow *target, df::burrow *source, bool enable) { CHECK_NULL_POINTER(target); CHECK_NULL_POINTER(source); @@ -291,12 +269,124 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable) } } +static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, + df::tile_designation d_value, bool enable) { + CHECK_NULL_POINTER(target); + + auto &blocks = world->map.map_blocks; + + for (auto block : blocks) { + 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 = Burrows::getBlockMask(target, block, enable); + if (!mask) + goto next_block; + + mask->setassignment(x, y, enable); + } + } + + if (mask && !enable && !mask->has_assignments()) + Burrows::deleteBlockMask(target, block, mask); + + next_block:; + } +} + +static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) { + CHECK_NULL_POINTER(target); + + df::tile_designation mask; + df::tile_designation value; + + 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 void copyUnits(df::burrow *target, df::burrow *source, bool enable) { + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + + if (source == target) { + if (!enable) + Burrows::clearUnits(target); + return; + } + + for (size_t i = 0; i < source->units.size(); i++) { + if (auto unit = df::unit::find(source->units[i])) + Burrows::setAssignedUnit(target, unit, enable); + } +} + +static int burrow_tiles_clear(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_clear\n"); + + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + df::burrow * burrow = get_burrow(L, -1); + if (burrow) + Burrows::clearTiles(burrow); + lua_pop(L, 1); // remove value, leave key + } + + return 0; +} + +static void tiles_set_add_remove(lua_State *L, bool do_set, bool enable) { + df::burrow *target = get_burrow(L, 1); + if (!target) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); + return; + } + + if (do_set) + Burrows::clearTiles(target); + + lua_pushnil(L); // first key + while (lua_next(L, 2)) { + if (!lua_isstring(L, -1) || !setTilesByKeyword(target, luaL_checkstring(L, -1), enable)) { + if (auto burrow = get_burrow(L, -1)) + copyTiles(target, burrow, enable); + } + lua_pop(L, 1); // remove value, leave key + } +} + static int burrow_tiles_set(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_set\n"); - // TODO + tiles_set_add_remove(L, true, true); return 0; } @@ -305,7 +395,7 @@ static int burrow_tiles_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_add\n"); - // TODO + tiles_set_add_remove(L, false, true); return 0; } @@ -314,46 +404,31 @@ static int burrow_tiles_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_remove\n"); - // TODO + tiles_set_add_remove(L, false, false); return 0; } -static int box_fill(lua_State *L, bool enable) { - df::coord pos_start, pos_end; - bool dry_run = false, zlevel = false; - +static void box_fill(lua_State *L, bool enable) { df::burrow *burrow = get_burrow(L, 1); if (!burrow) { luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); - return 0; + return; } + df::coord pos_start, pos_end; if (!get_bounds(L, 2, pos_start, pos_end)) { luaL_argerror(L, 2, "invalid box bounds"); - return 0; - } - get_opts(L, 3, dry_run, zlevel); - - if (zlevel) { - pos_start.z = *window_z; - pos_end.z = *window_z; + return; } - int32_t count = 0; for (int32_t z = pos_start.z; z <= pos_end.z; ++z) { for (int32_t y = pos_start.y; y <= pos_end.y; ++y) { for (int32_t x = pos_start.x; x <= pos_end.x; ++x) { df::coord pos(x, y, z); - if (enable != Burrows::isAssignedTile(burrow, pos)) - ++count; - if (!dry_run) - Burrows::setAssignedTile(burrow, pos, enable); + Burrows::setAssignedTile(burrow, pos, enable); } } } - - Lua::Push(L, count); - return 1; } static int burrow_tiles_box_add(lua_State *L) { @@ -361,7 +436,8 @@ static int burrow_tiles_box_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_box_add\n"); - return box_fill(L, true); + box_fill(L, true); + return 0; } static int burrow_tiles_box_remove(lua_State *L) { @@ -369,32 +445,30 @@ static int burrow_tiles_box_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_box_remove\n"); - return box_fill(L, false); + box_fill(L, false); + return 0; } -static int flood_fill(lua_State *L, bool enable) { +static void flood_fill(lua_State *L, bool enable) { df::coord start_pos; - bool dry_run = false, zlevel = false; + bool zlevel = false; df::burrow *burrow = get_burrow(L, 1); if (!burrow) { luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); - return 0; + return; } Lua::CheckDFAssign(L, &start_pos, 2); - get_opts(L, 3, dry_run, zlevel); + get_opts(L, 3, zlevel); - // record properties to match df::tile_designation *start_des = Maps::getTileDesignation(start_pos); if (!start_des) { luaL_argerror(L, 2, "invalid starting coordinates"); - return 0; + return; } uint16_t start_walk = Maps::getWalkableGroup(start_pos); - int32_t count = 0; - std::stack flood; flood.emplace(start_pos); @@ -416,9 +490,7 @@ static int flood_fill(lua_State *L, bool enable) { if (pos != start_pos && enable == Burrows::isAssignedTile(burrow, pos)) continue; - ++count; - if (!dry_run) - Burrows::setAssignedTile(burrow, pos, enable); + Burrows::setAssignedTile(burrow, pos, enable); // only go one tile outside of a walkability group if (start_walk && start_walk != Maps::getWalkableGroup(pos)) @@ -444,9 +516,6 @@ static int flood_fill(lua_State *L, bool enable) { flood.emplace(pos.x, pos.y, pos.z-1); } } - - Lua::Push(L, count); - return 1; } static int burrow_tiles_flood_add(lua_State *L) { @@ -454,7 +523,8 @@ static int burrow_tiles_flood_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_add\n"); - return flood_fill(L, true); + flood_fill(L, true); + return 0; } static int burrow_tiles_flood_remove(lua_State *L) { @@ -462,7 +532,8 @@ static int burrow_tiles_flood_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_remove\n"); - return flood_fill(L, false); + flood_fill(L, false); + return 0; } static int burrow_units_clear(lua_State *L) { @@ -470,29 +541,37 @@ static int burrow_units_clear(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_clear\n"); - // TODO - return 0; -} -static void copyUnits(df::burrow *target, df::burrow *source, bool enable) -{ - CHECK_NULL_POINTER(target); - CHECK_NULL_POINTER(source); + int32_t count = 0; + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + df::burrow * burrow = get_burrow(L, -1); + if (burrow) { + count += burrow->units.size(); + Burrows::clearUnits(burrow); + } + lua_pop(L, 1); // remove value, leave key + } - if (source == target) - { - if (!enable) - Burrows::clearUnits(target); + Lua::Push(L, count); + return 1; +} +static void units_set_add_remove(lua_State *L, bool do_set, bool enable) { + df::burrow *target = get_burrow(L, 1); + if (!target) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); return; } - for (size_t i = 0; i < source->units.size(); i++) - { - auto unit = df::unit::find(source->units[i]); + if (do_set) + Burrows::clearUnits(target); - if (unit) - Burrows::setAssignedUnit(target, unit, enable); + lua_pushnil(L); // first key + while (lua_next(L, 2)) { + if (auto burrow = get_burrow(L, -1)) + copyUnits(target, burrow, enable); + lua_pop(L, 1); // remove value, leave key } } @@ -501,7 +580,7 @@ static int burrow_units_set(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_set\n"); - // TODO + units_set_add_remove(L, true, true); return 0; } @@ -510,7 +589,7 @@ static int burrow_units_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_add\n"); - // TODO + units_set_add_remove(L, false, true); return 0; } @@ -519,7 +598,7 @@ static int burrow_units_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_remove\n"); - // TODO + units_set_add_remove(L, false, false); return 0; } @@ -540,17 +619,7 @@ DFHACK_PLUGIN_LUA_COMMANDS { }; - - - - - - - - /* - - #include "Core.h" #include "Console.h" #include "Export.h" @@ -952,72 +1021,6 @@ static df::burrow *findByName(color_ostream &out, std::string name, bool silent return rv; } - -static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, - df::tile_designation d_value, bool enable) -{ - CHECK_NULL_POINTER(target); - - 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 = Burrows::getBlockMask(target, block, enable); - if (!mask) - goto next_block; - - mask->setassignment(x, y, enable); - } - } - - if (mask && !enable && !mask->has_assignments()) - Burrows::deleteBlockMask(target, block, mask); - - next_block:; - } -} - -static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) -{ - CHECK_NULL_POINTER(target); - - df::tile_designation mask; - df::tile_designation value; - - 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; -} - DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(renameBurrow), DFHACK_LUA_FUNCTION(findByName), @@ -1033,121 +1036,4 @@ DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_END }; -static command_result burrow(color_ostream &out, vector ¶meters) -{ - CoreSuspender suspend; - - if (!active) - { - out.printerr("The plugin cannot be used without map.\n"); - return CR_FAILURE; - } - - string cmd; - if (!parameters.empty()) - cmd = parameters[0]; - - if (cmd == "enable" || cmd == "disable") - { - if (parameters.size() < 2) - return CR_WRONG_USAGE; - - bool state = (cmd == "enable"); - - for (size_t i = 1; i < parameters.size(); i++) - { - string &option = parameters[i]; - - if (option == "auto-grow") - enable_auto_grow(out, state); - else - return CR_WRONG_USAGE; - } - } - else if (cmd == "clear-units") - { - if (parameters.size() < 2) - return CR_WRONG_USAGE; - - for (size_t i = 1; i < parameters.size(); i++) - { - auto target = findByName(out, parameters[i]); - if (!target) - return CR_WRONG_USAGE; - - Burrows::clearUnits(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") - Burrows::clearUnits(target); - - bool enable = (cmd != "remove-units"); - - for (size_t 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 (size_t i = 1; i < parameters.size(); i++) - { - auto target = findByName(out, parameters[i]); - if (!target) - return CR_WRONG_USAGE; - - Burrows::clearTiles(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") - Burrows::clearTiles(target); - - bool enable = (cmd != "remove-tiles"); - - for (size_t 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 != "?") - out.printerr("Invalid command: %s\n", cmd.c_str()); - return CR_WRONG_USAGE; - } - - return CR_OK; -} */ diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 9b7d8c63d..be4a51dd4 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -9,6 +9,7 @@ local _ENV = mkmodule('plugins.burrow') --]] +local argparse = require('argparse') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') @@ -164,9 +165,9 @@ rawset_default(_ENV, dfhack.burrows) -- commandline handling -- -local function set_add_remove(mode, which, params, opts) +local function set_add_remove(mode, which, params, _) local target_burrow = table.remove(params, 1) - return _ENV[('burrow_%s_%s'):format(mode, which)](target_burrow, params, opts) + _ENV[('burrow_%s_%s'):format(mode, which)](target_burrow, params) end local function tiles_box_add_remove(which, params, opts) @@ -174,39 +175,40 @@ local function tiles_box_add_remove(which, params, opts) local pos1 = argparse.coords(params[1] or 'here', 'pos') local pos2 = opts.cursor or argparse.coords(params[2] or 'here', 'pos') local bounds = get_bounds(pos1, pos2) - return _ENV['burrow_tiles_box_'..which](target_burrow, bounds, opts) + _ENV['burrow_tiles_box_'..which](target_burrow, bounds) end local function tiles_flood_add_remove(which, params, opts) local target_burrow = table.remove(params, 1) local pos = opts.cursor or argparse.coords('here', 'pos') - return _ENV['burrow_tiles_flood_'..which](target_burrow, pos, opts) + _ENV['burrow_tiles_flood_'..which](target_burrow, pos, opts) end local function run_command(mode, command, params, opts) if mode == 'tiles' then if command == 'clear' then - return burrow_tiles_clear(params, opts) + burrow_tiles_clear(params) elseif command == 'set' or command == 'add' or command == 'remove' then - return set_add_remove('tiles', command, params, opts) + set_add_remove('tiles', command, params, opts) elseif command == 'box-add' or command == 'box-remove' then - return tiles_box_add_remove(command:sub(5), params, opts) + tiles_box_add_remove(command:sub(5), params, opts) elseif command == 'flood-add' or command == 'flood-remove' then - return tiles_flood_add_remove(command:sub(7), params, opts) + tiles_flood_add_remove(command:sub(7), params, opts) else return false end elseif mode == 'units' then if command == 'clear' then - return burrow_units_clear(params) + burrow_units_clear(params) elseif command == 'set' or command == 'add' or command == 'remove' then - return set_add_remove('units', command, params, opts) + set_add_remove('units', command, params, opts) else return false end else return false end + return true end function parse_commandline(...) @@ -219,7 +221,6 @@ function parse_commandline(...) local positionals = argparse.processArgsGetopt(args, { {'c', 'cursor', hasArg=true, handler=function(optarg) opts.cursor = argparse.coords(optarg, 'cursor') end}, - {'d', 'dry-run', handler=function() opts.dry_run = true end}, {'h', 'help', handler=function() opts.help = true end}, {'z', 'cur-zlevel', handler=function() opts.zlevel = true end}, }) @@ -234,7 +235,7 @@ function parse_commandline(...) if not ret then return false end - print(('%d %s affected'):format(ret, mode)) + print('done') return true end