From f3c7a685f5b6d84bff6193ad289df3cda634a4ee Mon Sep 17 00:00:00 2001 From: Jared Adams Date: Sun, 15 Apr 2012 08:40:19 -0600 Subject: [PATCH] Make tiletypes more useful * Paint, filter, and brush state is now saved between calls. * Added 'all' paint option to set material, shape, special, and variant at the same time. * Added tiletypes-here (like liquids here, except is uses the saved brush settings) * Added tiletypes-here-point (like liquids here, always only the tile under the cursor) * Added tiletypes-command: runs tiletypes commands seperated by ';' tokens (affects saved state) * Make the internal workings match liquids a bit more * Give brush objects a descriptor string * Make Core::cheap_tokenise available --- library/Core.cpp | 6 +- library/include/Core.h | 2 + plugins/Brushes.h | 23 + plugins/tiletypes.cpp | 937 ++++++++++++++++++++++++----------------- 4 files changed, 582 insertions(+), 386 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index e6b9c45ff..111a88019 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -118,7 +118,7 @@ struct Core::Private } }; -void cheap_tokenise(string const& input, vector &output) +void Core::cheap_tokenise(string const& input, vector &output) { string *cur = NULL; @@ -177,7 +177,7 @@ void fHKthread(void * iodata) color_ostream_proxy out(core->getConsole()); vector args; - cheap_tokenise(stuff, args); + Core::cheap_tokenise(stuff, args); if (args.empty()) { out.printerr("Empty hotkey command.\n"); continue; @@ -218,7 +218,7 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue { // cut the input into parts vector parts; - cheap_tokenise(command,parts); + Core::cheap_tokenise(command,parts); if(parts.size() == 0) { clueless_counter ++; diff --git a/library/include/Core.h b/library/include/Core.h index f8ac8e783..a97574692 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -135,6 +135,8 @@ namespace DFHack PluginManager *getPluginManager() { return plug_mgr; } + static void cheap_tokenise(std::string const& input, std::vector &output); + private: DFHack::Console con; diff --git a/plugins/Brushes.h b/plugins/Brushes.h index 73c3a05a9..97ddc44c0 100644 --- a/plugins/Brushes.h +++ b/plugins/Brushes.h @@ -6,6 +6,9 @@ class Brush public: virtual ~Brush(){}; virtual coord_vec points(MapExtras::MapCache & mc,DFHack::DFCoord start) = 0; + virtual std::string str() const { + return "unknown"; + } }; /** * generic 3D rectangle brush. you can specify the dimensions of @@ -56,6 +59,13 @@ public: return v; }; ~RectangleBrush(){}; + std::string str() const { + if (x_ == 1 && y_ == 1 && z_ == 1) { + return "point"; + } else { + return "rectangle"; + } + } private: int x_, y_, z_; int cx_, cy_, cz_; @@ -89,6 +99,9 @@ public: } return v; }; + std::string str() const { + return "block"; + } }; /** @@ -117,6 +130,9 @@ public: } return v; }; + std::string str() const { + return "column"; + } }; /** @@ -168,6 +184,9 @@ public: return v; } + std::string str() const { + return "flood"; + } private: void maybeFlood(DFCoord c, std::stack &to_flood, MapExtras::MapCache &mc) { if (mc.testCoord(c)) { @@ -176,3 +195,7 @@ private: } Core *c_; }; + +std::ostream &operator<<(std::ostream &stream, const Brush& brush) { + stream << brush.str(); +} diff --git a/plugins/tiletypes.cpp b/plugins/tiletypes.cpp index 61b4ec8e7..41627a852 100644 --- a/plugins/tiletypes.cpp +++ b/plugins/tiletypes.cpp @@ -1,4 +1,24 @@ +// Plugin tiletypes // +// This plugin allows fine editing of individual game tiles (expect for +// changing material subtypes). +// +// Commands: +// tiletypes - runs the interractive interpreter +// tiletypes-command - run the given command +// (intended to be mapped to a hotkey or used from dfhack-run) +// tiletypes-here - runs the execute method with the last settings from +// tiletypes(-command), including brush! +// (intended to be mapped to a hotkey) +// tiletypes-here-point - runs the execute method with the last settings from +// tiletypes(-command), except with a point brush! +// (intended to be mapped to a hotkey) +// Options (everything but tiletypes-command): +// ?, help - print some help +// +// Options (tiletypes-command): +// (anything) - run the given command + #include #include #include @@ -25,39 +45,120 @@ using namespace MapExtras; using namespace DFHack; using namespace df::enums; -//zilpin: These two functions were giving me compile errors in VS2008, so I cheated with the C style loop below, just to get it to build. -//Original code is commented out. -void tolower(std::string &str) -{ - //The C++ way... - //std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::tolower ), std::locale(""))); +CommandHistory tiletypes_hist; - //The C way... - for(char *c=(char *)str.c_str(); *c; ++c) - { - *c = tolower(*c); - } +command_result df_tiletypes (color_ostream &out, vector & parameters); +command_result df_tiletypes_command (color_ostream &out, vector & parameters); +command_result df_tiletypes_here (color_ostream &out, vector & parameters); +command_result df_tiletypes_here_point (color_ostream &out, vector & parameters); + +DFHACK_PLUGIN("tiletypes"); + +DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) +{ + tiletypes_hist.load("tiletypes.history"); + commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true)); + commands.push_back(PluginCommand("tiletypes-command", "Run the given commands (seperated by ' ; '; an empty command is the same as run).", df_tiletypes_command)); + commands.push_back(PluginCommand("tiletypes-here", "Use the last settings from tiletypes, including brush, at cursor location.", df_tiletypes_here)); + commands.push_back(PluginCommand("tiletypes-here-point", "Use the last settings from tiletypes, not including brush, at cursor location.", df_tiletypes_here_point)); + return CR_OK; } -void toupper(std::string &str) +DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { - //std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::toupper), std::locale(""))); - for(char *c=(char *)str.c_str(); *c; ++c) - { - *c = toupper(*c); - } + tiletypes_hist.save("tiletypes.history"); + return CR_OK; } -int toint(const std::string &str, int failValue = 0) +void help( color_ostream & out, std::vector &commands, int start, int end) { - std::istringstream ss(str); - int valInt; - ss >> valInt; - if (ss.fail()) + std::string option = commands.size() > start ? commands[start] : ""; + if (option.empty()) { - return failValue; + out << "Commands:" << std::endl + << " quit / q : quit" << std::endl + << " filter / f [options] : change filter options" << std::endl + << " paint / p [options] : change paint options" << std::endl + << " point / p : set point brush" << std::endl + << " range / r [w] [h] [z] : set range brush" << std::endl + << " block : set block brush" << std::endl + << " column : set column brush" << std::endl + << " run / (empty) : paint!" << std::endl + << std::endl + << "Filter/paint options:" << std::endl + << " Shape / sh / s: set tile shape information" << std::endl + << " Material / mat / m: set tile material information" << std::endl + << " Special / sp: set special tile information" << std::endl + << " Variant / var / v: set variant tile information" << std::endl + << " All / a: set the four above at the same time (no ANY support)" << std::endl + << " Designated / d: set designated flag" << std::endl + << " Hidden / h: set hidden flag" << std::endl + << " Light / l: set light flag" << std::endl + << " Subterranean / st: set subterranean flag" << std::endl + << " Skyview / sv: set skyview flag" << std::endl + << "See help [option] for more information" << std::endl; + } + else if (option == "shape" || option == "s" ||option == "sh") + { + out << "Available shapes:" << std::endl + << " ANY" << std::endl; + FOR_ENUM_ITEMS(tiletype_shape,i) + { + out << " " << ENUM_KEY_STR(tiletype_shape,i) << std::endl; + } + } + else if (option == "material"|| option == "mat" ||option == "m") + { + out << "Available materials:" << std::endl + << " ANY" << std::endl; + FOR_ENUM_ITEMS(tiletype_material,i) + { + out << " " << ENUM_KEY_STR(tiletype_material,i) << std::endl; + } + } + else if (option == "special" || option == "sp") + { + out << "Available specials:" << std::endl + << " ANY" << std::endl; + FOR_ENUM_ITEMS(tiletype_special,i) + { + out << " " << ENUM_KEY_STR(tiletype_special,i) << std::endl; + } + } + else if (option == "variant" || option == "var" || option == "v") + { + out << "Available variants:" << std::endl + << " ANY" << std::endl; + FOR_ENUM_ITEMS(tiletype_variant,i) + { + out << " " << ENUM_KEY_STR(tiletype_variant,i) << std::endl; + } + } + else if (option == "designated" || option == "d") + { + out << "Available designated flags:" << std::endl + << " ANY, 0, 1" << std::endl; + } + else if (option == "hidden" || option == "h") + { + out << "Available hidden flags:" << std::endl + << " ANY, 0, 1" << std::endl; + } + else if (option == "light" || option == "l") + { + out << "Available light flags:" << std::endl + << " ANY, 0, 1" << std::endl; + } + else if (option == "subterranean" || option == "st") + { + out << "Available subterranean flags:" << std::endl + << " ANY, 0, 1" << std::endl; + } + else if (option == "skyview" || option == "sv") + { + out << "Available skyview flags:" << std::endl + << " ANY, 0, 1" << std::endl; } - return valInt; } struct TileType @@ -217,12 +318,116 @@ std::ostream &operator<<(std::ostream &stream, const TileType &paint) return stream; } -bool processTileType(TileType &paint, const std::string &option, const std::string &value) +static TileType filter, paint; +static Brush *brush = new RectangleBrush(1,1); + +void printState(color_ostream &out) { - std::string val = value; - toupper(val); + out << "Filter: " << filter << std::endl + << "Paint: " << paint << std::endl + << "Brush: " << brush->str() << std::endl; +} + +//zilpin: These two functions were giving me compile errors in VS2008, so I cheated with the C style loop below, just to get it to build. +//Original code is commented out. +void tolower(std::string &str) +{ + //The C++ way... + //std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::tolower ), std::locale(""))); + + //The C way... + for(char *c=(char *)str.c_str(); *c; ++c) + { + *c = tolower(*c); + } +} + +void toupper(std::string &str) +{ + //std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(&std::toupper), std::locale(""))); + for(char *c=(char *)str.c_str(); *c; ++c) + { + *c = toupper(*c); + } +} + +int toint(const std::string &str, int failValue = 0) +{ + std::istringstream ss(str); int valInt; - if (val == "ANY") + ss >> valInt; + if (ss.fail()) + { + return failValue; + } + return valInt; +} + +bool tryShape(std::string value, TileType &paint) +{ + FOR_ENUM_ITEMS(tiletype_shape,i) + { + if (value == ENUM_KEY_STR(tiletype_shape,i)) + { + paint.shape = i; + return true; + } + } + return false; +} + +bool tryMaterial(std::string value, TileType &paint) +{ + FOR_ENUM_ITEMS(tiletype_material, i) + { + if (value == ENUM_KEY_STR(tiletype_material,i)) + { + paint.material = i; + return true; + } + } + return false; +} + +bool trySpecial(std::string value, TileType &paint) +{ + FOR_ENUM_ITEMS(tiletype_special, i) + { + if (value == ENUM_KEY_STR(tiletype_special,i)) + { + paint.special = i; + return true; + } + } + return false; +} + +bool tryVariant(std::string value, TileType &paint) +{ + FOR_ENUM_ITEMS(tiletype_variant, i) + { + if (value == ENUM_KEY_STR(tiletype_variant,i)) + { + paint.variant = i; + return true; + } + } + return false; +} + +bool processTileType(color_ostream & out, TileType &paint, std::vector ¶ms, int start, int end) +{ + if (params.size() < start + 2) + { + return false; + } + + int loc = start; + std::string option = params[loc++]; + std::string value = params[loc++]; + toupper(value); + int valInt; + if (value == "ANY") { valInt = -1; } @@ -241,19 +446,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - FOR_ENUM_ITEMS(tiletype_shape,i) + if (!tryShape(value, paint)) { - if (val == ENUM_KEY_STR(tiletype_shape,i)) - { - paint.shape = i; - found = true; - break; - } - } - - if (!found) - { - std::cout << "Unknown tile shape: " << value << std::endl; + out << "Unknown tile shape: " << value << std::endl; } } } @@ -266,19 +461,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - FOR_ENUM_ITEMS(tiletype_material, i) - { - if (val == ENUM_KEY_STR(tiletype_material,i)) - { - paint.material = i; - found = true; - break; - } - } - - if (!found) + if (!tryMaterial(value, paint)) { - std::cout << "Unknown tile material: " << value << std::endl; + out << "Unknown tile material: " << value << std::endl; } } } @@ -291,19 +476,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - FOR_ENUM_ITEMS(tiletype_special, i) + if (!trySpecial(value, paint)) { - if (val == ENUM_KEY_STR(tiletype_special,i)) - { - paint.special = i; - found = true; - break; - } - } - - if (!found) - { - std::cout << "Unknown tile special: " << value << std::endl; + out << "Unknown tile special: " << value << std::endl; } } } @@ -316,19 +491,9 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - FOR_ENUM_ITEMS(tiletype_variant, i) + if (!tryVariant(value, paint)) { - if (val == ENUM_KEY_STR(tiletype_variant,i)) - { - paint.variant = i; - found = true; - break; - } - } - - if (!found) - { - std::cout << "Unknown tile variant: " << value << std::endl; + out << "Unknown tile variant: " << value << std::endl; } } } @@ -341,7 +506,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - std::cout << "Unknown designation flag: " << value << std::endl; + out << "Unknown designation flag: " << value << std::endl; } } else if (option == "hidden" || option == "h") @@ -353,7 +518,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - std::cout << "Unknown hidden flag: " << value << std::endl; + out << "Unknown hidden flag: " << value << std::endl; } } else if (option == "light" || option == "l") @@ -365,7 +530,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - std::cout << "Unknown light flag: " << value << std::endl; + out << "Unknown light flag: " << value << std::endl; } } else if (option == "subterranean" || option == "st") @@ -377,7 +542,7 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - std::cout << "Unknown subterranean flag: " << value << std::endl; + out << "Unknown subterranean flag: " << value << std::endl; } } else if (option == "skyview" || option == "sv") @@ -389,380 +554,386 @@ bool processTileType(TileType &paint, const std::string &option, const std::stri } else { - std::cout << "Unknown skyview flag: " << value << std::endl; + out << "Unknown skyview flag: " << value << std::endl; + } + } + else if (option == "all" || option == "a") + { + for (; loc < end; loc++) + { + std::string param = params[loc]; + toupper(param); + + if (!(tryShape(param, paint) || tryMaterial(param, paint) || + trySpecial(param, paint) || tryVariant(param, paint))) + { + out << "Unknown description: '" << param << "'" << std::endl; + break; + } } + + found = true; } else { - std::cout << "Unknown option: '" << option << "'" << std::endl; + out << "Unknown option: '" << option << "'" << std::endl; } return found; } -void help( std::ostream & out, const std::string &option) +command_result executePaintJob(color_ostream &out) { - if (option.empty()) + if (paint.empty()) { - out << "Commands:" << std::endl - << " quit / q : quit" << std::endl - << " filter / f [options] : change filter options" << std::endl - << " paint / p [options] : change paint options" << std::endl - << " point / p : set point brush" << std::endl - << " range / r : set range brush" << std::endl - << " block : set block brush" << std::endl - << " column : set column brush" << std::endl - << std::endl - << "Filter/paint options:" << std::endl - << " Shape / sh / s: set tile shape information" << std::endl - << " Material / mat / m: set tile material information" << std::endl - << " Special / sp: set special tile information" << std::endl - << " Variant / var / v: set variant tile information" << std::endl - << " Designated / d: set designated flag" << std::endl - << " Hidden / h: set hidden flag" << std::endl - << " Light / l: set light flag" << std::endl - << " Subterranean / st: set subterranean flag" << std::endl - << " Skyview / sv: set skyview flag" << std::endl - << "See help [option] for more information" << std::endl; + out.printerr("Set the paint first.\n"); + return CR_OK; } - else if (option == "shape" || option == "s" ||option == "sh") + + CoreSuspender suspend; + uint32_t x_max = 0, y_max = 0, z_max = 0; + int32_t x = 0, y = 0, z = 0; + + if (!Maps::IsValid()) { - out << "Available shapes:" << std::endl - << " ANY" << std::endl; - FOR_ENUM_ITEMS(tiletype_shape,i) - { - out << " " << ENUM_KEY_STR(tiletype_shape,i) << std::endl; - } + out.printerr("Map is not available!\n"); + return CR_FAILURE; } - else if (option == "material"|| option == "mat" ||option == "m") + Maps::getSize(x_max, y_max, z_max); + + if (!Gui::getCursorCoords(x,y,z)) { - out << "Available materials:" << std::endl - << " ANY" << std::endl; - FOR_ENUM_ITEMS(tiletype_material,i) - { - out << " " << ENUM_KEY_STR(tiletype_material,i) << std::endl; - } + out.printerr("Can't get cursor coords! Make sure you have a cursor active in DF.\n"); + return CR_FAILURE; } - else if (option == "special" || option == "sp") + out.print("Cursor coords: (%d, %d, %d)\n", x, y, z); + + DFHack::DFCoord cursor(x,y,z); + MapExtras::MapCache map; + coord_vec all_tiles = brush->points(map, cursor); + out.print("working...\n"); + + for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter) { - out << "Available specials:" << std::endl - << " ANY" << std::endl; - FOR_ENUM_ITEMS(tiletype_special,i) + const df::tiletype source = map.tiletypeAt(*iter); + df::tile_designation des = map.designationAt(*iter); + + if ((filter.shape > -1 && filter.shape != tileShape(source)) + || (filter.material > -1 && filter.material != tileMaterial(source)) + || (filter.special > -1 && filter.special != tileSpecial(source)) + || (filter.variant > -1 && filter.variant != tileVariant(source)) + || (filter.dig > -1 && (filter.dig != 0) != (des.bits.dig != tile_dig_designation::No)) + ) { - out << " " << ENUM_KEY_STR(tiletype_special,i) << std::endl; + return CR_OK; } - } - else if (option == "variant" || option == "var" || option == "v") - { - out << "Available variants:" << std::endl - << " ANY" << std::endl; - FOR_ENUM_ITEMS(tiletype_variant,i) + + df::tiletype_shape shape = paint.shape; + if (shape == tiletype_shape::NONE) { - out << " " << ENUM_KEY_STR(tiletype_variant,i) << std::endl; + shape = tileShape(source); + } + + df::tiletype_material material = paint.material; + if (material == tiletype_material::NONE) + { + material = tileMaterial(source); + } + + df::tiletype_special special = paint.special; + if (special == tiletype_special::NONE) + { + special = tileSpecial(source); + } + df::tiletype_variant variant = paint.variant; + /* + * FIXME: variant should be: + * 1. If user variant: + * 2. If user variant \belongs target variants + * 3. use user variant + * 4. Else + * 5. use variant 0 + * 6. If the source variant \belongs target variants + * 7 use source variant + * 8 ElseIf num target shape/material variants > 1 + * 9. pick one randomly + * 10.Else + * 11. use variant 0 + * + * The following variant check has been disabled because it's severely limiting + * the usefullness of the tool. + */ + /* + if (variant == tiletype_variant::NONE) + { + variant = tileVariant(source); + } + */ + // Remove direction from directionless tiles + DFHack::TileDirection direction = tileDirection(source); + if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH))) + { + direction.whole = 0; + } + + df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction); + // hack for empty space + if (shape == tiletype_shape::EMPTY && material == tiletype_material::AIR && variant == tiletype_variant::VAR_1 && special == tiletype_special::NORMAL && direction.whole == 0) + { + type = tiletype::OpenSpace; + } + // make sure it's not invalid + if(type != tiletype::Void) + map.setTiletypeAt(*iter, type); + + if (paint.hidden > -1) + { + des.bits.hidden = paint.hidden; + } + + if (paint.light > -1) + { + des.bits.light = paint.light; + } + + if (paint.subterranean > -1) + { + des.bits.subterranean = paint.subterranean; } + + if (paint.skyview > -1) + { + des.bits.outside = paint.skyview; + } + + // Remove liquid from walls, etc + if (type != -1 && !DFHack::FlowPassable(type)) + { + des.bits.flow_size = 0; + //des.bits.liquid_type = DFHack::liquid_water; + //des.bits.water_table = 0; + des.bits.flow_forbid = 0; + //des.bits.liquid_static = 0; + //des.bits.water_stagnant = 0; + //des.bits.water_salt = 0; + } + + map.setDesignationAt(*iter, des); } - else if (option == "designated" || option == "d") + + if (map.WriteAll()) { - out << "Available designated flags:" << std::endl - << " ANY, 0, 1" << std::endl; + out.print("OK\n"); } - else if (option == "hidden" || option == "h") + else { - out << "Available hidden flags:" << std::endl - << " ANY, 0, 1" << std::endl; + out.printerr("Something failed horribly! RUN!\n"); + return CR_FAILURE; } - else if (option == "light" || option == "l") +} + +command_result processCommand(color_ostream &out, std::vector &commands, int start, int end, bool & endLoop, bool hasConsole = false) +{ + if (commands.size() == start) { - out << "Available light flags:" << std::endl - << " ANY, 0, 1" << std::endl; + return executePaintJob(out); } - else if (option == "subterranean" || option == "st") + + std::ostringstream ss_o; + int loc = start; + + std::string command = commands[loc++]; + tolower(command); + + if (command == "help" || command == "?") { - out << "Available subterranean flags:" << std::endl - << " ANY, 0, 1" << std::endl; + help(out, commands, loc, end); } - else if (option == "skyview" || option == "sv") + else if (command == "quit" || command == "q") { - out << "Available skyview flags:" << std::endl - << " ANY, 0, 1" << std::endl; + endLoop = true; } -} + else if (command == "filter" || command == "f") + { + processTileType(out, filter, commands, loc, end); + } + else if (command == "paint" || (command == "p" && commands.size() > 1)) + { + processTileType(out, paint, commands, loc, end); + } + else if (command == "point" || command == "p") + { + delete brush; + brush = new RectangleBrush(1,1); + } + else if (command == "range" || command == "r") + { + int width = 0, height = 0, z_levels = 0; -CommandHistory tiletypes_hist; + if (commands.size() > loc + 1) + { + width = toint(commands[loc++]); + height = toint(commands[loc++]); -command_result df_tiletypes (color_ostream &out, vector & parameters); + if (commands.size() > loc) { + z_levels = toint(commands[loc++]); + } + } -DFHACK_PLUGIN("tiletypes"); + if (width < 1 || height < 1) { + if (hasConsole) { + Console &con = static_cast(out); + CommandHistory hist; -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - tiletypes_hist.load("tiletypes.history"); - commands.push_back(PluginCommand("tiletypes", "Paint map tiles freely, similar to liquids.", df_tiletypes, true)); - return CR_OK; -} + ss_o << "Set range width <" << width << "> "; + con.lineedit(ss_o.str(),command,hist); + width = command == "" ? width : toint(command); + + ss_o.str(""); + ss_o << "Set range height <" << height << "> "; + con.lineedit(ss_o.str(),command,hist); + height = command == "" ? height : toint(command); + + ss_o.str(""); + ss_o << "Set range z-levels <" << z_levels << "> "; + con.lineedit(ss_o.str(),command,hist); + z_levels = command == "" ? z_levels : toint(command); + } else { + return CR_WRONG_USAGE; + } + } + + if (width < 1) width = 1; + if (height < 1) height = 1; + if (z_levels < 1) z_levels = 1; + + delete brush; + brush = new RectangleBrush(width, height, z_levels, 0, 0, 0); + } + else if (command == "block") + { + delete brush; + brush = new BlockBrush(); + } + else if (command == "column") + { + delete brush; + brush = new ColumnBrush(); + } + else if (command == "run" || command.empty()) + { + executePaintJob(out); + } -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - tiletypes_hist.save("tiletypes.history"); return CR_OK; } -command_result df_tiletypes (color_ostream &out, vector & parameters) +command_result df_tiletypes (color_ostream &out_, vector & parameters) { - uint32_t x_max = 0, y_max = 0, z_max = 0; - int32_t x = 0, y = 0, z = 0; - for(size_t i = 0; i < parameters.size();i++) { if(parameters[i] == "help" || parameters[i] == "?") { - out.print("This tool allows painting tiles types with a brush, using an optional filter.\n" - "The tool is interactive, similarly to the liquids tool.\n" - "Further help is available inside.\n" + out_.print("This tool allows painting tiles types with a brush, using an optional filter.\n" + "The tool is interactive, similarly to the liquids tool.\n" + "Further help is available inside.\n" ); return CR_OK; } } - if(!out.is_console()) + if(!out_.is_console()) return CR_FAILURE; - Console &con = static_cast(out); + Console &out = static_cast(out_); - TileType filter, paint; - Brush *brush = new RectangleBrush(1,1); + std::vector commands; bool end = false; - std::string brushname = "point"; - int width = 1, height = 1, z_levels = 1; - con << "Welcome to the tiletype tool.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl; - con.printerr("THIS TOOL CAN BE DANGEROUS. YOU'VE BEEN WARNED.\n"); + out << "Welcome to the tiletype tool.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl; + out.printerr("THIS TOOL CAN BE DANGEROUS. YOU'VE BEEN WARNED.\n"); while (!end) { - con << "Filter: " << filter << std::endl - << "Paint: " << paint << std::endl - << "Brush: " << brushname << std::endl; + printState(out); std::string input = ""; - std::string command = ""; - std::string option = ""; - std::string value = ""; - con.lineedit("tiletypes> ",input,tiletypes_hist); - tiletypes_hist.add(input); - std::istringstream ss(input); - ss >> command >> option >> value; - tolower(command); - tolower(option); + if (out.lineedit("tiletypes> ",input,tiletypes_hist) == -1) + return CR_FAILURE; - if (command == "help" || command == "?") - { - help(con,option); - } - else if (command == "quit" || command == "q") - { - end = true; - } - else if (command == "filter" || command == "f") - { - processTileType(filter, option, value); - } - else if (command == "paint" || (command == "p" && !option.empty())) - { - processTileType(paint, option, value); - } - else if (command == "point" || command == "p") + commands.clear(); + Core::cheap_tokenise(input, commands); + + command_result ret = processCommand(out, commands, 0, commands.size(), end, true); + + if (ret != CR_OK) { - delete brush; - brushname = "point"; - brush = new RectangleBrush(1,1); + return ret; } - else if (command == "range" || command == "r") - { - std::stringstream ss; - CommandHistory hist; - ss << "Set range width <" << width << "> "; - con.lineedit(ss.str(),command,hist); - width = command == "" ? width : toint(command); - if (width < 1) width = 1; - - ss.str(""); - ss << "Set range height <" << height << "> "; - con.lineedit(ss.str(),command,hist); - height = command == "" ? height : toint(command); - if (height < 1) height = 1; + } + return CR_OK; +} - ss.str(""); - ss << "Set range z-levels <" << z_levels << "> "; - con.lineedit(ss.str(),command,hist); - z_levels = command == "" ? z_levels : toint(command); - if (z_levels < 1) z_levels = 1; +command_result df_tiletypes_command (color_ostream &out, vector & parameters) +{ + bool dummy; + int start = 0, end = 0; - delete brush; - if (width == 1 && height == 1 && z_levels == 1) - { - brushname = "point"; - } - else - { - brushname = "range"; + parameters.push_back(";"); + for (size_t i = 0; i < parameters.size();i++) + { + if (parameters[i] == ";") { + command_result rv = processCommand(out, parameters, start, end, dummy); + if (rv != CR_OK) { + return rv; } - brush = new RectangleBrush(width, height, z_levels, 0, 0, 0); + end++; + start = end; + } else { + end++; } - else if (command == "block") - { - delete brush; - brushname = "block"; - brush = new BlockBrush(); - } - else if (command == "column") + } + + return CR_OK; +} + +command_result df_tiletypes_here (color_ostream &out, vector & parameters) +{ + for(size_t i = 0; i < parameters.size();i++) + { + if(parameters[i] == "help" || parameters[i] == "?") { - delete brush; - brushname = "column"; - brush = new ColumnBrush(); + 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; } - else if (command.empty()) - { - if (paint.empty()) - { - con.printerr("Set the paint first.\n"); - continue; - } + } - CoreSuspender suspend; + out.print("Run tiletypes-here with these parameters: "); + printState(out); - if (!Maps::IsValid()) - { - con.printerr("Map is not available!\n"); - return CR_FAILURE; - } - Maps::getSize(x_max, y_max, z_max); + return executePaintJob(out); +} - if (!Gui::getCursorCoords(x,y,z)) - { - con.printerr("Can't get cursor coords! Make sure you have a cursor active in DF.\n"); - return CR_FAILURE; - } - con.print("Cursor coords: (%d, %d, %d)\n",x,y,z); +command_result df_tiletypes_here_point (color_ostream &out, vector & parameters) +{ + for(size_t i = 0; i < parameters.size();i++) + { + 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; + } + } - DFHack::DFCoord cursor(x,y,z); - MapExtras::MapCache map; - coord_vec all_tiles = brush->points(map, cursor); - con.print("working...\n"); + Brush *old = brush; + brush = new RectangleBrush(1, 1); - for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter) - { - const df::tiletype source = map.tiletypeAt(*iter); - df::tile_designation des = map.designationAt(*iter); - - if ((filter.shape > -1 && filter.shape != tileShape(source)) - || (filter.material > -1 && filter.material != tileMaterial(source)) - || (filter.special > -1 && filter.special != tileSpecial(source)) - || (filter.variant > -1 && filter.variant != tileVariant(source)) - || (filter.dig > -1 && (filter.dig != 0) != (des.bits.dig != tile_dig_designation::No)) - ) - { - continue; - } - - df::tiletype_shape shape = paint.shape; - if (shape == tiletype_shape::NONE) - { - shape = tileShape(source); - } - - df::tiletype_material material = paint.material; - if (material == tiletype_material::NONE) - { - material = tileMaterial(source); - } - - df::tiletype_special special = paint.special; - if (special == tiletype_special::NONE) - { - special = tileSpecial(source); - } - df::tiletype_variant variant = paint.variant; - /* - * FIXME: variant should be: - * 1. If user variant: - * 2. If user variant \belongs target variants - * 3. use user variant - * 4. Else - * 5. use variant 0 - * 6. If the source variant \belongs target variants - * 7 use source variant - * 8 ElseIf num target shape/material variants > 1 - * 9. pick one randomly - * 10.Else - * 11. use variant 0 - * - * The following variant check has been disabled because it's severely limiting - * the usefullness of the tool. - */ - /* - if (variant == tiletype_variant::NONE) - { - variant = tileVariant(source); - } - */ - // Remove direction from directionless tiles - DFHack::TileDirection direction = tileDirection(source); - if (!(material == tiletype_material::RIVER || shape == tiletype_shape::BROOK_BED || shape == tiletype_shape::WALL && (material == tiletype_material::CONSTRUCTION || special == tiletype_special::SMOOTH))) { - direction.whole = 0; - } - - df::tiletype type = DFHack::findTileType(shape, material, variant, special, direction); - // hack for empty space - if (shape == tiletype_shape::EMPTY && material == tiletype_material::AIR && variant == tiletype_variant::VAR_1 && special == tiletype_special::NORMAL && direction.whole == 0) { - type = tiletype::OpenSpace; - } - // make sure it's not invalid - if(type != tiletype::Void) - map.setTiletypeAt(*iter, type); - - if (paint.hidden > -1) - { - des.bits.hidden = paint.hidden; - } - - if (paint.light > -1) - { - des.bits.light = paint.light; - } - - if (paint.subterranean > -1) - { - des.bits.subterranean = paint.subterranean; - } - - if (paint.skyview > -1) - { - des.bits.outside = paint.skyview; - } - - // Remove liquid from walls, etc - if (type != -1 && !DFHack::FlowPassable(type)) - { - des.bits.flow_size = 0; - //des.bits.liquid_type = DFHack::liquid_water; - //des.bits.water_table = 0; - des.bits.flow_forbid = 0; - //des.bits.liquid_static = 0; - //des.bits.water_stagnant = 0; - //des.bits.water_salt = 0; - } - - map.setDesignationAt(*iter, des); - } + out.print("Run tiletypes-here with these parameters: "); + printState(out); - if (map.WriteAll()) - { - con.print("OK\n"); - } - else - { - con.printerr("Something failed horribly! RUN!\n"); - } - } - } - return CR_OK; + command_result rv = executePaintJob(out); + + delete brush; + brush = old; + return rv; }