diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 5b86950b1..4d6316245 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -2702,9 +2702,15 @@ For more details, use ``tiletypes help``. tiletypes-command ----------------- -Runs tiletypes commands, separated by ;. This makes it possible to change +Runs tiletypes commands, separated by ``;``. This makes it possible to change tiletypes modes from a hotkey or via dfhack-run. +Example:: + + tiletypes-command p any ; p s wall ; p sp normal + +This resets the paint filter to unsmoothed walls. + .. _tiletypes-here: tiletypes-here @@ -2712,6 +2718,16 @@ tiletypes-here Apply the current tiletypes options at the in-game cursor position, including the brush. Can be used from a hotkey. +Options: + +:``-c``, ``--cursor ,,``: + Use the specified map coordinates instead of the current cursor position. If + this option is specified, then an active game map cursor is not necessary. +:``-h``, ``--help``: + Show command help text. +:``-q``, ``--quiet``: + Suppress non-error status output. + .. _tiletypes-here-point: tiletypes-here-point @@ -2719,6 +2735,8 @@ tiletypes-here-point Apply the current tiletypes options at the in-game cursor position to a single tile. Can be used from a hotkey. +This command supports the same options as `tiletypes-here` above. + .. _tubefill: tubefill diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index de6388050..92e2e9dbd 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -167,7 +167,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(stocks stocks.cpp) dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp) - dfhack_plugin(tiletypes tiletypes.cpp Brushes.h) + dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) dfhack_plugin(title-folder title-folder.cpp) dfhack_plugin(title-version title-version.cpp) dfhack_plugin(trackstop trackstop.cpp) diff --git a/plugins/lua/tiletypes.lua b/plugins/lua/tiletypes.lua new file mode 100644 index 000000000..ba2468696 --- /dev/null +++ b/plugins/lua/tiletypes.lua @@ -0,0 +1,29 @@ +local _ENV = mkmodule('plugins.tiletypes') + +local utils = require('utils') + +local function parse_cursor(opts, arg) + local _, _, x, y, z = arg:find('^%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*$') + if not x then + qerror(('invalid argument for --cursor option: "%s"; expected format' .. + ' is ",,", for example: "30,60,150"'):format(arg)) + end + opts.cursor.x = tonumber(x) + opts.cursor.y = tonumber(y) + opts.cursor.z = tonumber(z) +end + +function parse_commandline(opts, ...) + local positionals = utils.processArgsGetopt({...}, { + {'c', 'cursor', hasArg=true, + handler=function(arg) parse_cursor(opts, arg) end}, + {'h', 'help', handler=function() opts.help = true end}, + {'q', 'quiet', handler=function() opts.quiet = true end}, + }) + + if positionals[1] == 'help' or positionals[1] == '?' then + opts.help = true + end +end + +return _ENV diff --git a/plugins/tiletypes.cpp b/plugins/tiletypes.cpp index 7487ef649..602a5a1a8 100644 --- a/plugins/tiletypes.cpp +++ b/plugins/tiletypes.cpp @@ -34,6 +34,7 @@ using std::set; #include "Console.h" #include "Core.h" #include "Export.h" +#include "LuaTools.h" #include "PluginManager.h" #include "TileTypes.h" @@ -53,6 +54,25 @@ using namespace df::enums; DFHACK_PLUGIN("tiletypes"); REQUIRE_GLOBAL(world); +struct tiletypes_options { + // whether to display help + bool help = false; + bool quiet = false; + + // if set, then use this position instead of the active game cursor + df::coord cursor; + + static struct_identity _identity; +}; +static const struct_field_info tiletypes_options_fields[] = { + { struct_field_info::PRIMITIVE, "help", offsetof(tiletypes_options, help), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::PRIMITIVE, "quiet", offsetof(tiletypes_options, quiet), &df::identity_traits::identity, 0, 0 }, + { struct_field_info::SUBSTRUCT, "cursor", offsetof(tiletypes_options, cursor), &df::coord::_identity, 0, 0 }, + { struct_field_info::END } +}; +struct_identity tiletypes_options::_identity(sizeof(tiletypes_options), &df::allocator_fn, NULL, "tiletypes_options", NULL, tiletypes_options_fields); + + CommandHistory tiletypes_hist; command_result df_tiletypes (color_ostream &out, vector & parameters); @@ -713,7 +733,8 @@ bool processTileType(color_ostream & out, TileType &paint, std::vectorpoints(map, cursor); out.print("working...\n"); @@ -877,12 +910,13 @@ command_result executePaintJob(color_ostream &out) if (failures > 0) out.printerr("Could not update %d tiles of %zu.\n", failures, all_tiles.size()); - else + else if (!opts.quiet) out.print("Processed %zu tiles.\n", all_tiles.size()); if (map.WriteAll()) { - out.print("OK\n"); + if (!opts.quiet) + out.print("OK\n"); return CR_OK; } else @@ -894,9 +928,10 @@ command_result executePaintJob(color_ostream &out) command_result processCommand(color_ostream &out, std::vector &commands, int start, int end, bool & endLoop, bool hasConsole = false) { + tiletypes_options opts; if (commands.size() == size_t(start)) { - return executePaintJob(out); + return executePaintJob(out, opts); } int loc = start; @@ -951,7 +986,7 @@ command_result processCommand(color_ostream &out, std::vector &comm } else if (command == "run" || command.empty()) { - executePaintJob(out); + executePaintJob(out, opts); } return CR_OK; @@ -1028,43 +1063,71 @@ command_result df_tiletypes_command (color_ostream &out, vector & param return CR_OK; } +static bool get_options(color_ostream &out, + tiletypes_options &opts, + const vector ¶meters) +{ + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + + if (!lua_checkstack(L, parameters.size() + 2) || + !Lua::PushModulePublic( + out, L, "plugins.tiletypes", "parse_commandline")) + { + out.printerr("Failed to load tiletypes Lua code\n"); + return false; + } + + Lua::Push(L, &opts); + + for (const string ¶m : parameters) + Lua::Push(L, param); + + if (!Lua::SafeCall(out, L, parameters.size() + 1, 0)) + return false; + + return true; +} + command_result df_tiletypes_here (color_ostream &out, vector & parameters) { - for(size_t i = 0; i < parameters.size();i++) + tiletypes_options opts; + if (!get_options(out, opts, parameters) || opts.help) { - if(parameters[i] == "help" || parameters[i] == "?") - { - out << "This command is supposed to be mapped to a hotkey." << endl; - out << "It will use the current/last parameters set in tiletypes (including brush settings!)." << endl; - return CR_OK; - } + out << "This command is supposed to be mapped to a hotkey." << endl; + out << "It will use the current/last parameters set in tiletypes (including brush settings!)." << endl; + return opts.help ? CR_OK : CR_FAILURE; } - out.print("Run tiletypes-here with these parameters: "); - printState(out); + if (!opts.quiet) + { + out.print("Run tiletypes-here with these parameters: "); + printState(out); + } - return executePaintJob(out); + return executePaintJob(out, opts); } command_result df_tiletypes_here_point (color_ostream &out, vector & parameters) { - for(size_t i = 0; i < parameters.size();i++) + tiletypes_options opts; + if (!get_options(out, opts, parameters) || opts.help) { - if(parameters[i] == "help" || parameters[i] == "?") - { - out << "This command is supposed to be mapped to a hotkey." << endl; - out << "It will use the current/last parameters set in tiletypes (except with a point brush)." << endl; - return CR_OK; - } + out << "This command is supposed to be mapped to a hotkey." << endl; + out << "It will use the current/last parameters set in tiletypes (except with a point brush)." << endl; + return opts.help ? CR_OK : CR_FAILURE; } Brush *old = brush; brush = new RectangleBrush(1, 1); - out.print("Run tiletypes-here with these parameters: "); - printState(out); + if (!opts.quiet) + { + out.print("Run tiletypes-here-point with these parameters: "); + printState(out); + } - command_result rv = executePaintJob(out); + command_result rv = executePaintJob(out, opts); delete brush; brush = old;